]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 30 Apr 2007 15:14:42 +0000 (08:14 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 30 Apr 2007 15:14:42 +0000 (08:14 -0700)
* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (21 commits)
  [IPV4] SNMP: Support OutMcastPkts and OutBcastPkts
  [IPV4] SNMP: Support InMcastPkts and InBcastPkts
  [IPV4] SNMP: Support InTruncatedPkts
  [IPV4] SNMP: Support InNoRoutes
  [SNMP]: Add definitions for {In,Out}BcastPkts
  [TCP] FRTO: RFC4138 allows Nagle override when new data must be sent
  [TCP] FRTO: Delay skb available check until it's mandatory
  [XFRM]: Restrict upper layer information by bundle.
  [TCP]: Catch skb with S+L bugs earlier
  [PATCH] INET : IPV4 UDP lookups converted to a 2 pass algo
  [L2TP]: Add the ability to autoload a pppox protocol module.
  [SKB]: Introduce skb_queue_walk_safe()
  [AF_IUCV/IUCV]: smp_call_function deadlock
  [IPV6]: Fix slab corruption running ip6sic
  [TCP]: Update references in two old comments
  [XFRM]: Export SPD info
  [IPV6]: Track device renames in snmp6.
  [SCTP]: Fix sctp_getsockopt_local_addrs_old() to use local storage.
  [NET]: Remove NETIF_F_INTERNAL_STATS, default to internal stats.
  [NETPOLL]: Remove CONFIG_NETPOLL_RX
  ...

669 files changed:
Documentation/DocBook/kernel-api.tmpl
Documentation/kernel-parameters.txt
Documentation/networking/bcm43xx.txt
Documentation/powerpc/booting-without-of.txt
Documentation/sony-laptop.txt
Documentation/thinkpad-acpi.txt [moved from Documentation/ibm-acpi.txt with 60% similarity]
Documentation/video4linux/meye.txt
MAINTAINERS
arch/i386/defconfig
arch/i386/kernel/acpi/earlyquirk.c
arch/mips/mips-boards/sim/Makefile
arch/mips/mips-boards/sim/sim_platform.c [new file with mode: 0644]
arch/parisc/configs/c3000_defconfig
arch/powerpc/Kconfig
arch/powerpc/Kconfig.debug
arch/powerpc/Makefile
arch/powerpc/boot/.gitignore
arch/powerpc/boot/Makefile
arch/powerpc/boot/crt0.S
arch/powerpc/boot/cuboot-83xx.c [new file with mode: 0644]
arch/powerpc/boot/cuboot-85xx.c [new file with mode: 0644]
arch/powerpc/boot/devtree.c [new file with mode: 0644]
arch/powerpc/boot/dts/kuroboxHD.dts
arch/powerpc/boot/dts/kuroboxHG.dts
arch/powerpc/boot/dts/lite5200.dts
arch/powerpc/boot/dts/lite5200b.dts
arch/powerpc/boot/dts/mpc7448hpc2.dts
arch/powerpc/boot/dts/mpc8272ads.dts
arch/powerpc/boot/dts/mpc8313erdb.dts
arch/powerpc/boot/dts/mpc832x_mds.dts
arch/powerpc/boot/dts/mpc832x_rdb.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8349emitx.dts
arch/powerpc/boot/dts/mpc8349emitxgp.dts
arch/powerpc/boot/dts/mpc834x_mds.dts
arch/powerpc/boot/dts/mpc836x_mds.dts
arch/powerpc/boot/dts/mpc8540ads.dts
arch/powerpc/boot/dts/mpc8541cds.dts
arch/powerpc/boot/dts/mpc8544ds.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8548cds.dts
arch/powerpc/boot/dts/mpc8555cds.dts
arch/powerpc/boot/dts/mpc8560ads.dts
arch/powerpc/boot/dts/mpc8568mds.dts
arch/powerpc/boot/dts/mpc8641_hpcn.dts
arch/powerpc/boot/dts/mpc866ads.dts
arch/powerpc/boot/dts/mpc885ads.dts
arch/powerpc/boot/elf.h
arch/powerpc/boot/elf_util.c [new file with mode: 0644]
arch/powerpc/boot/flatdevtree.c
arch/powerpc/boot/flatdevtree.h
arch/powerpc/boot/flatdevtree_misc.c
arch/powerpc/boot/gunzip_util.c [new file with mode: 0644]
arch/powerpc/boot/gunzip_util.h [new file with mode: 0644]
arch/powerpc/boot/main.c
arch/powerpc/boot/ns16550.c
arch/powerpc/boot/of.c
arch/powerpc/boot/ops.h
arch/powerpc/boot/ppcboot.h [new file with mode: 0644]
arch/powerpc/boot/reg.h [new file with mode: 0644]
arch/powerpc/boot/simple_alloc.c
arch/powerpc/boot/stdio.h
arch/powerpc/boot/wrapper
arch/powerpc/boot/zImage.coff.lds.S
arch/powerpc/boot/zImage.lds.S
arch/powerpc/configs/cell_defconfig
arch/powerpc/configs/g5_defconfig
arch/powerpc/configs/maple_defconfig
arch/powerpc/configs/mpc832x_rdb_defconfig [new file with mode: 0644]
arch/powerpc/configs/mpc8544_ds_defconfig [new file with mode: 0644]
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/align.c
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/btext.c
arch/powerpc/kernel/cpu_setup_pa6t.S
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/ibmebus.c
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/kprobes.c
arch/powerpc/kernel/legacy_serial.c
arch/powerpc/kernel/lparcfg.c
arch/powerpc/kernel/machine_kexec_64.c
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/pci_dn.c
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/prom_parse.c
arch/powerpc/kernel/rtas-proc.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/rtas_pci.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/sys_ppc32.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vio.c
arch/powerpc/lib/copyuser_64.S
arch/powerpc/lib/locks.c
arch/powerpc/lib/mem_64.S
arch/powerpc/lib/memcpy_64.S
arch/powerpc/lib/sstep.c
arch/powerpc/mm/hash_low_32.S
arch/powerpc/mm/hash_low_64.S
arch/powerpc/mm/hash_native_64.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/init_32.c
arch/powerpc/mm/lmb.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/mmu_decl.h
arch/powerpc/mm/numa.c
arch/powerpc/mm/pgtable_32.c
arch/powerpc/mm/ppc_mmu_32.c
arch/powerpc/mm/tlb_64.c
arch/powerpc/oprofile/Makefile
arch/powerpc/oprofile/common.c
arch/powerpc/oprofile/op_model_cell.c
arch/powerpc/oprofile/op_model_pa6t.c [new file with mode: 0644]
arch/powerpc/platforms/4xx/Kconfig
arch/powerpc/platforms/52xx/Kconfig [new file with mode: 0644]
arch/powerpc/platforms/52xx/efika.c
arch/powerpc/platforms/52xx/lite5200.c
arch/powerpc/platforms/52xx/mpc52xx_common.c
arch/powerpc/platforms/52xx/mpc52xx_pci.c
arch/powerpc/platforms/82xx/Kconfig
arch/powerpc/platforms/82xx/mpc82xx.c
arch/powerpc/platforms/82xx/mpc82xx_ads.c
arch/powerpc/platforms/83xx/Kconfig
arch/powerpc/platforms/83xx/Makefile
arch/powerpc/platforms/83xx/mpc832x_mds.c
arch/powerpc/platforms/83xx/mpc832x_mds.h [deleted file]
arch/powerpc/platforms/83xx/mpc832x_rdb.c [new file with mode: 0644]
arch/powerpc/platforms/83xx/mpc834x_itx.h [deleted file]
arch/powerpc/platforms/83xx/pci.c
arch/powerpc/platforms/85xx/Kconfig
arch/powerpc/platforms/85xx/Makefile
arch/powerpc/platforms/85xx/mpc8544_ds.c [new file with mode: 0644]
arch/powerpc/platforms/85xx/mpc85xx_ads.c
arch/powerpc/platforms/85xx/mpc85xx_cds.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/85xx/pci.c
arch/powerpc/platforms/86xx/Kconfig
arch/powerpc/platforms/86xx/Makefile
arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
arch/powerpc/platforms/86xx/pci.c
arch/powerpc/platforms/8xx/Kconfig
arch/powerpc/platforms/8xx/m8xx_setup.c
arch/powerpc/platforms/8xx/mpc86xads.h
arch/powerpc/platforms/8xx/mpc86xads_setup.c
arch/powerpc/platforms/8xx/mpc885ads.h
arch/powerpc/platforms/8xx/mpc885ads_setup.c
arch/powerpc/platforms/Kconfig [new file with mode: 0644]
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/cbe_cpufreq.c
arch/powerpc/platforms/cell/cbe_regs.c
arch/powerpc/platforms/cell/cbe_regs.h
arch/powerpc/platforms/cell/cbe_thermal.c
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/cell/io-workarounds.c
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/cell/ras.c
arch/powerpc/platforms/cell/setup.c
arch/powerpc/platforms/cell/spider-pic.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/cell/spu_coredump.c
arch/powerpc/platforms/cell/spu_manage.c
arch/powerpc/platforms/cell/spufs/Makefile
arch/powerpc/platforms/cell/spufs/backing_ops.c
arch/powerpc/platforms/cell/spufs/context.c
arch/powerpc/platforms/cell/spufs/coredump.c
arch/powerpc/platforms/cell/spufs/fault.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/hw_ops.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/cell/spufs/run.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/cell/spufs/spufs.h
arch/powerpc/platforms/cell/spufs/switch.c
arch/powerpc/platforms/celleb/Kconfig [new file with mode: 0644]
arch/powerpc/platforms/celleb/iommu.c
arch/powerpc/platforms/celleb/pci.c
arch/powerpc/platforms/celleb/setup.c
arch/powerpc/platforms/chrp/Kconfig [new file with mode: 0644]
arch/powerpc/platforms/chrp/nvram.c
arch/powerpc/platforms/chrp/pci.c
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/chrp/time.c
arch/powerpc/platforms/embedded6xx/Kconfig
arch/powerpc/platforms/embedded6xx/linkstation.c
arch/powerpc/platforms/embedded6xx/ls_uart.c
arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
arch/powerpc/platforms/iseries/Kconfig
arch/powerpc/platforms/iseries/iommu.c
arch/powerpc/platforms/iseries/irq.c
arch/powerpc/platforms/iseries/pci.c
arch/powerpc/platforms/iseries/setup.c
arch/powerpc/platforms/iseries/viopath.c
arch/powerpc/platforms/maple/Kconfig [new file with mode: 0644]
arch/powerpc/platforms/maple/pci.c
arch/powerpc/platforms/maple/setup.c
arch/powerpc/platforms/pasemi/Kconfig
arch/powerpc/platforms/pasemi/Makefile
arch/powerpc/platforms/pasemi/cpufreq.c [new file with mode: 0644]
arch/powerpc/platforms/pasemi/gpio_mdio.c [new file with mode: 0644]
arch/powerpc/platforms/pasemi/idle.c
arch/powerpc/platforms/pasemi/iommu.c
arch/powerpc/platforms/pasemi/pasemi.h
arch/powerpc/platforms/pasemi/pci.c
arch/powerpc/platforms/pasemi/setup.c
arch/powerpc/platforms/powermac/Kconfig [new file with mode: 0644]
arch/powerpc/platforms/powermac/backlight.c
arch/powerpc/platforms/powermac/cpufreq_32.c
arch/powerpc/platforms/powermac/cpufreq_64.c
arch/powerpc/platforms/powermac/feature.c
arch/powerpc/platforms/powermac/low_i2c.c
arch/powerpc/platforms/powermac/pci.c
arch/powerpc/platforms/powermac/pfunc_base.c
arch/powerpc/platforms/powermac/pfunc_core.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/powermac/time.c
arch/powerpc/platforms/powermac/udbg_scc.c
arch/powerpc/platforms/prep/Kconfig
arch/powerpc/platforms/ps3/Kconfig
arch/powerpc/platforms/ps3/htab.c
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/Makefile
arch/powerpc/platforms/pseries/eeh.c
arch/powerpc/platforms/pseries/eeh_driver.c
arch/powerpc/platforms/pseries/eeh_event.c
arch/powerpc/platforms/pseries/firmware.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/nvram.c
arch/powerpc/platforms/pseries/pci.c
arch/powerpc/platforms/pseries/pci_dlpar.c
arch/powerpc/platforms/pseries/ras.c
arch/powerpc/platforms/pseries/rtasd.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/xics.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/dart_iommu.c
arch/powerpc/sysdev/dcr.c
arch/powerpc/sysdev/fsl_pcie.c [moved from arch/powerpc/platforms/86xx/mpc86xx_pcie.c with 99% similarity]
arch/powerpc/sysdev/fsl_pcie.h [new file with mode: 0644]
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/pmi.c
arch/powerpc/sysdev/qe_lib/Kconfig
arch/powerpc/sysdev/qe_lib/qe.c
arch/powerpc/sysdev/qe_lib/qe_io.c
arch/powerpc/sysdev/qe_lib/ucc_fast.c
arch/powerpc/sysdev/qe_lib/ucc_slow.c
arch/powerpc/sysdev/timer.c [new file with mode: 0644]
arch/powerpc/sysdev/tsi108_dev.c
arch/powerpc/sysdev/tsi108_pci.c
arch/powerpc/sysdev/uic.c [new file with mode: 0644]
arch/powerpc/xmon/xmon.c
arch/ppc/8xx_io/Kconfig
arch/ppc/8xx_io/Makefile
arch/ppc/8xx_io/cs4218.h [deleted file]
arch/ppc/8xx_io/cs4218_tdm.c [deleted file]
arch/ppc/boot/common/misc-common.c
arch/ppc/boot/simple/Makefile
arch/ppc/boot/simple/uartlite_tty.c [new file with mode: 0644]
arch/ppc/kernel/asm-offsets.c
arch/ppc/kernel/entry.S
arch/ppc/platforms/4xx/Kconfig
arch/ppc/platforms/4xx/Makefile
arch/ppc/platforms/4xx/ocotea.c
arch/ppc/platforms/4xx/taishan.c
arch/ppc/platforms/4xx/virtex.c [deleted file]
arch/ppc/platforms/4xx/virtex.h
arch/ppc/platforms/4xx/xilinx_ml300.c
arch/ppc/platforms/4xx/xilinx_ml300.h [deleted file]
arch/ppc/platforms/4xx/xilinx_ml403.c
arch/ppc/platforms/4xx/xilinx_ml403.h [deleted file]
arch/ppc/platforms/4xx/xparameters/xparameters.h
arch/ppc/platforms/rpxclassic.h
arch/ppc/platforms/rpxhiox.h [deleted file]
arch/ppc/platforms/rpxlite.h
arch/ppc/syslib/Makefile
arch/ppc/syslib/cpc710.h [deleted file]
arch/ppc/syslib/m8xx_setup.c
arch/ppc/syslib/ppc4xx_sgdma.c
arch/ppc/syslib/virtex_devices.c [new file with mode: 0644]
arch/ppc/syslib/virtex_devices.h [new file with mode: 0644]
arch/x86_64/defconfig
block/cfq-iosched.c
block/elevator.c
block/ll_rw_blk.c
crypto/michael_mic.c
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_memhotplug.c
drivers/acpi/bus.c
drivers/acpi/container.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/i2c_ec.c [deleted file]
drivers/acpi/i2c_ec.h [deleted file]
drivers/acpi/ibm_acpi.c [deleted file]
drivers/acpi/processor_core.c
drivers/acpi/processor_idle.c
drivers/acpi/sbs.c
drivers/acpi/scan.c
drivers/acpi/sleep/proc.c
drivers/acpi/tables/tbfadt.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/ata_generic.c
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/libata.h
drivers/ata/pata_ali.c
drivers/ata/pata_amd.c
drivers/ata/pata_artop.c
drivers/ata/pata_atiixp.c
drivers/ata/pata_cmd640.c [new file with mode: 0644]
drivers/ata/pata_cmd64x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_cs5530.c
drivers/ata/pata_cs5535.c
drivers/ata/pata_cypress.c
drivers/ata/pata_efar.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_hpt3x3.c
drivers/ata/pata_isapnp.c
drivers/ata/pata_it8213.c
drivers/ata/pata_it821x.c
drivers/ata/pata_ixp4xx_cf.c
drivers/ata/pata_legacy.c
drivers/ata/pata_marvell.c
drivers/ata/pata_mpc52xx.c
drivers/ata/pata_mpiix.c
drivers/ata/pata_netcell.c
drivers/ata/pata_ns87410.c
drivers/ata/pata_oldpiix.c
drivers/ata/pata_opti.c
drivers/ata/pata_optidma.c
drivers/ata/pata_pcmcia.c
drivers/ata/pata_pdc2027x.c
drivers/ata/pata_pdc202xx_old.c
drivers/ata/pata_platform.c
drivers/ata/pata_qdi.c
drivers/ata/pata_radisys.c
drivers/ata/pata_rz1000.c
drivers/ata/pata_sc1200.c
drivers/ata/pata_scc.c
drivers/ata/pata_serverworks.c
drivers/ata/pata_sil680.c
drivers/ata/pata_sis.c
drivers/ata/pata_sl82c105.c
drivers/ata/pata_triflex.c
drivers/ata/pata_via.c
drivers/ata/pata_winbond.c
drivers/ata/pdc_adma.c
drivers/ata/sata_inic162x.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_promise.c
drivers/ata/sata_qstor.c
drivers/ata/sata_sil.c
drivers/ata/sata_sil24.c
drivers/ata/sata_sis.c
drivers/ata/sata_svw.c
drivers/ata/sata_sx4.c
drivers/ata/sata_uli.c
drivers/ata/sata_via.c
drivers/ata/sata_vsc.c
drivers/char/briq_panel.c
drivers/char/hvc_console.c
drivers/char/hvc_iseries.c
drivers/char/hvc_vio.c
drivers/char/hvsi.c
drivers/char/sonypi.c
drivers/char/tpm/tpm_atmel.h
drivers/char/watchdog/Kconfig
drivers/clocksource/acpi_pm.c
drivers/hwmon/ams/ams-core.c
drivers/hwmon/ams/ams-i2c.c
drivers/hwmon/ams/ams-pmu.c
drivers/infiniband/hw/ehca/ehca_main.c
drivers/macintosh/adb.c
drivers/macintosh/ans-lcd.c
drivers/macintosh/apm_emu.c
drivers/macintosh/mac_hid.c
drivers/macintosh/macio-adb.c
drivers/macintosh/macio_asic.c
drivers/macintosh/macio_sysfs.c
drivers/macintosh/rack-meter.c
drivers/macintosh/smu.c
drivers/macintosh/therm_adt746x.c
drivers/macintosh/therm_pm72.c
drivers/macintosh/therm_windtunnel.c
drivers/macintosh/via-cuda.c
drivers/macintosh/via-pmu-led.c
drivers/macintosh/via-pmu.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_max6690_sensor.c
drivers/macintosh/windfarm_smu_controls.c
drivers/macintosh/windfarm_smu_sat.c
drivers/macintosh/windfarm_smu_sensors.c
drivers/md/dm-crypt.c
drivers/md/dm-io.c
drivers/md/dm.c
drivers/media/video/Kconfig
drivers/media/video/meye.c
drivers/media/video/meye.h
drivers/media/video/planb.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/asus-laptop.c
drivers/misc/sony-laptop.c
drivers/misc/thinkpad_acpi.c [new file with mode: 0644]
drivers/misc/thinkpad_acpi.h [new file with mode: 0644]
drivers/net/3c509.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/chelsio/Makefile
drivers/net/chelsio/common.h
drivers/net/chelsio/cphy.h
drivers/net/chelsio/gmac.h
drivers/net/chelsio/ixf1010.c [deleted file]
drivers/net/chelsio/mac.c
drivers/net/chelsio/mv88e1xxx.c
drivers/net/chelsio/mv88x201x.c
drivers/net/chelsio/my3126.c
drivers/net/chelsio/pm3393.c
drivers/net/chelsio/subr.c
drivers/net/chelsio/vsc7326.c
drivers/net/chelsio/vsc8244.c [deleted file]
drivers/net/chelsio/vsc8244_reg.h [deleted file]
drivers/net/e100.c
drivers/net/e1000/e1000.h
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000/e1000_param.c
drivers/net/eexpress.c
drivers/net/ehea/ehea.h
drivers/net/ehea/ehea_ethtool.c
drivers/net/ehea/ehea_main.c
drivers/net/ehea/ehea_phyp.c
drivers/net/ehea/ehea_phyp.h
drivers/net/ehea/ehea_qmr.c
drivers/net/ehea/ehea_qmr.h
drivers/net/hamradio/baycom_ser_fdx.c
drivers/net/ibmveth.c
drivers/net/ixgb/ixgb.h
drivers/net/ixgb/ixgb_ethtool.c
drivers/net/ixgb/ixgb_main.c
drivers/net/ixgb/ixgb_param.c
drivers/net/mii.c
drivers/net/mipsnet.c
drivers/net/mv643xx_eth.c
drivers/net/mv643xx_eth.h
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_ethtool.c
drivers/net/netxen/netxen_nic_hdr.h
drivers/net/netxen/netxen_nic_hw.c
drivers/net/netxen/netxen_nic_hw.h
drivers/net/netxen/netxen_nic_init.c
drivers/net/netxen/netxen_nic_isr.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/netxen/netxen_nic_niu.c
drivers/net/netxen/netxen_nic_phan_reg.h
drivers/net/pcnet32.c
drivers/net/phy/mdio_bus.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/qla3xxx.c
drivers/net/qla3xxx.h
drivers/net/s2io-regs.h
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/sb1250-mac.c
drivers/net/sgiseeq.c
drivers/net/sk98lin/skge.c
drivers/net/skfp/h/lnkstat.h [deleted file]
drivers/net/skge.c
drivers/net/skge.h
drivers/net/smc911x.c
drivers/net/tc35815.c
drivers/net/tulip/dmfe.c
drivers/net/tulip/interrupt.c
drivers/net/tulip/media.c
drivers/net/tulip/tulip.h
drivers/net/tulip/tulip_core.c
drivers/net/tulip/winbond-840.c
drivers/net/ucc_geth.c
drivers/net/ucc_geth.h
drivers/net/ucc_geth_mii.c [new file with mode: 0644]
drivers/net/ucc_geth_mii.h [new file with mode: 0644]
drivers/net/ucc_geth_phy.c [deleted file]
drivers/net/ucc_geth_phy.h [deleted file]
drivers/net/wan/hdlc_cisco.c
drivers/net/wan/hdlc_fr.c
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/README [deleted file]
drivers/net/wireless/airo.c
drivers/net/wireless/bcm43xx/bcm43xx.h
drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
drivers/net/wireless/bcm43xx/bcm43xx_main.c
drivers/net/wireless/bcm43xx/bcm43xx_phy.c
drivers/net/wireless/bcm43xx/bcm43xx_phy.h
drivers/net/wireless/bcm43xx/bcm43xx_radio.c
drivers/net/wireless/hostap/hostap_ap.c
drivers/net/wireless/hostap/hostap_common.h
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/hostap/hostap_hw.c
drivers/net/wireless/hostap/hostap_main.c
drivers/net/wireless/hostap/hostap_pci.c
drivers/net/wireless/hostap/hostap_plx.c
drivers/net/wireless/ipw2100.c
drivers/net/wireless/ipw2200.c
drivers/net/wireless/libertas/11d.c [new file with mode: 0644]
drivers/net/wireless/libertas/11d.h [new file with mode: 0644]
drivers/net/wireless/libertas/LICENSE [new file with mode: 0644]
drivers/net/wireless/libertas/Makefile [new file with mode: 0644]
drivers/net/wireless/libertas/README [new file with mode: 0644]
drivers/net/wireless/libertas/assoc.c [new file with mode: 0644]
drivers/net/wireless/libertas/assoc.h [new file with mode: 0644]
drivers/net/wireless/libertas/cmd.c [new file with mode: 0644]
drivers/net/wireless/libertas/cmdresp.c [new file with mode: 0644]
drivers/net/wireless/libertas/debugfs.c [new file with mode: 0644]
drivers/net/wireless/libertas/debugfs.h [new file with mode: 0644]
drivers/net/wireless/libertas/decl.h [new file with mode: 0644]
drivers/net/wireless/libertas/defs.h [new file with mode: 0644]
drivers/net/wireless/libertas/dev.h [new file with mode: 0644]
drivers/net/wireless/libertas/ethtool.c [new file with mode: 0644]
drivers/net/wireless/libertas/fw.c [new file with mode: 0644]
drivers/net/wireless/libertas/fw.h [new file with mode: 0644]
drivers/net/wireless/libertas/host.h [new file with mode: 0644]
drivers/net/wireless/libertas/hostcmd.h [new file with mode: 0644]
drivers/net/wireless/libertas/if_bootcmd.c [new file with mode: 0644]
drivers/net/wireless/libertas/if_usb.c [new file with mode: 0644]
drivers/net/wireless/libertas/if_usb.h [new file with mode: 0644]
drivers/net/wireless/libertas/ioctl.c [new file with mode: 0644]
drivers/net/wireless/libertas/join.c [new file with mode: 0644]
drivers/net/wireless/libertas/join.h [new file with mode: 0644]
drivers/net/wireless/libertas/main.c [new file with mode: 0644]
drivers/net/wireless/libertas/radiotap.h [new file with mode: 0644]
drivers/net/wireless/libertas/rx.c [new file with mode: 0644]
drivers/net/wireless/libertas/sbi.h [new file with mode: 0644]
drivers/net/wireless/libertas/scan.c [new file with mode: 0644]
drivers/net/wireless/libertas/scan.h [new file with mode: 0644]
drivers/net/wireless/libertas/thread.h [new file with mode: 0644]
drivers/net/wireless/libertas/tx.c [new file with mode: 0644]
drivers/net/wireless/libertas/types.h [new file with mode: 0644]
drivers/net/wireless/libertas/version.h [new file with mode: 0644]
drivers/net/wireless/libertas/wext.c [new file with mode: 0644]
drivers/net/wireless/libertas/wext.h [new file with mode: 0644]
drivers/net/wireless/todo.txt [deleted file]
drivers/net/wireless/zd1211rw/zd_chip.c
drivers/net/wireless/zd1211rw/zd_chip.h
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/net/wireless/zd1211rw/zd_rf.c
drivers/net/wireless/zd1211rw/zd_rf.h
drivers/net/wireless/zd1211rw/zd_rf_al2230.c
drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/pci/pci-acpi.c
drivers/pci/quirks.c
drivers/ps3/vuart.c
drivers/scsi/ibmvscsi/ibmvstgt.c
drivers/scsi/ibmvscsi/rpa_vscsi.c
drivers/scsi/ipr.c
drivers/scsi/scsi_lib.c
drivers/serial/pmac_zilog.c
drivers/video/Kconfig
drivers/video/aty/radeon_pm.c
drivers/video/controlfb.c
fs/bio.c
fs/proc/proc_devtree.c
include/acpi/actbl.h
include/asm-powerpc/asm-compat.h
include/asm-powerpc/cacheflush.h
include/asm-powerpc/cell-pmu.h
include/asm-powerpc/cputable.h
include/asm-powerpc/current.h
include/asm-powerpc/edac.h [new file with mode: 0644]
include/asm-powerpc/eeh_event.h
include/asm-powerpc/ibmebus.h
include/asm-powerpc/immap_86xx.h
include/asm-powerpc/io.h
include/asm-powerpc/kprobes.h
include/asm-powerpc/machdep.h
include/asm-powerpc/mmu-hash64.h [new file with mode: 0644]
include/asm-powerpc/mmu.h
include/asm-powerpc/mpic.h
include/asm-powerpc/of_device.h
include/asm-powerpc/oprofile_impl.h
include/asm-powerpc/paca.h
include/asm-powerpc/parport.h
include/asm-powerpc/pci.h
include/asm-powerpc/pgtable-4k.h
include/asm-powerpc/pgtable-64k.h
include/asm-powerpc/pgtable.h
include/asm-powerpc/pmc.h
include/asm-powerpc/ppc-pci.h
include/asm-powerpc/processor.h
include/asm-powerpc/prom.h
include/asm-powerpc/reg.h
include/asm-powerpc/spu_csa.h
include/asm-powerpc/system.h
include/asm-powerpc/tlb.h
include/asm-powerpc/tlbflush.h
include/asm-powerpc/uaccess.h
include/asm-powerpc/ucc_fast.h
include/asm-powerpc/uic.h [new file with mode: 0644]
include/asm-ppc/ibm4xx.h
include/asm-ppc/ppc_sys.h
include/asm-ppc/prom.h
include/linux/ata.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/fsl_devices.h
include/linux/hdlc.h
include/linux/ioport.h
include/linux/libata.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/phy.h
include/linux/pmu.h
include/linux/sony-laptop.h [new file with mode: 0644]
include/linux/wireless.h
include/net/ieee80211.h
include/net/ieee80211_crypt.h
include/net/ieee80211_radiotap.h
kernel/resource.c
lib/devres.c
net/ieee80211/ieee80211_crypt.c
net/ieee80211/ieee80211_crypt_ccmp.c
net/ieee80211/ieee80211_crypt_tkip.c
net/ieee80211/ieee80211_crypt_wep.c
net/ieee80211/ieee80211_module.c
net/ieee80211/ieee80211_rx.c
net/ieee80211/ieee80211_wx.c
sound/aoa/codecs/snd-aoa-codec-onyx.c
sound/aoa/codecs/snd-aoa-codec-tas.c
sound/aoa/core/snd-aoa-gpio-feature.c
sound/aoa/fabrics/snd-aoa-fabric-layout.c
sound/aoa/soundbus/core.c
sound/aoa/soundbus/i2sbus/i2sbus-core.c
sound/oss/dmasound/dmasound_awacs.c
sound/oss/dmasound/tas_common.c
sound/ppc/pmac.c
sound/ppc/tumbler.c

index 0bb90237e230d5e0d9c05448767741bd8c0c6e87..b61dfc79e1b87904b4280ad8a9fba47b733e0bef 100644 (file)
@@ -236,6 +236,12 @@ X!Ilib/string.c
 !Enet/core/dev.c
 !Enet/ethernet/eth.c
 !Iinclude/linux/etherdevice.h
+!Edrivers/net/phy/phy.c
+!Idrivers/net/phy/phy.c
+!Edrivers/net/phy/phy_device.c
+!Idrivers/net/phy/phy_device.c
+!Edrivers/net/phy/mdio_bus.c
+!Idrivers/net/phy/mdio_bus.c
 <!-- FIXME: Removed for now since no structured comments in source
 X!Enet/core/wireless.c
 -->
index 2017942e09664832589f4148066570e418489e00..84c3bd05c639df4510ae484f900f23865b2a46d8 100644 (file)
@@ -181,19 +181,41 @@ and is between 256 and 4096 characters. It is defined in the file
                        that require a timer override, but don't have
                        HPET
 
-       acpi_dbg_layer= [HW,ACPI]
+       acpi.debug_layer=       [HW,ACPI]
                        Format: <int>
                        Each bit of the <int> indicates an ACPI debug layer,
                        1: enable, 0: disable. It is useful for boot time
                        debugging. After system has booted up, it can be set
-                       via /proc/acpi/debug_layer.
-
-       acpi_dbg_level= [HW,ACPI]
+                       via /sys/module/acpi/parameters/debug_layer.
+                       CONFIG_ACPI_DEBUG must be enabled for this to produce any output.
+                       Available bits (add the numbers together) to enable debug output
+                       for specific parts of the ACPI subsystem:
+                       0x01 utilities 0x02 hardware 0x04 events 0x08 tables
+                       0x10 namespace 0x20 parser 0x40 dispatcher
+                       0x80 executer 0x100 resources 0x200 acpica debugger
+                       0x400 os services 0x800 acpica disassembler.
+                       The number can be in decimal or prefixed with 0x in hex.
+                       Warning: Many of these options can produce a lot of
+                       output and make your system unusable. Be very careful.
+
+       acpi.debug_level=       [HW,ACPI]
                        Format: <int>
                        Each bit of the <int> indicates an ACPI debug level,
                        1: enable, 0: disable. It is useful for boot time
                        debugging. After system has booted up, it can be set
-                       via /proc/acpi/debug_level.
+                       via /sys/module/acpi/parameters/debug_level.
+                       CONFIG_ACPI_DEBUG must be enabled for this to produce any output.
+                       Available bits (add the numbers together) to enable different
+                       debug output levels of the ACPI subsystem:
+                       0x01 error 0x02 warn 0x04 init 0x08 debug object
+                       0x10 info 0x20 init names 0x40 parse 0x80 load
+                       0x100 dispatch 0x200 execute 0x400 names 0x800 operation region
+                       0x1000 bfield 0x2000 tables 0x4000 values 0x8000 objects
+                       0x10000 resources 0x20000 user requests 0x40000 package.
+                       The number can be in decimal or prefixed with 0x in hex.
+                       Warning: Many of these options can produce a lot of
+                       output and make your system unusable. Be very careful.
+
 
        acpi_fake_ecdt  [HW,ACPI] Workaround failure due to BIOS lacking ECDT
 
index 28541d2bee1ef3e16c42027c481bcc6d7f4cd0f2..a136721499bfbb1d7683ed2c47a1340a6482ab24 100644 (file)
@@ -2,35 +2,88 @@
                        BCM43xx Linux Driver Project
                        ============================
 
-About this software
--------------------
+Introduction
+------------
 
-The goal of this project is to develop a linux driver for Broadcom
-BCM43xx chips, based on the specification at 
-http://bcm-specs.sipsolutions.net/
+Many of the wireless devices found in modern notebook computers are
+based on the wireless chips produced by Broadcom. These devices have
+been a problem for Linux users as there is no open-source driver
+available. In addition, Broadcom has not released specifications
+for the device, and driver availability has been limited to the
+binary-only form used in the GPL versions of AP hardware such as the
+Linksys WRT54G, and the Windows and OS X drivers.  Before this project
+began, the only way to use these devices were to use the Windows or
+OS X drivers with either the Linuxant or ndiswrapper modules. There
+is a strong penalty if this method is used as loading the binary-only
+module "taints" the kernel, and no kernel developer will help diagnose
+any kernel problems.
 
-The project page is http://bcm43xx.berlios.de/
+Development
+-----------
 
+This driver has been developed using
+a clean-room technique that is described at
+http://bcm-specs.sipsolutions.net/ReverseEngineeringProcess. For legal
+reasons, none of the clean-room crew works on the on the Linux driver,
+and none of the Linux developers sees anything but the specifications,
+which are the ultimate product of the reverse-engineering group.
 
-Requirements
-------------
+Software
+--------
+
+Since the release of the 2.6.17 kernel, the bcm43xx driver has been
+distributed with the kernel source, and is prebuilt in most, if not
+all, distributions.  There is, however, additional software that is
+required. The firmware used by the chip is the intellectual property
+of Broadcom and they have not given the bcm43xx team redistribution
+rights to this firmware.  Since we cannot legally redistribute
+the firwmare we cannot include it with the driver. Furthermore, it
+cannot be placed in the downloadable archives of any distributing
+organization; therefore, the user is responsible for obtaining the
+firmware and placing it in the appropriate location so that the driver
+can find it when initializing.
+
+To help with this process, the bcm43xx developers provide a separate
+program named bcm43xx-fwcutter to "cut" the firmware out of a
+Windows or OS X driver and write the extracted files to the proper
+location. This program is usually provided with the distribution;
+however, it may be downloaded from
+
+http://developer.berlios.de/project/showfiles.php?group_id=4547
 
-1)     Linux Kernel 2.6.16 or later
-       http://www.kernel.org/
+The firmware is available in two versions. V3 firmware is used with
+the in-kernel bcm43xx driver that uses a software MAC layer called
+SoftMAC, and will have a microcode revision of 0x127 or smaller. The
+V4 firmware is used by an out-of-kernel driver employing a variation of
+the Devicescape MAC layer known as d80211. Once bcm43xx-d80211 reaches
+a satisfactory level of development, it will replace bcm43xx-softmac
+in the kernel as it is much more flexible and powerful.
 
-       You may want to configure your kernel with:
+A source for the latest V3 firmware is
 
-       CONFIG_DEBUG_FS (optional):
-               -> Kernel hacking
-                 -> Debug Filesystem
+http://downloads.openwrt.org/sources/wl_apsta-3.130.20.0.o
 
-2)     SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211
-       modules:
-       http://softmac.sipsolutions.net/
+Once this file is downloaded, the command
+'bcm43xx-fwcutter -w <dir> <filename>'
+will extract the microcode and write it to directory
+<dir>. The correct directory will depend on your distribution;
+however, most use '/lib/firmware'. Once this step is completed,
+the bcm3xx driver should load when the system is booted. To see
+any messages relating to the driver, issue the command 'dmesg |
+grep bcm43xx' from a terminal window. If there are any problems,
+please send that output to Bcm43xx-dev@lists.berlios.de.
 
-3)     Firmware Files
+Although the driver has been in-kernel since 2.6.17, the earliest
+version is quite limited in its capability. Patches that include
+all features of later versions are available for the stable kernel
+versions from 2.6.18. These will be needed if you use a BCM4318,
+or a PCI Express version (BCM4311 and BCM4312). In addition, if you
+have an early BCM4306 and more than 1 GB RAM, your kernel will need
+to be patched. These patches, which are being updated regularly,
+are available at ftp://lwfinger.dynalias.org/patches. Look for
+combined_2.6.YY.patch. Of course you will need kernel source downloaded
+from kernel.org, or the source from your distribution.
 
-       Please try fwcutter. Fwcutter can extract the firmware from various 
-       binary driver files. It supports driver files from Windows, MacOS and 
-       Linux. You can get fwcutter from http://bcm43xx.berlios.de/.
-       Also, fwcutter comes with a README file for further instructions.
+If you build your own kernel, please enable CONFIG_BCM43XX_DEBUG
+and CONFIG_IEEE80211_SOFTMAC_DEBUG. The log information provided is
+essential for solving any problems.
index b41397d6430aa4a6a589d278e07d74f739b2f60e..033a3f3b3ab77b65d146ec38ec63acba35982c88 100644 (file)
@@ -39,7 +39,7 @@
                            and property data. The old style variable
                            alignment would make it impossible to do
                            "simple" insertion of properties using
-                           memove (thanks Milton for
+                           memmove (thanks Milton for
                            noticing). Updated kernel patch as well
                         - Correct a few more alignment constraints
                         - Add a chapter about the device-tree
@@ -55,7 +55,7 @@
 
  ToDo:
        - Add some definitions of interrupt tree (simple/complex)
-       - Add some definitions for pci host bridges
+       - Add some definitions for PCI host bridges
        - Add some common address format examples
        - Add definitions for standard properties and "compatible"
          names for cells that are not already defined by the existing
@@ -114,7 +114,7 @@ it with special cases.
         forth words isn't required), you can enter the kernel with:
 
               r5 : OF callback pointer as defined by IEEE 1275
-              bindings to powerpc. Only the 32 bit client interface
+              bindings to powerpc. Only the 32-bit client interface
               is currently supported
 
               r3, r4 : address & length of an initrd if any or 0
@@ -194,7 +194,7 @@ it with special cases.
   for this is to keep kernels on embedded systems small and efficient;
   part of this is due to the fact the code is already that way. In the
   future, a kernel may support multiple platforms, but only if the
-  platforms feature the same core architectire.  A single kernel build
+  platforms feature the same core architecture.  A single kernel build
   cannot support both configurations with Book E and configurations
   with classic Powerpc architectures.
 
@@ -215,7 +215,7 @@ of the boot sequences.... someone speak up if this is wrong!
   enable another config option to select the specific board
   supported.
 
-NOTE: If ben doesn't merge the setup files, may need to change this to
+NOTE: If Ben doesn't merge the setup files, may need to change this to
 point to setup_32.c
 
 
@@ -256,7 +256,7 @@ struct boot_param_header {
         u32     off_dt_struct;          /* offset to structure */
         u32     off_dt_strings;         /* offset to strings */
         u32     off_mem_rsvmap;         /* offset to memory reserve map
-*/
+                                           */
         u32     version;                /* format version */
         u32     last_comp_version;      /* last compatible version */
 
@@ -265,6 +265,9 @@ struct boot_param_header {
                                            booting on */
         /* version 3 fields below */
         u32     size_dt_strings;        /* size of the strings block */
+
+        /* version 17 fields below */
+        u32    size_dt_struct;         /* size of the DT structure block */
 };
 
    Along with the constants:
@@ -273,7 +276,7 @@ struct boot_param_header {
 #define OF_DT_HEADER            0xd00dfeed      /* 4: version,
                                                   4: total size */
 #define OF_DT_BEGIN_NODE        0x1             /* Start node: full name
-*/
+                                                  */
 #define OF_DT_END_NODE          0x2             /* End node */
 #define OF_DT_PROP              0x3             /* Property: name off,
                                                    size, content */
@@ -310,9 +313,8 @@ struct boot_param_header {
    - off_mem_rsvmap
 
      This is an offset from the beginning of the header to the start
-     of the reserved memory map. This map is a list of pairs of 64
+     of the reserved memory map. This map is a list of pairs of 64-
      bit integers. Each pair is a physical address and a size. The
-
      list is terminated by an entry of size 0. This map provides the
      kernel with a list of physical memory areas that are "reserved"
      and thus not to be used for memory allocations, especially during
@@ -325,7 +327,7 @@ struct boot_param_header {
      contain _at least_ this DT block itself (header,total_size). If
      you are passing an initrd to the kernel, you should reserve it as
      well. You do not need to reserve the kernel image itself. The map
-     should be 64 bit aligned.
+     should be 64-bit aligned.
 
    - version
 
@@ -335,10 +337,13 @@ struct boot_param_header {
      to reallocate it easily at boot and free up the unused flattened
      structure after expansion. Version 16 introduces a new more
      "compact" format for the tree itself that is however not backward
-     compatible. You should always generate a structure of the highest
-     version defined at the time of your implementation. Currently
-     that is version 16, unless you explicitly aim at being backward
-     compatible.
+     compatible. Version 17 adds an additional field, size_dt_struct,
+     allowing it to be reallocated or moved more easily (this is
+     particularly useful for bootloaders which need to make
+     adjustments to a device tree based on probed information). You
+     should always generate a structure of the highest version defined
+     at the time of your implementation. Currently that is version 17,
+     unless you explicitly aim at being backward compatible.
 
    - last_comp_version
 
@@ -347,7 +352,7 @@ struct boot_param_header {
      is backward compatible with version 1 (that is, a kernel build
      for version 1 will be able to boot with a version 2 format). You
      should put a 1 in this field if you generate a device tree of
-     version 1 to 3, or 0x10 if you generate a tree of version 0x10
+     version 1 to 3, or 16 if you generate a tree of version 16 or 17
      using the new unit name format.
 
    - boot_cpuid_phys
@@ -360,6 +365,17 @@ struct boot_param_header {
      point (see further chapters for more informations on the required
      device-tree contents)
 
+   - size_dt_strings
+
+     This field only exists on version 3 and later headers.  It
+     gives the size of the "strings" section of the device tree (which
+     starts at the offset given by off_dt_strings).
+
+   - size_dt_struct
+
+     This field only exists on version 17 and later headers.  It gives
+     the size of the "structure" section of the device tree (which
+     starts at the offset given by off_dt_struct).
 
    So the typical layout of a DT block (though the various parts don't
    need to be in that order) looks like this (addresses go from top to
@@ -417,7 +433,7 @@ root node who has no parent.
 A node has 2 names. The actual node name is generally contained in a
 property of type "name" in the node property list whose value is a
 zero terminated string and is mandatory for version 1 to 3 of the
-format definition (as it is in Open Firmware). Version 0x10 makes it
+format definition (as it is in Open Firmware). Version 16 makes it
 optional as it can generate it from the unit name defined below.
 
 There is also a "unit name" that is used to differentiate nodes with
@@ -461,7 +477,7 @@ referencing another node via "phandle" is when laying out the
 interrupt tree which will be described in a further version of this
 document.
 
-This "linux, phandle" property is a 32 bit value that uniquely
+This "linux, phandle" property is a 32-bit value that uniquely
 identifies a node. You are free to use whatever values or system of
 values, internal pointers, or whatever to generate these, the only
 requirement is that every node for which you provide that property has
@@ -471,7 +487,7 @@ Here is an example of a simple device-tree. In this example, an "o"
 designates a node followed by the node unit name. Properties are
 presented with their name followed by their content. "content"
 represents an ASCII string (zero terminated) value, while <content>
-represents a 32 bit hexadecimal value. The various nodes in this
+represents a 32-bit hexadecimal value. The various nodes in this
 example will be discussed in a later chapter. At this point, it is
 only meant to give you a idea of what a device-tree looks like. I have
 purposefully kept the "name" and "linux,phandle" properties which
@@ -543,15 +559,15 @@ Here's the basic structure of a single node:
      * [align gap to next 4 bytes boundary]
      * for each property:
         * token OF_DT_PROP (that is 0x00000003)
-        * 32 bit value of property value size in bytes (or 0 of no
-     * value)
-        * 32 bit value of offset in string block of property name
+        * 32-bit value of property value size in bytes (or 0 if no
+          value)
+        * 32-bit value of offset in string block of property name
         * property value data if any
         * [align gap to next 4 bytes boundary]
      * [child nodes if any]
      * token OF_DT_END_NODE (that is 0x00000002)
 
-So the node content can be summarised as a start token, a full path,
+So the node content can be summarized as a start token, a full path,
 a list of properties, a list of child nodes, and an end token. Every
 child node is a full node structure itself as defined above.
 
@@ -583,7 +599,7 @@ provide those properties yourself.
 ----------------------------------------------
 
 The general rule is documented in the various Open Firmware
-documentations. If you chose to describe a bus with the device-tree
+documentations. If you choose to describe a bus with the device-tree
 and there exist an OF bus binding, then you should follow the
 specification. However, the kernel does not require every single
 device or bus to be described by the device tree.
@@ -596,9 +612,9 @@ those properties defining addresses format for devices directly mapped
 on the processor bus.
 
 Those 2 properties define 'cells' for representing an address and a
-size. A "cell" is a 32 bit number. For example, if both contain 2
+size. A "cell" is a 32-bit number. For example, if both contain 2
 like the example tree given above, then an address and a size are both
-composed of 2 cells, and each is a 64 bit number (cells are
+composed of 2 cells, and each is a 64-bit number (cells are
 concatenated and expected to be in big endian format). Another example
 is the way Apple firmware defines them, with 2 cells for an address
 and one cell for a size.  Most 32-bit implementations should define
@@ -632,7 +648,7 @@ prom_parse.c file of the recent kernels for your bus type.
 
 The "reg" property only defines addresses and sizes (if #size-cells
 is non-0) within a given bus. In order to translate addresses upward
-(that is into parent bus addresses, and possibly into cpu physical
+(that is into parent bus addresses, and possibly into CPU physical
 addresses), all busses must contain a "ranges" property. If the
 "ranges" property is missing at a given level, it's assumed that
 translation isn't possible. The format of the "ranges" property for a
@@ -648,9 +664,9 @@ example, for a PCI host controller, that would be a CPU address. For a
 PCI<->ISA bridge, that would be a PCI address. It defines the base
 address in the parent bus where the beginning of that range is mapped.
 
-For a new 64 bit powerpc board, I recommend either the 2/2 format or
+For a new 64-bit powerpc board, I recommend either the 2/2 format or
 Apple's 2/1 format which is slightly more compact since sizes usually
-fit in a single 32 bit word.   New 32 bit powerpc boards should use a
+fit in a single 32-bit word.   New 32-bit powerpc boards should use a
 1/1 format, unless the processor supports physical addresses greater
 than 32-bits, in which case a 2/1 format is recommended.
 
@@ -764,7 +780,7 @@ address which can extend beyond that limit.
   Required properties:
 
     - device_type : has to be "cpu"
-    - reg : This is the physical cpu number, it's a single 32 bit cell
+    - reg : This is the physical CPU number, it's a single 32-bit cell
       and is also used as-is as the unit number for constructing the
       unit name in the full path. For example, with 2 CPUs, you would
       have the full path:
@@ -785,7 +801,7 @@ address which can extend beyond that limit.
       the kernel timebase/decrementer calibration based on this
       value.
     - clock-frequency : a cell indicating the CPU core clock frequency
-      in Hz. A new property will be defined for 64 bit values, but if
+      in Hz. A new property will be defined for 64-bit values, but if
       your frequency is < 4Ghz, one cell is enough. Here as well as
       for the above, the common code doesn't use that property, but
       you are welcome to re-use the pSeries or Maple one. A future
@@ -832,8 +848,7 @@ address which can extend beyond that limit.
 
   This node is a bit "special". Normally, that's where open firmware
   puts some variable environment information, like the arguments, or
-  phandle pointers to nodes like the main interrupt controller, or the
-  default input/output devices.
+  the default input/output devices.
 
   This specification makes a few of these mandatory, but also defines
   some linux-specific properties that would be normally constructed by
@@ -853,14 +868,14 @@ address which can extend beyond that limit.
       that the kernel tries to find out the default console and has
       knowledge of various types like 8250 serial ports. You may want
       to extend this function to add your own.
-    - interrupt-controller : This is one cell containing a phandle
-      value that matches the "linux,phandle" property of your main
-      interrupt controller node. May be used for interrupt routing.
-
 
   Note that u-boot creates and fills in the chosen node for platforms
   that use it.
 
+  (Note: a practice that is now obsolete was to include a property
+  under /chosen called interrupt-controller which had a phandle value
+  that pointed to the main interrupt controller)
+
   f) the /soc<SOCname> node
 
   This node is used to represent a system-on-a-chip (SOC) and must be
@@ -908,8 +923,7 @@ address which can extend beyond that limit.
   The SOC node may contain child nodes for each SOC device that the
   platform uses.  Nodes should not be created for devices which exist
   on the SOC but are not used by a particular platform. See chapter VI
-  for more information on how to specify devices that are part of an
-SOC.
+  for more information on how to specify devices that are part of a SOC.
 
   Example SOC node for the MPC8540:
 
@@ -972,7 +986,7 @@ The syntax of the dtc tool is
         [-o output-filename] [-V output_version] input_filename
 
 
-The "output_version" defines what versio of the "blob" format will be
+The "output_version" defines what version of the "blob" format will be
 generated. Supported versions are 1,2,3 and 16. The default is
 currently version 3 but that may change in the future to version 16.
 
@@ -994,12 +1008,12 @@ supported currently at the toplevel.
                                 */
 
   property2 = <1234abcd>;      /* define a property containing a
-                                 * numerical 32 bits value (hexadecimal)
+                                 * numerical 32-bit value (hexadecimal)
                                 */
 
   property3 = <12345678 12345678 deadbeef>;
                                 /* define a property containing 3
-                                 * numerical 32 bits values (cells) in
+                                 * numerical 32-bit values (cells) in
                                  * hexadecimal
                                 */
   property4 = [0a 0b 0c 0d de ea ad be ef];
@@ -1068,7 +1082,7 @@ while all this has been defined and implemented.
     its usage in early_init_devtree(), and the corresponding various
     early_init_dt_scan_*() callbacks. That code can be re-used in a
     GPL bootloader, and as the author of that code, I would be happy
-    to discuss possible free licencing to any vendor who wishes to
+    to discuss possible free licensing to any vendor who wishes to
     integrate all or part of this code into a non-GPL bootloader.
 
 
@@ -1077,7 +1091,7 @@ VI - System-on-a-chip devices and nodes
 =======================================
 
 Many companies are now starting to develop system-on-a-chip
-processors, where the processor core (cpu) and many peripheral devices
+processors, where the processor core (CPU) and many peripheral devices
 exist on a single piece of silicon.  For these SOCs, an SOC node
 should be used that defines child nodes for the devices that make
 up the SOC. While platforms are not required to use this model in
@@ -1109,42 +1123,7 @@ See appendix A for an example partial SOC node definition for the
 MPC8540.
 
 
-2) Specifying interrupt information for SOC devices
----------------------------------------------------
-
-Each device that is part of an SOC and which generates interrupts
-should have the following properties:
-
-       - interrupt-parent : contains the phandle of the interrupt
-          controller which handles interrupts for this device
-       - interrupts : a list of tuples representing the interrupt
-          number and the interrupt sense and level for each interrupt
-          for this device.
-
-This information is used by the kernel to build the interrupt table
-for the interrupt controllers in the system.
-
-Sense and level information should be encoded as follows:
-
-   Devices connected to openPIC-compatible controllers should encode
-   sense and polarity as follows:
-
-       0 = low to high edge sensitive type enabled
-       1 = active low level sensitive type enabled
-       2 = active high level sensitive type enabled
-       3 = high to low edge sensitive type enabled
-
-   ISA PIC interrupt controllers should adhere to the ISA PIC
-   encodings listed below:
-
-       0 =  active low level sensitive type enabled
-       1 =  active high level sensitive type enabled
-       2 =  high to low edge sensitive type enabled
-       3 =  low to high edge sensitive type enabled
-
-
-
-3) Representing devices without a current OF specification
+2) Representing devices without a current OF specification
 ----------------------------------------------------------
 
 Currently, there are many devices on SOCs that do not have a standard
@@ -1201,6 +1180,13 @@ platforms are moved over to use the flattened-device-tree model.
     - phy-handle : The phandle for the PHY connected to this ethernet
       controller.
 
+  Recommended properties:
+
+    - linux,network-index : This is the intended "index" of this
+      network device.  This is used by the bootwrapper to interpret
+      MAC addresses passed by the firmware when no information other
+      than indices is available to associate an address with a device.
+
   Example:
 
        ethernet@24000 {
@@ -1312,10 +1298,10 @@ platforms are moved over to use the flattened-device-tree model.
    and additions :  
 
    Required properties :
-    - compatible : Should be "fsl-usb2-mph" for multi port host usb
-      controllers, or "fsl-usb2-dr" for dual role usb controllers
-    - phy_type : For multi port host usb controllers, should be one of
-      "ulpi", or "serial". For dual role usb controllers, should be
+    - compatible : Should be "fsl-usb2-mph" for multi port host USB
+      controllers, or "fsl-usb2-dr" for dual role USB controllers
+    - phy_type : For multi port host USB controllers, should be one of
+      "ulpi", or "serial". For dual role USB controllers, should be
       one of "ulpi", "utmi", "utmi_wide", or "serial".
     - reg : Offset and length of the register set for the device
     - port0 : boolean; if defined, indicates port0 is connected for
@@ -1339,7 +1325,7 @@ platforms are moved over to use the flattened-device-tree model.
     - interrupt-parent : the phandle for the interrupt controller that
       services interrupts for this device.
 
-   Example multi port host usb controller device node : 
+   Example multi port host USB controller device node :
        usb@22000 {
                device_type = "usb";
                compatible = "fsl-usb2-mph";
@@ -1353,7 +1339,7 @@ platforms are moved over to use the flattened-device-tree model.
                port1;
        };
 
-   Example dual role usb controller device node : 
+   Example dual role USB controller device node :
        usb@23000 {
                device_type = "usb";
                compatible = "fsl-usb2-dr";
@@ -1387,7 +1373,7 @@ platforms are moved over to use the flattened-device-tree model.
     - channel-fifo-len : An integer representing the number of
       descriptor pointers each channel fetch fifo can hold.
     - exec-units-mask : The bitmask representing what execution units
-      (EUs) are available. It's a single 32 bit cell. EU information
+      (EUs) are available. It's a single 32-bit cell. EU information
       should be encoded following the SEC's Descriptor Header Dword
       EU_SEL0 field documentation, i.e. as follows:
 
@@ -1403,7 +1389,7 @@ platforms are moved over to use the flattened-device-tree model.
       bits 8 through 31 are reserved for future SEC EUs.
 
     - descriptor-types-mask : The bitmask representing what descriptors
-      are available. It's a single 32 bit cell. Descriptor type
+      are available. It's a single 32-bit cell. Descriptor type
       information should be encoded following the SEC's Descriptor
       Header Dword DESC_TYPE field documentation, i.e. as follows:
 
@@ -1492,7 +1478,7 @@ platforms are moved over to use the flattened-device-tree model.
    Required properties:
    - device_type : should be "spi".
    - compatible : should be "fsl_spi".
-   - mode : the spi operation mode, it can be "cpu" or "qe".
+   - mode : the SPI operation mode, it can be "cpu" or "qe".
    - reg : Offset and length of the register set for the device
    - interrupts : <a b> where a is the interrupt number and b is a
      field that represents an encoding of the sense and level
@@ -1569,6 +1555,12 @@ platforms are moved over to use the flattened-device-tree model.
    - mac-address : list of bytes representing the ethernet address.
    - phy-handle : The phandle for the PHY connected to this controller.
 
+   Recommended properties:
+   - linux,network-index : This is the intended "index" of this
+     network device.  This is used by the bootwrapper to interpret
+     MAC addresses passed by the firmware when no information other
+     than indices is available to associate an address with a device.
+
    Example:
        ucc@2000 {
                device_type = "network";
@@ -1712,7 +1704,7 @@ platforms are moved over to use the flattened-device-tree model.
      - partitions : Several pairs of 32-bit values where the first value is
        partition's offset from the start of the device and the second one is
        partition size in bytes with LSB used to signify a read only
-       partition (so, the parition size should always be an even number).
+       partition (so, the partition size should always be an even number).
      - partition-names : The list of concatenated zero terminated strings
        representing the partition names.
      - probe-type : The type of probe which should be done for the chip
@@ -1733,6 +1725,92 @@ platforms are moved over to use the flattened-device-tree model.
 
    More devices will be defined as this spec matures.
 
+VII - Specifying interrupt information for devices
+===================================================
+
+The device tree represents the busses and devices of a hardware
+system in a form similar to the physical bus topology of the
+hardware.
+
+In addition, a logical 'interrupt tree' exists which represents the
+hierarchy and routing of interrupts in the hardware.
+
+The interrupt tree model is fully described in the
+document "Open Firmware Recommended Practice: Interrupt
+Mapping Version 0.9".  The document is available at:
+<http://playground.sun.com/1275/practice>.
+
+1) interrupts property
+----------------------
+
+Devices that generate interrupts to a single interrupt controller
+should use the conventional OF representation described in the
+OF interrupt mapping documentation.
+
+Each device which generates interrupts must have an 'interrupt'
+property.  The interrupt property value is an arbitrary number of
+of 'interrupt specifier' values which describe the interrupt or
+interrupts for the device.
+
+The encoding of an interrupt specifier is determined by the
+interrupt domain in which the device is located in the
+interrupt tree.  The root of an interrupt domain specifies in
+its #interrupt-cells property the number of 32-bit cells
+required to encode an interrupt specifier.  See the OF interrupt
+mapping documentation for a detailed description of domains.
+
+For example, the binding for the OpenPIC interrupt controller
+specifies  an #interrupt-cells value of 2 to encode the interrupt
+number and level/sense information. All interrupt children in an
+OpenPIC interrupt domain use 2 cells per interrupt in their interrupts
+property.
+
+The PCI bus binding specifies a #interrupt-cell value of 1 to encode
+which interrupt pin (INTA,INTB,INTC,INTD) is used.
+
+2) interrupt-parent property
+----------------------------
+
+The interrupt-parent property is specified to define an explicit
+link between a device node and its interrupt parent in
+the interrupt tree.  The value of interrupt-parent is the
+phandle of the parent node.
+
+If the interrupt-parent property is not defined for a node, it's
+interrupt parent is assumed to be an ancestor in the node's
+_device tree_ hierarchy.
+
+3) OpenPIC Interrupt Controllers
+--------------------------------
+
+OpenPIC interrupt controllers require 2 cells to encode
+interrupt information.  The first cell defines the interrupt
+number.  The second cell defines the sense and level
+information.
+
+Sense and level information should be encoded as follows:
+
+       0 = low to high edge sensitive type enabled
+       1 = active low level sensitive type enabled
+       2 = active high level sensitive type enabled
+       3 = high to low edge sensitive type enabled
+
+4) ISA Interrupt Controllers
+----------------------------
+
+ISA PIC interrupt controllers require 2 cells to encode
+interrupt information.  The first cell defines the interrupt
+number.  The second cell defines the sense and level
+information.
+
+ISA PIC interrupt controllers should adhere to the ISA PIC
+encodings listed below:
+
+       0 =  active low level sensitive type enabled
+       1 =  active high level sensitive type enabled
+       2 =  high to low edge sensitive type enabled
+       3 =  low to high edge sensitive type enabled
+
 
 Appendix A - Sample SOC node for MPC8540
 ========================================
index dfd26df056f4039fcf35c87548424ee301c21850..7a5c1a81905c66940fe2c3a2d516b237f957b970 100644 (file)
@@ -3,12 +3,18 @@ Sony Notebook Control Driver (SNC) Readme
        Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net>
        Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
 
-This mini-driver drives the SNC device present in the ACPI BIOS of
-the Sony Vaio laptops.
+This mini-driver drives the SNC and SPIC device present in the ACPI BIOS of the
+Sony Vaio laptops. This driver mixes both devices functions under the same
+(hopefully consistent) interface. This also means that the sonypi driver is
+obsoleted by sony-laptop now.
 
-It gives access to some extra laptop functionalities. In its current
-form, this driver let the user set or query the screen brightness
-through the backlight subsystem and remove/apply power to some devices.
+Fn keys (hotkeys):
+------------------
+Some models report hotkeys through the SNC or SPIC devices, such events are
+reported both through the ACPI subsystem as acpi events and through the INPUT
+subsystem. See the logs of acpid or /proc/acpi/event and
+/proc/bus/input/devices to find out what those events are and which input
+devices are created by the driver.
 
 Backlight control:
 ------------------
@@ -39,6 +45,8 @@ The files are:
        audiopower              power on/off the internal sound card
        lanpower                power on/off the internal ethernet card
                                (only in debug mode)
+       bluetoothpower          power on/off the internal bluetooth device
+       fanspeed                get/set the fan speed
 
 Note that some files may be missing if they are not supported
 by your particular laptop model.
@@ -76,9 +84,9 @@ The sony-laptop driver creates, for some of those methods (the most
 current ones found on several Vaio models), an entry under
 /sys/devices/platform/sony-laptop, just like the 'cdpower' one.
 You can create other entries corresponding to your own laptop methods by
-further editing the source (see the 'sony_acpi_values' table, and add a new
+further editing the source (see the 'sony_nc_values' table, and add a new
 entry to this table with your get/set method names using the
-HANDLE_NAMES macro).
+SNC_HANDLE_NAMES macro).
 
 Your mission, should you accept it, is to try finding out what
 those entries are for, by reading/writing random values from/to those
@@ -87,6 +95,9 @@ files and find out what is the impact on your laptop.
 Should you find anything interesting, please report it back to me,
 I will not disavow all knowledge of your actions :)
 
+See also http://www.linux.it/~malattia/wiki/index.php/Sony_drivers for other
+useful info.
+
 Bugs/Limitations:
 -----------------
 
similarity index 60%
rename from Documentation/ibm-acpi.txt
rename to Documentation/thinkpad-acpi.txt
index 0132d363feb564b0af0c3544226887df9f474aec..2d4803359a043e228292d9f8e82eeffc14ff454b 100644 (file)
@@ -1,16 +1,22 @@
-                   IBM ThinkPad ACPI Extras Driver
+                    ThinkPad ACPI Extras Driver
 
-                            Version 0.12
-                           17 August 2005
+                            Version 0.14
+                          April 21st, 2007
 
                Borislav Deianov <borislav@users.sf.net>
+            Henrique de Moraes Holschuh <hmh@hmh.eng.br>
                      http://ibm-acpi.sf.net/
 
 
-This is a Linux ACPI driver for the IBM ThinkPad laptops. It supports
-various features of these laptops which are accessible through the
-ACPI framework but not otherwise supported by the generic Linux ACPI
-drivers.
+This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It
+supports various features of these laptops which are accessible
+through the ACPI and ACPI EC framework, but not otherwise fully
+supported by the generic Linux ACPI drivers.
+
+This driver used to be named ibm-acpi until kernel 2.6.21 and release
+0.13-20070314.  It used to be in the drivers/acpi tree, but it was
+moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
+2.6.22, and release 0.14.
 
 
 Status
@@ -21,7 +27,7 @@ detailed description):
 
        - Fn key combinations
        - Bluetooth enable and disable
-       - video output switching, expansion control     
+       - video output switching, expansion control
        - ThinkLight on and off
        - limited docking and undocking
        - UltraBay eject
@@ -32,7 +38,7 @@ detailed description):
        - Experimental: embedded controller register dump
        - LCD brightness control
        - Volume control
-       - Experimental: fan speed, fan enable/disable
+       - Fan control and monitoring: fan speed, fan enable/disable
        - Experimental: WAN enable and disable
 
 A compatibility table by model and feature is maintained on the web
@@ -42,6 +48,8 @@ Please include the following information in your report:
 
        - ThinkPad model name
        - a copy of your DSDT, from /proc/acpi/dsdt
+       - a copy of the output of dmidecode, with serial numbers
+         and UUIDs masked off
        - which driver features work and which don't
        - the observed behavior of non-working features
 
@@ -52,25 +60,85 @@ Installation
 ------------
 
 If you are compiling this driver as included in the Linux kernel
-sources, simply enable the CONFIG_ACPI_IBM option (Power Management /
-ACPI / IBM ThinkPad Laptop Extras).
+sources, simply enable the CONFIG_THINKPAD_ACPI option, and optionally
+enable the CONFIG_THINKPAD_ACPI_BAY option if you want the
+thinkpad-specific bay functionality.
 
 Features
 --------
 
-The driver creates the /proc/acpi/ibm directory. There is a file under
-that directory for each feature described below. Note that while the
-driver is still in the alpha stage, the exact proc file format and
-commands supported by the various features is guaranteed to change
-frequently.
+The driver exports two different interfaces to userspace, which can be
+used to access the features it provides.  One is a legacy procfs-based
+interface, which will be removed at some time in the distant future.
+The other is a new sysfs-based interface which is not complete yet.
 
-Driver version -- /proc/acpi/ibm/driver
----------------------------------------
+The procfs interface creates the /proc/acpi/ibm directory.  There is a
+file under that directory for each feature it supports.  The procfs
+interface is mostly frozen, and will change very little if at all: it
+will not be extended to add any new functionality in the driver, instead
+all new functionality will be implemented on the sysfs interface.
+
+The sysfs interface tries to blend in the generic Linux sysfs subsystems
+and classes as much as possible.  Since some of these subsystems are not
+yet ready or stabilized, it is expected that this interface will change,
+and any and all userspace programs must deal with it.
+
+
+Notes about the sysfs interface:
+
+Unlike what was done with the procfs interface, correctness when talking
+to the sysfs interfaces will be enforced, as will correctness in the
+thinkpad-acpi's implementation of sysfs interfaces.
+
+Also, any bugs in the thinkpad-acpi sysfs driver code or in the
+thinkpad-acpi's implementation of the sysfs interfaces will be fixed for
+maximum correctness, even if that means changing an interface in
+non-compatible ways.  As these interfaces mature both in the kernel and
+in thinkpad-acpi, such changes should become quite rare.
+
+Applications interfacing to the thinkpad-acpi sysfs interfaces must
+follow all sysfs guidelines and correctly process all errors (the sysfs
+interface makes extensive use of errors).  File descriptors and open /
+close operations to the sysfs inodes must also be properly implemented.
+
+The version of thinkpad-acpi's sysfs interface is exported by the driver
+as a driver attribute (see below).
+
+Sysfs driver attributes are on the driver's sysfs attribute space,
+for 2.6.20 this is /sys/bus/platform/drivers/thinkpad-acpi/.
+
+Sysfs device attributes are on the driver's sysfs attribute space,
+for 2.6.20 this is /sys/devices/platform/thinkpad-acpi/.
+
+Driver version
+--------------
+
+procfs: /proc/acpi/ibm/driver
+sysfs driver attribute: version
 
 The driver name and version. No commands can be written to this file.
 
-Hot keys -- /proc/acpi/ibm/hotkey
----------------------------------
+Sysfs interface version
+-----------------------
+
+sysfs driver attribute: interface_version
+
+Version of the thinkpad-acpi sysfs interface, as an unsigned long
+(output in hex format: 0xAAAABBCC), where:
+       AAAA - major revision
+       BB - minor revision
+       CC - bugfix revision
+
+The sysfs interface version changelog for the driver can be found at the
+end of this document.  Changes to the sysfs interface done by the kernel
+subsystems are not documented here, nor are they tracked by this
+attribute.
+
+Hot keys
+--------
+
+procfs: /proc/acpi/ibm/hotkey
+sysfs device attribute: hotkey/*
 
 Without this driver, only the Fn-F4 key (sleep button) generates an
 ACPI event. With the driver loaded, the hotkey feature enabled and the
@@ -84,15 +152,6 @@ All labeled Fn-Fx key combinations generate distinct events. In
 addition, the lid microswitch and some docking station buttons may
 also generate such events.
 
-The following commands can be written to this file:
-
-       echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
-       echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
-       echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
-       echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
-       ... any other 4-hex-digit mask ...
-       echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
-
 The bit mask allows some control over which hot keys generate ACPI
 events. Not all bits in the mask can be modified. Not all bits that
 can be modified do anything. Not all hot keys can be individually
@@ -124,15 +183,77 @@ buttons do not generate ACPI events even with this driver. They *can*
 be used through the "ThinkPad Buttons" utility, see
 http://www.nongnu.org/tpb/
 
-Bluetooth -- /proc/acpi/ibm/bluetooth
--------------------------------------
+procfs notes:
+
+The following commands can be written to the /proc/acpi/ibm/hotkey file:
+
+       echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
+       echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
+       echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
+       echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
+       ... any other 4-hex-digit mask ...
+       echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
+
+sysfs notes:
+
+       The hot keys attributes are in a hotkey/ subdirectory off the
+       thinkpad device.
+
+       bios_enabled:
+               Returns the status of the hot keys feature when
+               thinkpad-acpi was loaded.  Upon module unload, the hot
+               key feature status will be restored to this value.
+
+               0: hot keys were disabled
+               1: hot keys were enabled
+
+       bios_mask:
+               Returns the hot keys mask when thinkpad-acpi was loaded.
+               Upon module unload, the hot keys mask will be restored
+               to this value.
+
+       enable:
+               Enables/disables the hot keys feature, and reports
+               current status of the hot keys feature.
+
+               0: disables the hot keys feature / feature disabled
+               1: enables the hot keys feature / feature enabled
+
+       mask:
+               bit mask to enable ACPI event generation for each hot
+               key (see above).  Returns the current status of the hot
+               keys mask, and allows one to modify it.
+
 
-This feature shows the presence and current state of a Bluetooth
-device. If Bluetooth is installed, the following commands can be used:
+Bluetooth
+---------
+
+procfs: /proc/acpi/ibm/bluetooth
+sysfs device attribute: bluetooth/enable
+
+This feature shows the presence and current state of a ThinkPad
+Bluetooth device in the internal ThinkPad CDC slot.
+
+Procfs notes:
+
+If Bluetooth is installed, the following commands can be used:
 
        echo enable > /proc/acpi/ibm/bluetooth
        echo disable > /proc/acpi/ibm/bluetooth
 
+Sysfs notes:
+
+       If the Bluetooth CDC card is installed, it can be enabled /
+       disabled through the "bluetooth/enable" thinkpad-acpi device
+       attribute, and its current status can also be queried.
+
+       enable:
+               0: disables Bluetooth / Bluetooth is disabled
+               1: enables Bluetooth / Bluetooth is enabled.
+
+       Note: this interface will be probably be superseeded by the
+       generic rfkill class.
+
 Video output control -- /proc/acpi/ibm/video
 --------------------------------------------
 
@@ -209,7 +330,7 @@ hot plugging of devices in the Linux ACPI framework. If the laptop was
 booted while not in the dock, the following message is shown in the
 logs:
 
-       Mar 17 01:42:34 aero kernel: ibm_acpi: dock device not present
+       Mar 17 01:42:34 aero kernel: thinkpad_acpi: dock device not present
 
 In this case, no dock-related events are generated but the dock and
 undock commands described below still work. They can be executed
@@ -269,7 +390,7 @@ This is due to the current lack of support for hot plugging of devices
 in the Linux ACPI framework. If the laptop was booted without the
 UltraBay, the following message is shown in the logs:
 
-       Mar 17 01:42:34 aero kernel: ibm_acpi: bay device not present
+       Mar 17 01:42:34 aero kernel: thinkpad_acpi: bay device not present
 
 In this case, no bay-related events are generated but the eject
 command described below still works. It can be executed manually or
@@ -313,23 +434,19 @@ supported. Use "eject2" instead of "eject" for the second bay.
 Note: the UltraBay eject support on the 600e/x, A22p and A3x is
 EXPERIMENTAL and may not work as expected. USE WITH CAUTION!
 
-CMOS control -- /proc/acpi/ibm/cmos
------------------------------------
+CMOS control
+------------
+
+procfs: /proc/acpi/ibm/cmos
+sysfs device attribute: cmos_command
 
 This feature is used internally by the ACPI firmware to control the
 ThinkLight on most newer ThinkPad models. It may also control LCD
 brightness, sounds volume and more, but only on some models.
 
-The commands are non-negative integer numbers:
-
-       echo 0 >/proc/acpi/ibm/cmos
-       echo 1 >/proc/acpi/ibm/cmos
-       echo 2 >/proc/acpi/ibm/cmos
-       ...
-
-The range of valid numbers is 0 to 21, but not all have an effect and
-the behavior varies from model to model. Here is the behavior on the
-X40 (tpb is the ThinkPad Buttons utility):
+The range of valid cmos command numbers is 0 to 21, but not all have an
+effect and the behavior varies from model to model.  Here is the behavior
+on the X40 (tpb is the ThinkPad Buttons utility):
 
        0 - no effect but tpb reports "Volume down"
        1 - no effect but tpb reports "Volume up"
@@ -342,6 +459,9 @@ X40 (tpb is the ThinkPad Buttons utility):
        13 - ThinkLight off
        14 - no effect but tpb reports ThinkLight status change
 
+The cmos command interface is prone to firmware split-brain problems, as
+in newer ThinkPads it is just a compatibility layer.
+
 LED control -- /proc/acpi/ibm/led
 ---------------------------------
 
@@ -393,17 +513,17 @@ X40:
        16 - one medium-pitched beep repeating constantly, stop with 17
        17 - stop 16
 
-Temperature sensors -- /proc/acpi/ibm/thermal
----------------------------------------------
+Temperature sensors
+-------------------
+
+procfs: /proc/acpi/ibm/thermal
+sysfs device attributes: (hwmon) temp*_input
 
 Most ThinkPads include six or more separate temperature sensors but
 only expose the CPU temperature through the standard ACPI methods.
 This feature shows readings from up to eight different sensors on older
 ThinkPads, and it has experimental support for up to sixteen different
-sensors on newer ThinkPads.  Readings from sensors that are not available
-return -128.
-
-No commands can be written to this file.
+sensors on newer ThinkPads.
 
 EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the
 implementation directly accesses hardware registers and may not work as
@@ -460,6 +580,20 @@ The A31 has a very atypical layout for the thermal sensors
 8:  Bay Battery: secondary sensor
 
 
+Procfs notes:
+       Readings from sensors that are not available return -128.
+       No commands can be written to this file.
+
+Sysfs notes:
+       Sensors that are not available return the ENXIO error.  This
+       status may change at runtime, as there are hotplug thermal
+       sensors, like those inside the batteries and docks.
+
+       thinkpad-acpi thermal sensors are reported through the hwmon
+       subsystem, and follow all of the hwmon guidelines at
+       Documentation/hwmon.
+
+
 EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
 ------------------------------------------------------------------------
 
@@ -472,7 +606,7 @@ This feature dumps the values of 256 embedded controller
 registers. Values which have changed since the last time the registers
 were dumped are marked with a star:
 
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump 
+[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
 EC       +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
 EC 0x00:  a7  47  87  01  fe  96  00  08  01  00  cb  00  00  00  40  00
 EC 0x10:  00  00  ff  ff  f4  3c  87  09  01  ff  42  01  ff  ff  0d  00
@@ -503,7 +637,7 @@ vary. The second ensures that the fan-related values do vary, since
 the fan speed fluctuates a bit. The third will (hopefully) mark the
 fan register with a star:
 
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump 
+[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
 EC       +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
 EC 0x00:  a7  47  87  01  fe  96  00  08  01  00  cb  00  00  00  40  00
 EC 0x10:  00  00  ff  ff  f4  3c  87  09  01  ff  42  01  ff  ff  0d  00
@@ -533,19 +667,59 @@ registers contain the current battery capacity, etc. If you experiment
 with this, do send me your results (including some complete dumps with
 a description of the conditions when they were taken.)
 
-LCD brightness control -- /proc/acpi/ibm/brightness
----------------------------------------------------
+LCD brightness control
+----------------------
+
+procfs: /proc/acpi/ibm/brightness
+sysfs backlight device "thinkpad_screen"
 
 This feature allows software control of the LCD brightness on ThinkPad
-models which don't have a hardware brightness slider. The available
-commands are:
+models which don't have a hardware brightness slider.
+
+It has some limitations: the LCD backlight cannot be actually turned on or off
+by this interface, and in many ThinkPad models, the "dim while on battery"
+functionality will be enabled by the BIOS when this interface is used, and
+cannot be controlled.
+
+The backlight control has eight levels, ranging from 0 to 7.  Some of the
+levels may not be distinct.
+
+Procfs notes:
+
+       The available commands are:
 
        echo up   >/proc/acpi/ibm/brightness
        echo down >/proc/acpi/ibm/brightness
        echo 'level <level>' >/proc/acpi/ibm/brightness
 
-The <level> number range is 0 to 7, although not all of them may be
-distinct. The current brightness level is shown in the file.
+Sysfs notes:
+
+The interface is implemented through the backlight sysfs class, which is poorly
+documented at this time.
+
+Locate the thinkpad_screen device under /sys/class/backlight, and inside it
+there will be the following attributes:
+
+       max_brightness:
+               Reads the maximum brightness the hardware can be set to.
+               The minimum is always zero.
+
+       actual_brightness:
+               Reads what brightness the screen is set to at this instant.
+
+       brightness:
+               Writes request the driver to change brightness to the given
+               value.  Reads will tell you what brightness the driver is trying
+               to set the display to when "power" is set to zero and the display
+               has not been dimmed by a kernel power management event.
+
+       power:
+               power management mode, where 0 is "display on", and 1 to 3 will
+               dim the display backlight to brightness level 0 because
+               thinkpad-acpi cannot really turn the backlight off.  Kernel
+               power management events can temporarily increase the current
+               power management level, i.e. they can dim the display.
+
 
 Volume control -- /proc/acpi/ibm/volume
 ---------------------------------------
@@ -563,41 +737,42 @@ distinct. The unmute the volume after the mute command, use either the
 up or down command (the level command will not unmute the volume).
 The current volume level and mute state is shown in the file.
 
-EXPERIMENTAL: fan speed, fan enable/disable -- /proc/acpi/ibm/fan
------------------------------------------------------------------
+Fan control and monitoring: fan speed, fan enable/disable
+---------------------------------------------------------
 
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
+procfs: /proc/acpi/ibm/fan
+sysfs device attributes: (hwmon) fan_input, pwm1, pwm1_enable
+
+NOTE NOTE NOTE: fan control operations are disabled by default for
+safety reasons.  To enable them, the module parameter "fan_control=1"
+must be given to thinkpad-acpi.
 
 This feature attempts to show the current fan speed, control mode and
 other fan data that might be available.  The speed is read directly
 from the hardware registers of the embedded controller.  This is known
-to work on later R, T and X series ThinkPads but may show a bogus
+to work on later R, T, X and Z series ThinkPads but may show a bogus
 value on other models.
 
-Most ThinkPad fans work in "levels".  Level 0 stops the fan.  The higher
-the level, the higher the fan speed, although adjacent levels often map
-to the same fan speed.  7 is the highest level, where the fan reaches
-the maximum recommended speed.  Level "auto" means the EC changes the
-fan level according to some internal algorithm, usually based on
-readings from the thermal sensors.  Level "disengaged" means the EC
-disables the speed-locked closed-loop fan control, and drives the fan as
-fast as it can go, which might exceed hardware limits, so use this level
-with caution.
+Fan levels:
 
-The fan usually ramps up or down slowly from one speed to another,
-and it is normal for the EC to take several seconds to react to fan
-commands.
+Most ThinkPad fans work in "levels" at the firmware interface.  Level 0
+stops the fan.  The higher the level, the higher the fan speed, although
+adjacent levels often map to the same fan speed.  7 is the highest
+level, where the fan reaches the maximum recommended speed.
 
-The fan may be enabled or disabled with the following commands:
+Level "auto" means the EC changes the fan level according to some
+internal algorithm, usually based on readings from the thermal sensors.
 
-       echo enable  >/proc/acpi/ibm/fan
-       echo disable >/proc/acpi/ibm/fan
+There is also a "full-speed" level, also known as "disengaged" level.
+In this level, the EC disables the speed-locked closed-loop fan control,
+and drives the fan as fast as it can go, which might exceed hardware
+limits, so use this level with caution.
 
-Placing a fan on level 0 is the same as disabling it.  Enabling a fan
-will try to place it in a safe level if it is too slow or disabled.
+The fan usually ramps up or down slowly from one speed to another, and
+it is normal for the EC to take several seconds to react to fan
+commands.  The full-speed level may take up to two minutes to ramp up to
+maximum speed, and in some ThinkPads, the tachometer readings go stale
+while the EC is transitioning to the full-speed level.
 
 WARNING WARNING WARNING: do not leave the fan disabled unless you are
 monitoring all of the temperature sensor readings and you are ready to
@@ -615,46 +790,146 @@ fan is turned off when the CPU temperature drops to 49 degrees and the
 HDD temperature drops to 41 degrees.  These thresholds cannot
 currently be controlled.
 
+The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
+certain conditions are met.  It will override any fan programming done
+through thinkpad-acpi.
+
+The thinkpad-acpi kernel driver can be programmed to revert the fan
+level to a safe setting if userspace does not issue one of the procfs
+fan commands: "enable", "disable", "level" or "watchdog", or if there
+are no writes to pwm1_enable (or to pwm1 *if and only if* pwm1_enable is
+set to 1, manual mode) within a configurable amount of time of up to
+120 seconds.  This functionality is called fan safety watchdog.
+
+Note that the watchdog timer stops after it enables the fan.  It will be
+rearmed again automatically (using the same interval) when one of the
+above mentioned fan commands is received.  The fan watchdog is,
+therefore, not suitable to protect against fan mode changes made through
+means other than the "enable", "disable", and "level" procfs fan
+commands, or the hwmon fan control sysfs interface.
+
+Procfs notes:
+
+The fan may be enabled or disabled with the following commands:
+
+       echo enable  >/proc/acpi/ibm/fan
+       echo disable >/proc/acpi/ibm/fan
+
+Placing a fan on level 0 is the same as disabling it.  Enabling a fan
+will try to place it in a safe level if it is too slow or disabled.
+
 The fan level can be controlled with the command:
 
-       echo 'level <level>' > /proc/acpi/ibm/thermal
+       echo 'level <level>' > /proc/acpi/ibm/fan
 
-Where <level> is an integer from 0 to 7, or one of the words "auto"
-or "disengaged" (without the quotes).  Not all ThinkPads support the
-"auto" and "disengaged" levels.
+Where <level> is an integer from 0 to 7, or one of the words "auto" or
+"full-speed" (without the quotes).  Not all ThinkPads support the "auto"
+and "full-speed" levels.  The driver accepts "disengaged" as an alias for
+"full-speed", and reports it as "disengaged" for backwards
+compatibility.
 
 On the X31 and X40 (and ONLY on those models), the fan speed can be
-controlled to a certain degree. Once the fan is running, it can be
+controlled to a certain degree.  Once the fan is running, it can be
 forced to run faster or slower with the following command:
 
-       echo 'speed <speed>' > /proc/acpi/ibm/thermal
+       echo 'speed <speed>' > /proc/acpi/ibm/fan
 
-The sustainable range of fan speeds on the X40 appears to be from
-about 3700 to about 7350. Values outside this range either do not have
-any effect or the fan speed eventually settles somewhere in that
-range. The fan cannot be stopped or started with this command.
+The sustainable range of fan speeds on the X40 appears to be from about
+3700 to about 7350. Values outside this range either do not have any
+effect or the fan speed eventually settles somewhere in that range.  The
+fan cannot be stopped or started with this command.  This functionality
+is incomplete, and not available through the sysfs interface.
 
-The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
-certain conditions are met.  It will override any fan programming done
-through ibm-acpi.
+To program the safety watchdog, use the "watchdog" command.
 
-EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
----------------------------------------
+       echo 'watchdog <interval in seconds>' > /proc/acpi/ibm/fan
+
+If you want to disable the watchdog, use 0 as the interval.
+
+Sysfs notes:
+
+The sysfs interface follows the hwmon subsystem guidelines for the most
+part, and the exception is the fan safety watchdog.
+
+Writes to any of the sysfs attributes may return the EINVAL error if
+that operation is not supported in a given ThinkPad or if the parameter
+is out-of-bounds, and EPERM if it is forbidden.  They may also return
+EINTR (interrupted system call), and EIO (I/O error while trying to talk
+to the firmware).
+
+Features not yet implemented by the driver return ENOSYS.
+
+hwmon device attribute pwm1_enable:
+       0: PWM offline (fan is set to full-speed mode)
+       1: Manual PWM control (use pwm1 to set fan level)
+       2: Hardware PWM control (EC "auto" mode)
+       3: reserved (Software PWM control, not implemented yet)
+
+       Modes 0 and 2 are not supported by all ThinkPads, and the
+       driver is not always able to detect this.  If it does know a
+       mode is unsupported, it will return -EINVAL.
+
+hwmon device attribute pwm1:
+       Fan level, scaled from the firmware values of 0-7 to the hwmon
+       scale of 0-255.  0 means fan stopped, 255 means highest normal
+       speed (level 7).
+
+       This attribute only commands the fan if pmw1_enable is set to 1
+       (manual PWM control).
+
+hwmon device attribute fan1_input:
+       Fan tachometer reading, in RPM.  May go stale on certain
+       ThinkPads while the EC transitions the PWM to offline mode,
+       which can take up to two minutes.  May return rubbish on older
+       ThinkPads.
+
+driver attribute fan_watchdog:
+       Fan safety watchdog timer interval, in seconds.  Minimum is
+       1 second, maximum is 120 seconds.  0 disables the watchdog.
+
+To stop the fan: set pwm1 to zero, and pwm1_enable to 1.
+
+To start the fan in a safe mode: set pwm1_enable to 2.  If that fails
+with EINVAL, try to set pwm1_enable to 1 and pwm1 to at least 128 (255
+would be the safest choice, though).
+
+
+EXPERIMENTAL: WAN
+-----------------
+
+procfs: /proc/acpi/ibm/wan
+sysfs device attribute: wwan/enable
 
 This feature is marked EXPERIMENTAL because the implementation
 directly accesses hardware registers and may not work as expected. USE
 WITH CAUTION! To use this feature, you need to supply the
 experimental=1 parameter when loading the module.
 
-This feature shows the presence and current state of a WAN (Sierra
-Wireless EV-DO) device. If WAN is installed, the following commands can
-be used:
+This feature shows the presence and current state of a W-WAN (Sierra
+Wireless EV-DO) device.
+
+It was tested on a Lenovo Thinkpad X60. It should probably work on other
+Thinkpad models which come with this module installed.
+
+Procfs notes:
+
+If the W-WAN card is installed, the following commands can be used:
 
        echo enable > /proc/acpi/ibm/wan
        echo disable > /proc/acpi/ibm/wan
 
-It was tested on a Lenovo Thinkpad X60. It should probably work on other
-Thinkpad models which come with this module installed.
+Sysfs notes:
+
+       If the W-WAN card is installed, it can be enabled /
+       disabled through the "wwan/enable" thinkpad-acpi device
+       attribute, and its current status can also be queried.
+
+       enable:
+               0: disables WWAN card / WWAN card is disabled
+               1: enables WWAN card / WWAN card is enabled.
+
+       Note: this interface will be probably be superseeded by the
+       generic rfkill class.
 
 Multiple Commands, Module Parameters
 ------------------------------------
@@ -665,64 +940,42 @@ separating them with commas, for example:
        echo enable,0xffff > /proc/acpi/ibm/hotkey
        echo lcd_disable,crt_enable > /proc/acpi/ibm/video
 
-Commands can also be specified when loading the ibm_acpi module, for
-example:
-
-       modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable
-
-The ibm-acpi kernel driver can be programmed to revert the fan level
-to a safe setting if userspace does not issue one of the fan commands:
-"enable", "disable", "level" or "watchdog" within a configurable
-ammount of time.  To do this, use the "watchdog" command.
-
-       echo 'watchdog <interval>' > /proc/acpi/ibm/fan
-
-Interval is the ammount of time in seconds to wait for one of the
-above mentioned fan commands before reseting the fan level to a safe
-one.  If set to zero, the watchdog is disabled (default).  When the
-watchdog timer runs out, it does the exact equivalent of the "enable"
-fan command.
-
-Note that the watchdog timer stops after it enables the fan.  It will
-be rearmed again automatically (using the same interval) when one of
-the above mentioned fan commands is received.  The fan watchdog is,
-therefore, not suitable to protect against fan mode changes made
-through means other than the "enable", "disable", and "level" fan
-commands.
-
-
-Example Configuration
----------------------
-
-The ACPI support in the kernel is intended to be used in conjunction
-with a user-space daemon, acpid. The configuration files for this
-daemon control what actions are taken in response to various ACPI
-events. An example set of configuration files are included in the
-config/ directory of the tarball package available on the web
-site. Note that these are provided for illustration purposes only and
-may need to be adapted to your particular setup.
-
-The following utility scripts are used by the example action
-scripts (included with ibm-acpi for completeness):
-
-       /usr/local/sbin/idectl -- from the hdparm source distribution,
-               see http://www.ibiblio.org/pub/Linux/system/hardware
-       /usr/local/sbin/laptop_mode -- from the Linux kernel source
-               distribution, see Documentation/laptop-mode.txt
-       /sbin/service -- comes with Redhat/Fedora distributions
-       /usr/sbin/hibernate -- from the Software Suspend 2 distribution,
-               see http://softwaresuspend.berlios.de/
-
-Toan T Nguyen <ntt@physics.ucla.edu> notes that Suse uses the
-powersave program to suspend ('powersave --suspend-to-ram') or
-hibernate ('powersave --suspend-to-disk'). This means that the
-hibernate script is not needed on that distribution.
-
-Henrik Brix Andersen <brix@gentoo.org> has written a Gentoo ACPI event
-handler script for the X31. You can get the latest version from
-http://dev.gentoo.org/~brix/files/x31.sh
-
-David Schweikert <dws@ee.eth.ch> has written an alternative blank.sh
-script which works on Debian systems. This scripts has now been
-extended to also work on Fedora systems and included as the default
-blank.sh in the distribution.
+Commands can also be specified when loading the thinkpad-acpi module,
+for example:
+
+       modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable
+
+Enabling debugging output
+-------------------------
+
+The module takes a debug paramater which can be used to selectively
+enable various classes of debugging output, for example:
+
+        modprobe ibm_acpi debug=0xffff
+
+will enable all debugging output classes.  It takes a bitmask, so
+to enable more than one output class, just add their values.
+
+       Debug bitmask           Description
+       0x0001                  Initialization and probing
+       0x0002                  Removal
+
+There is also a kernel build option to enable more debugging
+information, which may be necessary to debug driver problems.
+
+The level of debugging information output by the driver can be changed
+at runtime through sysfs, using the driver attribute debug_level.  The
+attribute takes the same bitmask as the debug module parameter above.
+
+Force loading of module
+-----------------------
+
+If thinkpad-acpi refuses to detect your ThinkPad, you can try to specify
+the module parameter force_load=1.  Regardless of whether this works or
+not, please contact ibm-acpi-devel@lists.sourceforge.net with a report.
+
+
+Sysfs interface changelog:
+
+0x000100:      Initial sysfs support, as a single platform driver and
+               device.
index ecb34160e61d5ca2fafad4bba259b782199cc66e..5e51c59bf2b024e2915d747e76f63d00e11d53f9 100644 (file)
@@ -5,10 +5,9 @@ Vaio Picturebook Motion Eye Camera Driver Readme
        Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
 
 This driver enable the use of video4linux compatible applications with the
-Motion Eye camera. This driver requires the "Sony Vaio Programmable I/O
-Control Device" driver (which can be found in the "Character drivers"
-section of the kernel configuration utility) to be compiled and installed
-(using its "camera=1" parameter).
+Motion Eye camera. This driver requires the "Sony Laptop Extras" driver (which
+can be found in the "Misc devices" section of the kernel configuration utility)
+to be compiled and installed (using its "camera=1" parameter).
 
 It can do at maximum 30 fps @ 320x240 or 15 fps @ 640x480.
 
index 77bff8ce1a44b97da2d9f6465add0e64a1a79f48..af1c7926c1530e16da6e2bb4d196707d4d5c77cb 100644 (file)
@@ -1582,9 +1582,9 @@ S:        Supported
 
 HOST AP DRIVER
 P:     Jouni Malinen
-M:     jkmaline@cc.hut.fi
+M:     j@w1.fi
+L:     hostap@shmoo.com (subscribers-only)
 L:     linux-wireless@vger.kernel.org
-L:     hostap@shmoo.com
 W:     http://hostap.epitest.fi/
 S:     Maintained
 
@@ -1658,15 +1658,6 @@ W:       http://www.ia64-linux.org/
 T:     git kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
 S:     Maintained
 
-IBM ACPI EXTRAS DRIVER
-P:     Henrique de Moraes Holschuh
-M:     ibm-acpi@hmh.eng.br
-L:     ibm-acpi-devel@lists.sourceforge.net
-W:     http://ibm-acpi.sourceforge.net
-W:     http://thinkwiki.org/wiki/Ibm-acpi
-T:     git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
-S:     Maintained
-
 SN-IA64 (Itanium) SUB-PLATFORM
 P:     Jes Sorensen
 M:     jes@sgi.com
@@ -1820,6 +1811,7 @@ P:        Jeff Kirsher
 M:     jeffrey.t.kirsher@intel.com
 P:     Auke Kok
 M:     auke-jan.h.kok@intel.com
+L:     e1000-devel@lists.sourceforge.net
 W:     http://sourceforge.net/projects/e1000/
 S:     Supported
 
@@ -1834,6 +1826,7 @@ P:        Jeff Kirsher
 M:     jeffrey.t.kirsher@intel.com
 P:     Auke Kok
 M:     auke-jan.h.kok@intel.com
+L:     e1000-devel@lists.sourceforge.net
 W:     http://sourceforge.net/projects/e1000/
 S:     Supported
 
@@ -1848,6 +1841,7 @@ P:        Jesse Brandeburg
 M:     jesse.brandeburg@intel.com
 P:     Auke Kok
 M:     auke-jan.h.kok@intel.com
+L:     e1000-devel@lists.sourceforge.net
 W:     http://sourceforge.net/projects/e1000/
 S:     Supported
 
@@ -2509,6 +2503,19 @@ M:       adaplas@gmail.com
 L:     linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
 S:     Maintained
 
+NETERION (S2IO) Xframe 10GbE DRIVER
+P:     Ramkrishna Vepa
+M:     ram.vepa@neterion.com
+P:     Rastapur Santosh
+M:     santosh.rastapur@neterion.com
+P:     Sivakumar Subramani
+M:     sivakumar.subramani@neterion.com
+P:     Sreenivasa Honnur
+M:     sreenivasa.honnur@neterion.com
+L:     netdev@vger.kernel.org
+W:     http://trac.neterion.com/cgi-bin/trac.cgi/wiki/TitleIndex?anonymous
+S:     Supported
+
 OPENCORES I2C BUS DRIVER
 P:     Peter Korsgaard
 M:     jacmet@sunsite.dk
@@ -3166,6 +3173,15 @@ P:       Chris Zankel
 M:     chris@zankel.net
 S:     Maintained
 
+THINKPAD ACPI EXTRAS DRIVER
+P:     Henrique de Moraes Holschuh
+M:     ibm-acpi@hmh.eng.br
+L:     ibm-acpi-devel@lists.sourceforge.net
+W:     http://ibm-acpi.sourceforge.net
+W:     http://thinkwiki.org/wiki/Ibm-acpi
+T:     git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
+S:     Maintained
+
 UltraSPARC (sparc64):
 P:     David S. Miller
 M:     davem@davemloft.net
index f4efd66e1ee502a401c720085d8f81fcfe6c803e..c96911c37aea28b7141c7ee26d43b49e4982f902 100644 (file)
@@ -692,7 +692,6 @@ CONFIG_SATA_SIL=y
 CONFIG_SATA_VIA=y
 # CONFIG_SATA_VITESSE is not set
 # CONFIG_SATA_INIC162X is not set
-CONFIG_SATA_INTEL_COMBINED=y
 CONFIG_SATA_ACPI=y
 # CONFIG_PATA_ALI is not set
 # CONFIG_PATA_AMD is not set
index a7d22d9f3d7e50d13ae2c4d6a43aba093a920b8a..8f7efd38254d47afd953054fa8cbf42e47d1dff8 100644 (file)
@@ -23,10 +23,13 @@ static int __init nvidia_hpet_check(struct acpi_table_header *header)
 static int __init check_bridge(int vendor, int device)
 {
 #ifdef CONFIG_ACPI
+       static int warned;
        /* According to Nvidia all timer overrides are bogus unless HPET
           is enabled. */
        if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) {
-               if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) {
+               if (!warned && acpi_table_parse(ACPI_SIG_HPET,
+                                               nvidia_hpet_check)) {
+                       warned = 1;
                        acpi_skip_timer_override = 1;
                          printk(KERN_INFO "Nvidia board "
                        "detected. Ignoring ACPI "
index 6aeebc9122f25ff96de48b107833a7a324a6de65..dc0bfda114277fa17a32d4f5280e345cb6b22a2f 100644 (file)
@@ -17,7 +17,8 @@
 # 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
 #
 
-obj-y := sim_setup.o sim_mem.o sim_time.o sim_int.o sim_cmdline.o
+obj-y := sim_platform.o sim_setup.o sim_mem.o sim_time.o sim_int.o \
+        sim_cmdline.o
 
 obj-$(CONFIG_EARLY_PRINTK) += sim_console.o
 obj-$(CONFIG_SMP) += sim_smp.o
diff --git a/arch/mips/mips-boards/sim/sim_platform.c b/arch/mips/mips-boards/sim/sim_platform.c
new file mode 100644 (file)
index 0000000..53210a8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007 by Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/init.h>
+#include <linux/if_ether.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+static char mipsnet_string[] = "mipsnet";
+
+static struct platform_device eth1_device = {
+       .name           = mipsnet_string,
+       .id             = 0,
+};
+
+/*
+ * Create a platform device for the GPI port that receives the
+ * image data from the embedded camera.
+ */
+static int __init mipsnet_devinit(void)
+{
+       int err;
+
+       err = platform_device_register(&eth1_device);
+       if (err)
+               printk(KERN_ERR "%s: registration failed\n", mipsnet_string);
+
+       return err;
+}
+
+device_initcall(mipsnet_devinit);
index 782906b644ddd46253f231bfd692153f4ef973e0..eb2f9a3d515c4ec6925b30eb034888a67688541b 100644 (file)
@@ -435,7 +435,6 @@ CONFIG_SCSI_SATA_SIL=m
 # CONFIG_SCSI_SATA_ULI is not set
 CONFIG_SCSI_SATA_VIA=m
 # CONFIG_SCSI_SATA_VITESSE is not set
-CONFIG_SCSI_SATA_INTEL_COMBINED=y
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_IPS is not set
index 6dfbd52694ab855600205680beea9b3b49c89ed4..a54a9a2e36f34367ec1d22206075e8fe318fcd07 100644 (file)
@@ -11,6 +11,11 @@ config PPC64
          This option selects whether a 32-bit or a 64-bit kernel
          will be built.
 
+config PPC_PM_NEEDS_RTC_LIB
+       bool
+       select RTC_LIB
+       default y if PM
+
 config PPC32
        bool
        default y if !PPC64
@@ -89,7 +94,7 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER
 
 config ARCH_MAY_HAVE_PC_FDC
        bool
-       default y
+       default !PPC_PSERIES || PCI
 
 config PPC_OF
        def_bool y
@@ -157,17 +162,20 @@ config PPC_83xx
        select FSL_SOC
        select 83xx
        select PPC_FPU
+       select WANT_DEVICE_TREE
 
 config PPC_85xx
        bool "Freescale 85xx"
        select E500
        select FSL_SOC
        select 85xx
+       select WANT_DEVICE_TREE
 
 config PPC_86xx
        bool "Freescale 86xx"
        select 6xx
        select FSL_SOC
+       select FSL_PCIE
        select PPC_FPU
        select ALTIVEC
        help
@@ -186,7 +194,6 @@ config 44x
        bool "AMCC 44x"
        select PPC_DCR_NATIVE
 
-
 config E200
        bool "Freescale e200"
 
@@ -367,394 +374,7 @@ endmenu
 
 source "init/Kconfig"
 
-menu "Platform support"
-       depends on PPC64 || CLASSIC32
-
-choice
-       prompt "Machine type"
-       default PPC_MULTIPLATFORM
-
-config PPC_MULTIPLATFORM
-       bool "Generic desktop/server/laptop"
-       help
-         Select this option if configuring for an IBM pSeries or
-         RS/6000 machine, an Apple machine, or a PReP, CHRP,
-         Maple or Cell-based machine.
-
-config EMBEDDED6xx
-       bool "Embedded 6xx/7xx/7xxx-based board"
-       depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
-
-config APUS
-       bool "Amiga-APUS"
-       depends on PPC32 && BROKEN
-       help
-         Select APUS if configuring for a PowerUP Amiga.
-         More information is available at:
-         <http://linux-apus.sourceforge.net/>.
-endchoice
-
-config QUICC_ENGINE
-       bool
-       depends on PPC_MPC836x || PPC_MPC832x
-       default y
-       help
-         The QUICC Engine (QE) is a new generation of communications
-         coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
-         Selecting this option means that you wish to build a kernel
-         for a machine with a QE coprocessor.
-
-config PPC_PSERIES
-       depends on PPC_MULTIPLATFORM && PPC64
-       bool "IBM pSeries & new (POWER5-based) iSeries"
-       select MPIC
-       select PPC_I8259
-       select PPC_RTAS
-       select RTAS_ERROR_LOGGING
-       select PPC_UDBG_16550
-       select PPC_NATIVE
-       default y
-
-config PPC_ISERIES
-       bool "IBM Legacy iSeries"
-       depends on PPC_MULTIPLATFORM && PPC64
-       select PPC_INDIRECT_IO
-
-config PPC_CHRP
-       bool "Common Hardware Reference Platform (CHRP) based machines"
-       depends on PPC_MULTIPLATFORM && PPC32
-       select MPIC
-       select PPC_I8259
-       select PPC_INDIRECT_PCI
-       select PPC_RTAS
-       select PPC_MPC106
-       select PPC_UDBG_16550
-       select PPC_NATIVE
-       default y
-
-config PPC_MPC52xx
-       bool
-       default n
-
-config PPC_MPC5200
-       bool
-       select PPC_MPC52xx
-       default n
-
-config PPC_MPC5200_BUGFIX
-       bool "MPC5200 (L25R) bugfix support"
-       depends on PPC_MPC5200
-       default n
-       help
-         Enable workarounds for original MPC5200 errata.  This is not required
-         for MPC5200B based boards.
-
-         It is safe to say 'Y' here
-
-config PPC_EFIKA
-       bool "bPlan Efika 5k2. MPC5200B based computer"
-       depends on PPC_MULTIPLATFORM && PPC32
-       select PPC_RTAS
-       select RTAS_PROC
-       select PPC_MPC52xx
-       select PPC_NATIVE
-       default n
-
-config PPC_LITE5200
-       bool "Freescale Lite5200 Eval Board"
-       depends on PPC_MULTIPLATFORM && PPC32
-       select PPC_MPC5200
-       default n
-
-config PPC_PMAC
-       bool "Apple PowerMac based machines"
-       depends on PPC_MULTIPLATFORM
-       select MPIC
-       select PPC_INDIRECT_PCI if PPC32
-       select PPC_MPC106 if PPC32
-       select PPC_NATIVE
-       default y
-
-config PPC_PMAC64
-       bool
-       depends on PPC_PMAC && POWER4
-       select MPIC
-       select U3_DART
-       select MPIC_BROKEN_U3
-       select GENERIC_TBSYNC
-       select PPC_970_NAP
-       default y
-
-config PPC_PREP
-       bool "PowerPC Reference Platform (PReP) based machines"
-       depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
-       select MPIC
-       select PPC_I8259
-       select PPC_INDIRECT_PCI
-       select PPC_UDBG_16550
-       select PPC_NATIVE
-       default n
-
-config PPC_MAPLE
-       depends on PPC_MULTIPLATFORM && PPC64
-       bool "Maple 970FX Evaluation Board"
-       select MPIC
-       select U3_DART
-       select MPIC_BROKEN_U3
-       select GENERIC_TBSYNC
-       select PPC_UDBG_16550
-       select PPC_970_NAP
-       select PPC_NATIVE
-       select PPC_RTAS
-       select MMIO_NVRAM
-       select ATA_NONSTANDARD if ATA
-       default n
-       help
-          This option enables support for the Maple 970FX Evaluation Board.
-         For more information, refer to <http://www.970eval.com>
-
-config PPC_PASEMI
-       depends on PPC_MULTIPLATFORM && PPC64
-       bool "PA Semi SoC-based platforms"
-       default n
-       select MPIC
-       select PPC_UDBG_16550
-       select GENERIC_TBSYNC
-       select PPC_NATIVE
-       help
-         This option enables support for PA Semi's PWRficient line
-         of SoC processors, including PA6T-1682M
-
-config PPC_CELL
-       bool
-       default n
-
-config PPC_CELL_NATIVE
-       bool
-       select PPC_CELL
-       select PPC_DCR_MMIO
-       select PPC_OF_PLATFORM_PCI
-       select PPC_INDIRECT_IO
-       select PPC_NATIVE
-       select MPIC
-       default n
-
-config PPC_IBM_CELL_BLADE
-       bool "IBM Cell Blade"
-       depends on PPC_MULTIPLATFORM && PPC64
-       select PPC_CELL_NATIVE
-       select PPC_RTAS
-       select MMIO_NVRAM
-       select PPC_UDBG_16550
-       select UDBG_RTAS_CONSOLE
-
-config PPC_PS3
-       bool "Sony PS3 (incomplete)"
-       depends on PPC_MULTIPLATFORM && PPC64
-       select PPC_CELL
-       select USB_ARCH_HAS_OHCI
-       select USB_OHCI_LITTLE_ENDIAN
-       select USB_OHCI_BIG_ENDIAN_MMIO
-       select USB_ARCH_HAS_EHCI
-       select USB_EHCI_BIG_ENDIAN_MMIO
-       help
-         This option enables support for the Sony PS3 game console
-         and other platforms using the PS3 hypervisor.
-         Support for this platform is not yet complete, so
-         enabling this will not result in a bootable kernel on a
-         PS3 system.
-
-config PPC_CELLEB
-       bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
-       depends on PPC_MULTIPLATFORM && PPC64
-       select PPC_CELL
-       select PPC_OF_PLATFORM_PCI
-       select HAS_TXX9_SERIAL
-       select PPC_UDBG_BEAT
-       select USB_OHCI_BIG_ENDIAN_MMIO
-       select USB_EHCI_BIG_ENDIAN_MMIO
-
-config PPC_NATIVE
-       bool
-       depends on PPC_MULTIPLATFORM
-       help
-         Support for running natively on the hardware, i.e. without
-         a hypervisor. This option is not user-selectable but should
-         be selected by all platforms that need it.
-
-config UDBG_RTAS_CONSOLE
-       bool "RTAS based debug console"
-       depends on PPC_RTAS
-       default n
-
-config PPC_UDBG_BEAT
-       bool "BEAT based debug console"
-       depends on PPC_CELLEB
-       default n
-
-config XICS
-       depends on PPC_PSERIES
-       bool
-       default y
-
-config U3_DART
-       bool 
-       depends on PPC_MULTIPLATFORM && PPC64
-       default n
-
-config PPC_RTAS
-       bool
-       default n
-
-config RTAS_ERROR_LOGGING
-       bool
-       depends on PPC_RTAS
-       default n
-
-config RTAS_PROC
-       bool "Proc interface to RTAS"
-       depends on PPC_RTAS
-       default y
-
-config RTAS_FLASH
-       tristate "Firmware flash interface"
-       depends on PPC64 && RTAS_PROC
-
-config PPC_PMI
-       tristate "Support for PMI"
-       depends PPC_IBM_CELL_BLADE
-       help
-         PMI (Platform Management Interrupt) is a way to
-         communicate with the BMC (Baseboard Mangement Controller).
-         It is used in some IBM Cell blades.
-       default m
-
-config MMIO_NVRAM
-       bool
-       default n
-
-config MPIC_BROKEN_U3
-       bool
-       depends on PPC_MAPLE
-       default y
-
-config IBMVIO
-       depends on PPC_PSERIES || PPC_ISERIES
-       bool
-       default y
-
-config IBMEBUS
-       depends on PPC_PSERIES
-       bool "Support for GX bus based adapters"
-       help
-         Bus device driver for GX bus based adapters.
-
-config PPC_MPC106
-       bool
-       default n
-
-config PPC_970_NAP
-       bool
-       default n
-
-config PPC_INDIRECT_IO
-       bool
-       select GENERIC_IOMAP
-       default n
-
-config GENERIC_IOMAP
-       bool
-       default n
-
-source "drivers/cpufreq/Kconfig"
-
-config CPU_FREQ_PMAC
-       bool "Support for Apple PowerBooks"
-       depends on CPU_FREQ && ADB_PMU && PPC32
-       select CPU_FREQ_TABLE
-       help
-         This adds support for frequency switching on Apple PowerBooks,
-         this currently includes some models of iBook & Titanium
-         PowerBook.
-
-config CPU_FREQ_PMAC64
-       bool "Support for some Apple G5s"
-       depends on CPU_FREQ && PPC64
-       select CPU_FREQ_TABLE
-       help
-         This adds support for frequency switching on Apple iMac G5,
-         and some of the more recent desktop G5 machines as well.
-
-config PPC601_SYNC_FIX
-       bool "Workarounds for PPC601 bugs"
-       depends on 6xx && (PPC_PREP || PPC_PMAC)
-       help
-         Some versions of the PPC601 (the first PowerPC chip) have bugs which
-         mean that extra synchronization instructions are required near
-         certain instructions, typically those that make major changes to the
-         CPU state.  These extra instructions reduce performance slightly.
-         If you say N here, these extra instructions will not be included,
-         resulting in a kernel which will run faster but may not run at all
-         on some systems with the PPC601 chip.
-
-         If in doubt, say Y here.
-
-config TAU
-       bool "On-chip CPU temperature sensor support"
-       depends on 6xx
-       help
-         G3 and G4 processors have an on-chip temperature sensor called the
-         'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
-         temperature within 2-4 degrees Celsius. This option shows the current
-         on-die temperature in /proc/cpuinfo if the cpu supports it.
-
-         Unfortunately, on some chip revisions, this sensor is very inaccurate
-         and in many cases, does not work at all, so don't assume the cpu
-         temp is actually what /proc/cpuinfo says it is.
-
-config TAU_INT
-       bool "Interrupt driven TAU driver (DANGEROUS)"
-       depends on TAU
-       ---help---
-         The TAU supports an interrupt driven mode which causes an interrupt
-         whenever the temperature goes out of range. This is the fastest way
-         to get notified the temp has exceeded a range. With this option off,
-         a timer is used to re-check the temperature periodically.
-
-         However, on some cpus it appears that the TAU interrupt hardware
-         is buggy and can cause a situation which would lead unexplained hard
-         lockups.
-
-         Unless you are extending the TAU driver, or enjoy kernel/hardware
-         debugging, leave this option off.
-
-config TAU_AVERAGE
-       bool "Average high and low temp"
-       depends on TAU
-       ---help---
-         The TAU hardware can compare the temperature to an upper and lower
-         bound.  The default behavior is to show both the upper and lower
-         bound in /proc/cpuinfo. If the range is large, the temperature is
-         either changing a lot, or the TAU hardware is broken (likely on some
-         G4's). If the range is small (around 4 degrees), the temperature is
-         relatively stable.  If you say Y here, a single temperature value,
-         halfway between the upper and lower bounds, will be reported in
-         /proc/cpuinfo.
-
-         If in doubt, say N here.
-
-endmenu
-
-source arch/powerpc/platforms/embedded6xx/Kconfig
-source arch/powerpc/platforms/4xx/Kconfig
-source arch/powerpc/platforms/82xx/Kconfig
-source arch/powerpc/platforms/83xx/Kconfig
-source arch/powerpc/platforms/85xx/Kconfig
-source arch/powerpc/platforms/86xx/Kconfig
-source arch/powerpc/platforms/8xx/Kconfig
-source arch/powerpc/platforms/cell/Kconfig
-source arch/powerpc/platforms/ps3/Kconfig
-source arch/powerpc/platforms/pasemi/Kconfig
+source "arch/powerpc/platforms/Kconfig"
 
 menu "Kernel options"
 
@@ -837,15 +457,6 @@ config CRASH_DUMP
 
          Don't change this unless you know what you are doing.
 
-config EMBEDDEDBOOT
-       bool
-       depends on 8xx || 8260
-       default y
-
-config PC_KEYBOARD
-       bool "PC PS/2 style Keyboard"
-       depends on 4xx || CPM2
-
 config PPCBUG_NVRAM
        bool "Enable reading PPCBUG NVRAM during boot" if PPLUS || LOPEC
        default y if PPC_PREP
@@ -859,8 +470,6 @@ config IRQ_ALL_CPUS
          CPU.  Generally saying Y is safe, although some problems have been
          reported with SMP Power Macintoshes with this option enabled.
 
-source "arch/powerpc/platforms/pseries/Kconfig"
-
 config NUMA
        bool "NUMA support"
        depends on PPC64
@@ -910,10 +519,10 @@ config PPC_64K_PAGES
        depends on PPC64
        help
          This option changes the kernel logical page size to 64k. On machines
-          without processor support for 64k pages, the kernel will simulate
-          them by loading each individual 4k page on demand transparently,
-          while on hardware with such support, it will be used to map
-          normal application pages.
+         without processor support for 64k pages, the kernel will simulate
+         them by loading each individual 4k page on demand transparently,
+         while on hardware with such support, it will be used to map
+         normal application pages.
 
 config SCHED_SMT
        bool "SMT (Hyperthreading) scheduler support"
@@ -931,8 +540,6 @@ config PROC_DEVICETREE
          an image of the device tree that the kernel copies from Open
          Firmware or other boot firmware. If unsure, say Y here.
 
-source "arch/powerpc/platforms/prep/Kconfig"
-
 config CMDLINE_BOOL
        bool "Default bootloader kernel arguments"
 
@@ -967,6 +574,29 @@ config SECCOMP
 
          If unsure, say Y. Only embedded should say N here.
 
+config WANT_DEVICE_TREE
+       bool
+       default n
+
+config DEVICE_TREE
+       string "Static device tree source file"
+       depends on WANT_DEVICE_TREE
+       help
+         This specifies the device tree source (.dts) file to be
+         compiled and included when building the bootwrapper.  If a
+         relative filename is given, then it will be relative to
+         arch/powerpc/boot/dts.  If you are not using the bootwrapper,
+         or do not need to build a dts into the bootwrapper, this
+         field is ignored.
+
+         For example, this is required when building a cuImage target
+         for an older U-Boot, which cannot pass a device tree itself.
+         Such a kernel will not work with a newer U-Boot that tries to
+         pass a device tree (unless you tell it not to).  If your U-Boot
+         does not mention a device tree in "help bootm", then use the
+         cuImage target and specify a device tree here.  Otherwise, use
+         the uImage target and leave this field blank.
+
 endmenu
 
 config ISA_DMA_API
@@ -995,24 +625,17 @@ config GENERIC_ISA_DMA
        depends on PPC64 || POWER4 || 6xx && !CPM2
        default y
 
-config MPIC
-       bool
-       default n
-
-config MPIC_WEIRD
-       bool
-       default n
-
-config PPC_I8259
-       bool
-       default n
-
 config PPC_INDIRECT_PCI
        bool
        depends on PCI
        default y if 40x || 44x
        default n
 
+config PPC_INDIRECT_PCI_BE
+       bool
+       depends PPC_INDIRECT_PCI
+       default n
+
 config EISA
        bool
 
@@ -1022,13 +645,18 @@ config SBUS
 config FSL_SOC
        bool
 
+config FSL_PCIE
+       bool
+       depends on PPC_86xx
+
 # Yes MCA RS/6000s exist but Linux-PPC does not currently support any
 config MCA
        bool
 
 config PCI
        bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
-               || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES) || MPC7448HPC2 || PPC_PS3
+               || PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
+               || MPC7448HPC2 || PPC_PS3
        default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx \
                && !PPC_85xx && !PPC_86xx
        default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
@@ -1228,12 +856,10 @@ source "fs/Kconfig"
 
 source "arch/powerpc/sysdev/qe_lib/Kconfig"
 
-source "arch/powerpc/platforms/iseries/Kconfig"
-
 source "lib/Kconfig"
 
 menu "Instrumentation Support"
-        depends on EXPERIMENTAL
+       depends on EXPERIMENTAL
 
 source "arch/powerpc/oprofile/Kconfig"
 
index d39d13327e6d928aee8370797827c342698446e8..86aa3745af7f65f1d1240bac863be9145eda91f2 100644 (file)
@@ -18,6 +18,15 @@ config DEBUG_STACK_USAGE
 
          This option will slow down process creation somewhat.
 
+config DEBUG_PAGEALLOC
+        bool "Debug page memory allocations"
+        depends on DEBUG_KERNEL && !SOFTWARE_SUSPEND
+        help
+          Unmap pages from the kernel linear mapping after free_pages().
+          This results in a large slowdown, but helps to find certain types
+          of memory corruptions.
+
+
 config HCALL_STATS
        bool "Hypervisor call instrumentation"
        depends on PPC_PSERIES && DEBUG_FS
@@ -132,8 +141,7 @@ config BOOTX_TEXT
 
 config SERIAL_TEXT_DEBUG
        bool "Support for early boot texts over serial port"
-       depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \
-               PPC_GEN550 || PPC_MPC52xx
+       depends on 4xx
 
 config PPC_EARLY_DEBUG
        bool "Early debugging (dangerous)"
index a00fe7236555676aa1abdabafc4f355456e335d3..794992025d8de94222fe26e5c90592d8f2a6a42e 100644 (file)
@@ -102,9 +102,9 @@ CFLAGS += $(call cc-option,-mno-altivec)
 # kernel considerably.
 CFLAGS += $(call cc-option,-funit-at-a-time)
 
-ifndef CONFIG_FSL_BOOKE
-CFLAGS         += -mstring
-endif
+# Never use string load/store instructions as they are
+# often slow when they are implemented at all
+CFLAGS         += -mno-string
 
 ifeq ($(CONFIG_6xx),y)
 CFLAGS         += -mcpu=powerpc
@@ -148,7 +148,7 @@ all: $(KBUILD_IMAGE)
 
 CPPFLAGS_vmlinux.lds   := -Upowerpc
 
-BOOT_TARGETS = zImage zImage.initrd uImage
+BOOT_TARGETS = zImage zImage.initrd uImage cuImage
 
 PHONY += $(BOOT_TARGETS)
 
@@ -166,6 +166,9 @@ define archhelp
   @echo '  *_defconfig     - Select default config from arch/$(ARCH)/configs'
 endef
 
+install:
+       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
+
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
 
index 0734b2fc1d957f4150dfeb341c30988d5d5abb2f..eec7af7e5993c8e8cf3c9d2f2a10d1122e5fa69c 100644 (file)
@@ -18,6 +18,9 @@ kernel-vmlinux.strip.c
 kernel-vmlinux.strip.gz
 mktree
 uImage
+cuImage
+cuImage.bin.gz
+cuImage.elf
 zImage
 zImage.chrp
 zImage.coff
index dc779407de14ab4927676c0c2f9842b92caeb0cf..3716594ea33eaec75ea10b40ac1372dffbbc05e6 100644 (file)
@@ -40,10 +40,11 @@ zliblinuxheader := zlib.h zconf.h zutil.h
 $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \
                $(addprefix $(obj)/,$(zlibheader))
 
-src-wlib := string.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
-               ns16550.c serial.c simple_alloc.c div64.S util.S $(zlib)
-src-plat := of.c
-src-boot := crt0.S $(src-wlib) $(src-plat) empty.c
+src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
+               ns16550.c serial.c simple_alloc.c div64.S util.S \
+               gunzip_util.c elf_util.c $(zlib) devtree.c
+src-plat := of.c cuboot-83xx.c cuboot-85xx.c
+src-boot := $(src-wlib) $(src-plat) empty.c
 
 src-boot := $(addprefix $(obj)/, $(src-boot))
 obj-boot := $(addsuffix .o, $(basename $(src-boot)))
@@ -75,7 +76,7 @@ $(obj)/zImage.lds $(obj)/zImage.coff.lds: $(obj)/%: $(srctree)/$(src)/%.S
        @cp $< $@
 
 clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \
-               empty.c zImage zImage.coff.lds zImage.lds zImage.sandpoint
+               empty.c zImage.coff.lds zImage.lds
 
 quiet_cmd_bootcc = BOOTCC  $@
       cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
@@ -84,23 +85,25 @@ quiet_cmd_bootas = BOOTAS  $@
       cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
 
 quiet_cmd_bootar = BOOTAR  $@
-      cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $^; mv $@.$$$$ $@
+      cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@
 
-$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
+$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c FORCE
        $(call if_changed_dep,bootcc)
-$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S
+$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S FORCE
        $(call if_changed_dep,bootas)
 
-$(obj)/wrapper.a: $(obj-wlib)
-       $(call cmd,bootar)
+$(obj)/wrapper.a: $(obj-wlib) FORCE
+       $(call if_changed,bootar)
 
 hostprogs-y    := addnote addRamDisk hack-coff mktree
 
-extra-y                := $(obj)/crt0.o $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
+targets                += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a)
+extra-y                := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
                   $(obj)/zImage.lds $(obj)/zImage.coff.lds
 
 wrapper                :=$(srctree)/$(src)/wrapper
-wrapperbits    := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree)
+wrapperbits    := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree) \
+                       $(wrapper) FORCE
 
 #############
 # Bits for building various flavours of zImage
@@ -113,50 +116,10 @@ CROSSWRAP := -C "$(CROSS_COMPILE)"
 endif
 endif
 
+# args (to if_changed): 1 = (this rule), 2 = platform, 3 = dts 4=dtb 5=initrd
 quiet_cmd_wrap = WRAP    $@
-      cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux
-quiet_cmd_wrap_initrd = WRAP    $@
-      cmd_wrap_initrd =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
-                               -i $(obj)/ramdisk.image.gz vmlinux
-
-$(obj)/zImage.chrp: vmlinux $(wrapperbits)
-       $(call cmd,wrap,chrp)
-
-$(obj)/zImage.initrd.chrp: vmlinux $(wrapperbits)
-       $(call cmd,wrap_initrd,chrp)
-
-$(obj)/zImage.pseries: vmlinux $(wrapperbits)
-       $(call cmd,wrap,pseries)
-
-$(obj)/zImage.initrd.pseries: vmlinux $(wrapperbits)
-       $(call cmd,wrap_initrd,pseries)
-
-$(obj)/zImage.pmac: vmlinux $(wrapperbits)
-       $(call cmd,wrap,pmac)
-
-$(obj)/zImage.initrd.pmac: vmlinux $(wrapperbits)
-       $(call cmd,wrap_initrd,pmac)
-
-$(obj)/zImage.coff: vmlinux $(wrapperbits)
-       $(call cmd,wrap,pmaccoff)
-
-$(obj)/zImage.initrd.coff: vmlinux $(wrapperbits)
-       $(call cmd,wrap_initrd,pmaccoff)
-
-$(obj)/zImage.miboot: vmlinux $(wrapperbits)
-       $(call cmd,wrap,miboot)
-
-$(obj)/zImage.initrd.miboot: vmlinux $(wrapperbits)
-       $(call cmd,wrap_initrd,miboot)
-
-$(obj)/zImage.ps3: vmlinux
-       $(STRIP) -s -R .comment $< -o $@
-
-$(obj)/zImage.initrd.ps3: vmlinux
-       @echo "  WARNING zImage.initrd.ps3 not supported (yet)"
-
-$(obj)/uImage: vmlinux $(wrapperbits)
-       $(call cmd,wrap,uboot)
+      cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
+               $(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) vmlinux
 
 image-$(CONFIG_PPC_PSERIES)            += zImage.pseries
 image-$(CONFIG_PPC_MAPLE)              += zImage.pseries
@@ -166,7 +129,7 @@ image-$(CONFIG_PPC_CELLEB)          += zImage.pseries
 image-$(CONFIG_PPC_CHRP)               += zImage.chrp
 image-$(CONFIG_PPC_EFIKA)              += zImage.chrp
 image-$(CONFIG_PPC_PMAC)               += zImage.pmac
-image-$(CONFIG_DEFAULT_UIMAGE)         += uImage
+image-$(CONFIG_DEFAULT_UIMAGE)         += uImage cuImage
 
 # For 32-bit powermacs, build the COFF and miboot images
 # as well as the ELF images.
@@ -174,16 +137,55 @@ ifeq ($(CONFIG_PPC32),y)
 image-$(CONFIG_PPC_PMAC)       += zImage.coff zImage.miboot
 endif
 
+initrd-  := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-))
 initrd-y := $(patsubst zImage%, zImage.initrd%, $(image-y))
+initrd-y := $(filter-out $(image-y), $(initrd-y))
+targets        += $(image-y) $(initrd-y)
+
+$(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz
+
+# Don't put the ramdisk on the pattern rule; when its missing make will try
+# the pattern rule with less dependencies that also matches (even with the
+# hard dependency listed).
+$(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
+       $(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
+
+$(obj)/zImage.%: vmlinux $(wrapperbits)
+       $(call if_changed,wrap,$*)
+
+$(obj)/zImage.ps3: vmlinux
+       $(STRIP) -s -R .comment $< -o $@
+
+$(obj)/zImage.initrd.ps3: vmlinux
+       @echo "  WARNING zImage.initrd.ps3 not supported (yet)"
+
+$(obj)/uImage: vmlinux $(wrapperbits)
+       $(call if_changed,wrap,uboot)
+
+cuboot-plat-$(CONFIG_83xx) += 83xx
+cuboot-plat-$(CONFIG_85xx) += 85xx
+cuboot-plat-y += unknown-platform
+
+dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\
+       ,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE)
+
+$(obj)/cuImage: vmlinux $(wrapperbits)
+       $(call if_changed,wrap,cuboot-$(word 1,$(cuboot-plat-y)),$(dts))
 
 $(obj)/zImage:         $(addprefix $(obj)/, $(image-y))
        @rm -f $@; ln $< $@
 $(obj)/zImage.initrd:  $(addprefix $(obj)/, $(initrd-y))
        @rm -f $@; ln $< $@
 
-install: $(CONFIGURE) $(image-y)
+install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y))
        sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" $<
 
-clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip.gz)
-clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.bin.gz)
-clean-files += $(image-)
+# anything not in $(targets)
+clean-files += $(image-) $(initrd-) zImage zImage.initrd \
+               cuImage.elf cuImage.bin.gz
+
+# clean up files cached by wrapper
+clean-kernel := vmlinux.strip vmlinux.bin
+clean-kernel += $(addsuffix .gz,$(clean-kernel))
+# If not absolute clean-files are relative to $(obj).
+clean-files += $(addprefix $(objtree)/, $(clean-kernel))
index 70e65b13e0336fd86c02f3c602181be94c3ae3e0..5a4215c4b0146aa063fe87c5bb503a398232f6d3 100644 (file)
 _zimage_start_opd:
        .long   _zimage_start, 0, 0, 0
 
+       .weak   _zimage_start
        .globl  _zimage_start
 _zimage_start:
+       .globl  _zimage_start_lib
+_zimage_start_lib:
        /* Work out the offset between the address we were linked at
           and the address where we're running. */
        bl      1f
@@ -44,7 +47,7 @@ _zimage_start:
        addi    r9,r9,4
        bdnz    2b
 
-       /* Do a cache flush for our text, in case OF didn't */
+       /* Do a cache flush for our text, in case the loader didn't */
 3:     lis     r9,_start@ha
        addi    r9,r9,_start@l
        add     r9,r0,r9
@@ -59,6 +62,34 @@ _zimage_start:
        sync
        isync
 
-       mr      r6,r1
-       b       start
+       /* Clear the BSS */
+       lis     r9,__bss_start@ha
+       addi    r9,r9,__bss_start@l
+       add     r9,r0,r9
+       lis     r8,_end@ha
+       addi    r8,r8,_end@l
+       add     r8,r0,r8
+       li      r10,0
+5:     stw     r10,0(r9)
+       addi    r9,r9,4
+       cmplw   cr0,r9,r8
+       blt     5b
 
+       /* Possibly set up a custom stack */
+.weak  _platform_stack_top
+       lis     r8,_platform_stack_top@ha
+       addi    r8,r8,_platform_stack_top@l
+       cmpwi   r8,0
+       beq     6f
+       add     r8,r0,r8
+       lwz     r1,0(r8)
+       add     r1,r0,r1
+       li      r0,0
+       stwu    r0,-16(r1)      /* establish a stack frame */
+6:
+
+       /* Call platform_init() */
+       bl      platform_init
+
+       /* Call start */
+       b       start
diff --git a/arch/powerpc/boot/cuboot-83xx.c b/arch/powerpc/boot/cuboot-83xx.c
new file mode 100644 (file)
index 0000000..6cbc20a
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Old U-boot compatibility for 83xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+
+#define TARGET_83xx
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+extern char _dtb_start[], _dtb_end[];
+
+static void platform_fixups(void)
+{
+       void *soc;
+
+       dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+       dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr);
+       dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq);
+
+       /* Unfortunately, the specific model number is encoded in the
+        * soc node name in existing dts files -- once that is fixed,
+        * this can do a simple path lookup.
+        */
+       soc = find_node_by_devtype(NULL, "soc");
+       if (soc) {
+               void *serial = NULL;
+
+               setprop(soc, "bus-frequency", &bd.bi_busfreq,
+                       sizeof(bd.bi_busfreq));
+
+               while ((serial = find_node_by_devtype(serial, "serial"))) {
+                       if (get_parent(serial) != soc)
+                               continue;
+
+                       setprop(serial, "clock-frequency", &bd.bi_busfreq,
+                               sizeof(bd.bi_busfreq));
+               }
+       }
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                   unsigned long r6, unsigned long r7)
+{
+       unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+       unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+       memcpy(&bd, (bd_t *)r3, sizeof(bd));
+       loader_info.initrd_addr = r4;
+       loader_info.initrd_size = r4 ? r5 : 0;
+       loader_info.cmdline = (char *)r6;
+       loader_info.cmdline_len = r7 - r6;
+
+       simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+       ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+       serial_console_init();
+       platform_ops.fixups = platform_fixups;
+}
diff --git a/arch/powerpc/boot/cuboot-85xx.c b/arch/powerpc/boot/cuboot-85xx.c
new file mode 100644 (file)
index 0000000..f88ba00
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Old U-boot compatibility for 85xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+
+#define TARGET_85xx
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+extern char _dtb_start[], _dtb_end[];
+
+static void platform_fixups(void)
+{
+       void *soc;
+
+       dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+       dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr,
+                              bd.bi_enet2addr);
+       dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 8, bd.bi_busfreq);
+
+       /* Unfortunately, the specific model number is encoded in the
+        * soc node name in existing dts files -- once that is fixed,
+        * this can do a simple path lookup.
+        */
+       soc = find_node_by_devtype(NULL, "soc");
+       if (soc) {
+               void *serial = NULL;
+
+               setprop(soc, "bus-frequency", &bd.bi_busfreq,
+                       sizeof(bd.bi_busfreq));
+
+               while ((serial = find_node_by_devtype(serial, "serial"))) {
+                       if (get_parent(serial) != soc)
+                               continue;
+
+                       setprop(serial, "clock-frequency", &bd.bi_busfreq,
+                               sizeof(bd.bi_busfreq));
+               }
+       }
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                   unsigned long r6, unsigned long r7)
+{
+       unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+       unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+       memcpy(&bd, (bd_t *)r3, sizeof(bd));
+       loader_info.initrd_addr = r4;
+       loader_info.initrd_size = r4 ? r5 : 0;
+       loader_info.cmdline = (char *)r6;
+       loader_info.cmdline_len = r7 - r6;
+
+       simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+       ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+       serial_console_init();
+       platform_ops.fixups = platform_fixups;
+}
diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c
new file mode 100644 (file)
index 0000000..c995155
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * devtree.c - convenience functions for device tree manipulation
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * Authors: David Gibson <david@gibson.dropbear.id.au>
+ *         Scott Wood <scottwood@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+
+void dt_fixup_memory(u64 start, u64 size)
+{
+       void *root, *memory;
+       int naddr, nsize, i;
+       u32 memreg[4];
+
+       root = finddevice("/");
+       if (getprop(root, "#address-cells", &naddr, sizeof(naddr)) < 0)
+               naddr = 2;
+       if (naddr < 1 || naddr > 2)
+               fatal("Can't cope with #address-cells == %d in /\n\r", naddr);
+
+       if (getprop(root, "#size-cells", &nsize, sizeof(nsize)) < 0)
+               nsize = 1;
+       if (nsize < 1 || nsize > 2)
+               fatal("Can't cope with #size-cells == %d in /\n\r", nsize);
+
+       i = 0;
+       if (naddr == 2)
+               memreg[i++] = start >> 32;
+       memreg[i++] = start & 0xffffffff;
+       if (nsize == 2)
+               memreg[i++] = size >> 32;
+       memreg[i++] = size & 0xffffffff;
+
+       memory = finddevice("/memory");
+       if (! memory) {
+               memory = create_node(NULL, "memory");
+               setprop_str(memory, "device_type", "memory");
+       }
+
+       printf("Memory <- <0x%x", memreg[0]);
+       for (i = 1; i < (naddr + nsize); i++)
+               printf(" 0x%x", memreg[i]);
+       printf("> (%ldMB)\n\r", (unsigned long)(size >> 20));
+
+       setprop(memory, "reg", memreg, (naddr + nsize)*sizeof(u32));
+}
+
+#define MHZ(x) ((x + 500000) / 1000000)
+
+void dt_fixup_cpu_clocks(u32 cpu, u32 tb, u32 bus)
+{
+       void *devp = NULL;
+
+       printf("CPU clock-frequency <- 0x%x (%dMHz)\n\r", cpu, MHZ(cpu));
+       printf("CPU timebase-frequency <- 0x%x (%dMHz)\n\r", tb, MHZ(tb));
+       if (bus > 0)
+               printf("CPU bus-frequency <- 0x%x (%dMHz)\n\r", bus, MHZ(bus));
+
+       while ((devp = find_node_by_devtype(devp, "cpu"))) {
+               setprop_val(devp, "clock-frequency", cpu);
+               setprop_val(devp, "timebase-frequency", tb);
+               if (bus > 0)
+                       setprop_val(devp, "bus-frequency", bus);
+       }
+}
+
+void dt_fixup_clock(const char *path, u32 freq)
+{
+       void *devp = finddevice(path);
+
+       if (devp) {
+               printf("%s: clock-frequency <- %x (%dMHz)\n\r", path, freq, MHZ(freq));
+               setprop_val(devp, "clock-frequency", freq);
+       }
+}
+
+void __dt_fixup_mac_addresses(u32 startindex, ...)
+{
+       va_list ap;
+       u32 index = startindex;
+       void *devp;
+       const u8 *addr;
+
+       va_start(ap, startindex);
+       while ((addr = va_arg(ap, const u8 *))) {
+               devp = find_node_by_prop_value(NULL, "linux,network-index",
+                                              (void*)&index, sizeof(index));
+
+               printf("ENET%d: local-mac-address <-"
+                      " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index,
+                      addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+               if (devp)
+                       setprop(devp, "local-mac-address", addr, 6);
+
+               index++;
+       }
+       va_end(ap);
+}
+
+#define MAX_ADDR_CELLS 4
+#define MAX_RANGES 8
+
+static void get_reg_format(void *node, u32 *naddr, u32 *nsize)
+{
+       if (getprop(node, "#address-cells", naddr, 4) != 4)
+               *naddr = 2;
+       if (getprop(node, "#size-cells", nsize, 4) != 4)
+               *nsize = 1;
+}
+
+static void copy_val(u32 *dest, u32 *src, int naddr)
+{
+       int pad = MAX_ADDR_CELLS - naddr;
+
+       memset(dest, 0, pad * 4);
+       memcpy(dest + pad, src, naddr * 4);
+}
+
+static int sub_reg(u32 *reg, u32 *sub)
+{
+       int i, borrow = 0;
+
+       for (i = MAX_ADDR_CELLS - 1; i >= 0; i--) {
+               int prev_borrow = borrow;
+               borrow = reg[i] < sub[i] + prev_borrow;
+               reg[i] -= sub[i] + prev_borrow;
+       }
+
+       return !borrow;
+}
+
+static int add_reg(u32 *reg, u32 *add, int naddr)
+{
+       int i, carry = 0;
+
+       for (i = MAX_ADDR_CELLS - 1; i >= MAX_ADDR_CELLS - naddr; i--) {
+               u64 tmp = (u64)reg[i] + add[i] + carry;
+               carry = tmp >> 32;
+               reg[i] = (u32)tmp;
+       }
+
+       return !carry;
+}
+
+/* It is assumed that if the first byte of reg fits in a
+ * range, then the whole reg block fits.
+ */
+static int compare_reg(u32 *reg, u32 *range, u32 *rangesize)
+{
+       int i;
+       u32 end;
+
+       for (i = 0; i < MAX_ADDR_CELLS; i++) {
+               if (reg[i] < range[i])
+                       return 0;
+               if (reg[i] > range[i])
+                       break;
+       }
+
+       for (i = 0; i < MAX_ADDR_CELLS; i++) {
+               end = range[i] + rangesize[i];
+
+               if (reg[i] < end)
+                       break;
+               if (reg[i] > end)
+                       return 0;
+       }
+
+       return reg[i] != end;
+}
+
+/* reg must be MAX_ADDR_CELLS */
+static int find_range(u32 *reg, u32 *ranges, int nregaddr,
+                      int naddr, int nsize, int buflen)
+{
+       int nrange = nregaddr + naddr + nsize;
+       int i;
+
+       for (i = 0; i + nrange <= buflen; i += nrange) {
+               u32 range_addr[MAX_ADDR_CELLS];
+               u32 range_size[MAX_ADDR_CELLS];
+
+               copy_val(range_addr, ranges + i, naddr);
+               copy_val(range_size, ranges + i + nregaddr + naddr, nsize);
+
+               if (compare_reg(reg, range_addr, range_size))
+                       return i;
+       }
+
+       return -1;
+}
+
+/* Currently only generic buses without special encodings are supported.
+ * In particular, PCI is not supported.  Also, only the beginning of the
+ * reg block is tracked; size is ignored except in ranges.
+ */
+static u32 dt_xlate_buf[MAX_ADDR_CELLS * MAX_RANGES * 3];
+
+static int dt_xlate(void *node, int res, int reglen, unsigned long *addr,
+               unsigned long *size)
+{
+       u32 last_addr[MAX_ADDR_CELLS];
+       u32 this_addr[MAX_ADDR_CELLS];
+       void *parent;
+       u64 ret_addr, ret_size;
+       u32 naddr, nsize, prev_naddr;
+       int buflen, offset;
+
+       parent = get_parent(node);
+       if (!parent)
+               return 0;
+
+       get_reg_format(parent, &naddr, &nsize);
+
+       if (nsize > 2)
+               return 0;
+
+       offset = (naddr + nsize) * res;
+
+       if (reglen < offset + naddr + nsize ||
+           sizeof(dt_xlate_buf) < offset + naddr + nsize)
+               return 0;
+
+       copy_val(last_addr, dt_xlate_buf + offset, naddr);
+
+       ret_size = dt_xlate_buf[offset + naddr];
+       if (nsize == 2) {
+               ret_size <<= 32;
+               ret_size |= dt_xlate_buf[offset + naddr + 1];
+       }
+
+       while ((node = get_parent(node))) {
+               prev_naddr = naddr;
+
+               get_reg_format(node, &naddr, &nsize);
+
+               buflen = getprop(node, "ranges", dt_xlate_buf,
+                               sizeof(dt_xlate_buf));
+               if (buflen < 0)
+                       continue;
+               if (buflen > sizeof(dt_xlate_buf))
+                       return 0;
+
+               offset = find_range(last_addr, dt_xlate_buf, prev_naddr,
+                                   naddr, nsize, buflen / 4);
+
+               if (offset < 0)
+                       return 0;
+
+               copy_val(this_addr, dt_xlate_buf + offset, prev_naddr);
+
+               if (!sub_reg(last_addr, this_addr))
+                       return 0;
+
+               copy_val(this_addr, dt_xlate_buf + offset + prev_naddr, naddr);
+
+               if (!add_reg(last_addr, this_addr, naddr))
+                       return 0;
+       }
+
+       if (naddr > 2)
+               return 0;
+
+       ret_addr = ((u64)last_addr[2] << 32) | last_addr[3];
+
+       if (sizeof(void *) == 4 &&
+           (ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL ||
+            ret_addr + ret_size > 0x100000000ULL))
+               return 0;
+
+       *addr = ret_addr;
+       if (size)
+               *size = ret_size;
+
+       return 1;
+}
+
+int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size)
+{
+       int reglen;
+
+       reglen = getprop(node, "reg", dt_xlate_buf, sizeof(dt_xlate_buf)) / 4;
+       return dt_xlate(node, res, reglen, addr, size);
+}
+
+int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr)
+{
+
+       if (buflen > sizeof(dt_xlate_buf))
+               return 0;
+
+       memcpy(dt_xlate_buf, buf, buflen);
+       return dt_xlate(node, 0, buflen / 4, xlated_addr, NULL);
+}
index b89791802e86efcc422c97ba9c71954d022312b0..157dc98d3988bd3c6efb92d995c35ba13d33cc01 100644 (file)
@@ -29,7 +29,6 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts"
 
        cpus {
                linux,phandle = <2000>;
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
@@ -126,17 +125,17 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts"
                        interrupt-parent = <4400>;
                        interrupt-map-mask = <f800 0 0 7>;
                        interrupt-map = <
-                               /* IDSEL 0x11 - IRQ0 ETH */
+                               /* IDSEL 11 - IRQ0 ETH */
                                5800 0 0 1 4400 0 1
                                5800 0 0 2 4400 1 1
                                5800 0 0 3 4400 2 1
                                5800 0 0 4 4400 3 1
-                               /* IDSEL 0x12 - IRQ1 IDE0 */
+                               /* IDSEL 12 - IRQ1 IDE0 */
                                6000 0 0 1 4400 1 1
                                6000 0 0 2 4400 2 1
                                6000 0 0 3 4400 3 1
                                6000 0 0 4 4400 0 1
-                               /* IDSEL 0x14 - IRQ3 USB2.0 */
+                               /* IDSEL 14 - IRQ3 USB2.0 */
                                7000 0 0 1 4400 3 1
                                7000 0 0 2 4400 3 1
                                7000 0 0 3 4400 3 1
index 753102752d8babb0d83142b93681b1053b26f047..919eb29097dba60aed4c731dd8c92da781e28703 100644 (file)
@@ -29,7 +29,6 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts"
 
        cpus {
                linux,phandle = <2000>;
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
@@ -126,17 +125,17 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts"
                        interrupt-parent = <4400>;
                        interrupt-map-mask = <f800 0 0 7>;
                        interrupt-map = <
-                               /* IDSEL 0x11 - IRQ0 ETH */
+                               /* IDSEL 11 - IRQ0 ETH */
                                5800 0 0 1 4400 0 1
                                5800 0 0 2 4400 1 1
                                5800 0 0 3 4400 2 1
                                5800 0 0 4 4400 3 1
-                               /* IDSEL 0x12 - IRQ1 IDE0 */
+                               /* IDSEL 12 - IRQ1 IDE0 */
                                6000 0 0 1 4400 1 1
                                6000 0 0 2 4400 2 1
                                6000 0 0 3 4400 3 1
                                6000 0 0 4 4400 0 1
-                               /* IDSEL 0x14 - IRQ3 USB2.0 */
+                               /* IDSEL 14 - IRQ3 USB2.0 */
                                7000 0 0 1 4400 3 1
                                7000 0 0 2 4400 3 1
                                7000 0 0 3 4400 3 1
index c03103c632855877dd2c7d088dfd6d509a3ea540..ba54c6b40a09dfe613fee0be2333aa3b2b7501da 100644 (file)
@@ -24,7 +24,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index 3875ca9a9a624550b457188e3dd53602e86c35d4..2e003081b0d3be1c37469933ef22b627afb92e11 100644 (file)
@@ -24,7 +24,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index 41d0720c5900a2d27eba79f37650ab0b863fba2a..6fa3754f293a96ac500da979d2f049b606da8afd 100644 (file)
@@ -19,7 +19,6 @@
        linux,phandle = <100>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells =<0>;
                linux,phandle = <200>;
index 260b2e447779f5c672ed686dac183416b8864529..423eedcf634f6be2e07ab64c108dceb935678803 100644 (file)
@@ -17,7 +17,6 @@
        linux,phandle = <100>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
                linux,phandle = <200>;
index 6d721900d00e702d3d4b4b1e5f7709f74227fd51..a1533cc07d097dbb65915d5757a67035759e2b9d 100644 (file)
@@ -16,7 +16,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index 06b310698a024e95e759302c9f9a79be24ef1add..c798491f4cd0396f10102b96a1bc62614f8411e3 100644 (file)
@@ -16,7 +16,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
new file mode 100644 (file)
index 0000000..b55bced
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * MPC832x RDB Device Tree Source
+ *
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/ {
+       model = "MPC8323ERDB";
+       compatible = "MPC8323ERDB", "MPC832xRDB", "MPC83xxRDB";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8323@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <20>;       // 32 bytes
+                       i-cache-line-size = <20>;       // 32 bytes
+                       d-cache-size = <4000>;          // L1, 16K
+                       i-cache-size = <4000>;          // L1, 16K
+                       timebase-frequency = <0>;
+                       bus-frequency = <0>;
+                       clock-frequency = <0>;
+                       32-bit;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <00000000 04000000>;
+       };
+
+       soc8323@e0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               #interrupt-cells = <2>;
+               device_type = "soc";
+               ranges = <0 e0000000 00100000>;
+               reg = <e0000000 00000200>;
+               bus-frequency = <0>;
+
+               wdt@200 {
+                       device_type = "watchdog";
+                       compatible = "mpc83xx_wdt";
+                       reg = <200 100>;
+               };
+
+               i2c@3000 {
+                       device_type = "i2c";
+                       compatible = "fsl-i2c";
+                       reg = <3000 100>;
+                       interrupts = <e 8>;
+                       interrupt-parent = <&pic>;
+                       dfsrr;
+               };
+
+               serial@4500 {
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <4500 100>;
+                       clock-frequency = <0>;
+                       interrupts = <9 8>;
+                       interrupt-parent = <&pic>;
+               };
+
+               serial@4600 {
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <4600 100>;
+                       clock-frequency = <0>;
+                       interrupts = <a 8>;
+                       interrupt-parent = <&pic>;
+               };
+
+               crypto@30000 {
+                       device_type = "crypto";
+                       model = "SEC2";
+                       compatible = "talitos";
+                       reg = <30000 7000>;
+                       interrupts = <b 8>;
+                       interrupt-parent = <&pic>;
+                       /* Rev. 2.2 */
+                       num-channels = <1>;
+                       channel-fifo-len = <18>;
+                       exec-units-mask = <0000004c>;
+                       descriptor-types-mask = <0122003f>;
+               };
+
+               pci@8500 {
+                       interrupt-map-mask = <f800 0 0 7>;
+                       interrupt-map = <
+                                       /* IDSEL 0x10 AD16 (USB) */
+                                        8000 0 0 1 &pic 11 8
+
+                                       /* IDSEL 0x11 AD17 (Mini1)*/
+                                        8800 0 0 1 &pic 12 8
+                                        8800 0 0 2 &pic 13 8
+                                        8800 0 0 3 &pic 14 8
+                                        8800 0 0 4 &pic 30 8
+
+                                       /* IDSEL 0x12 AD18 (PCI/Mini2) */
+                                        9000 0 0 1 &pic 13 8
+                                        9000 0 0 2 &pic 14 8
+                                        9000 0 0 3 &pic 30 8
+                                        9000 0 0 4 &pic 11 8>;
+
+                       interrupt-parent = <&pic>;
+                       interrupts = <42 8>;
+                       bus-range = <0 0>;
+                       ranges = <42000000 0 80000000 80000000 0 10000000
+                                 02000000 0 90000000 90000000 0 10000000
+                                 01000000 0 d0000000 d0000000 0 04000000>;
+                       clock-frequency = <0>;
+                       #interrupt-cells = <1>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       reg = <8500 100>;
+                       compatible = "83xx";
+                       device_type = "pci";
+               };
+
+               pic:pic@700 {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <700 100>;
+                       built-in;
+                       device_type = "ipic";
+               };
+
+               par_io@1400 {
+                       reg = <1400 100>;
+                       device_type = "par_io";
+                       num-ports = <7>;
+
+                       ucc2pio:ucc_pin@02 {
+                               pio-map = <
+                       /* port  pin  dir  open_drain  assignment  has_irq */
+                                       3  4  3  0  2  0        /* MDIO */
+                                       3  5  1  0  2  0        /* MDC */
+                                       3 15  2  0  1  0        /* RX_CLK (CLK16) */
+                                       3 17  2  0  1  0        /* TX_CLK (CLK3) */
+                                       0 12  1  0  1  0        /* TxD0 */
+                                       0 13  1  0  1  0        /* TxD1 */
+                                       0 14  1  0  1  0        /* TxD2 */
+                                       0 15  1  0  1  0        /* TxD3 */
+                                       0 16  2  0  1  0        /* RxD0 */
+                                       0 17  2  0  1  0        /* RxD1 */
+                                       0 18  2  0  1  0        /* RxD2 */
+                                       0 19  2  0  1  0        /* RxD3 */
+                                       0 1a  2  0  1  0        /* RX_ER */
+                                       0 1b  1  0  1  0        /* TX_ER */
+                                       0 1c  2  0  1  0        /* RX_DV */
+                                       0 1d  2  0  1  0        /* COL */
+                                       0 1e  1  0  1  0        /* TX_EN */
+                                       0 1f  2  0  1  0>;      /* CRS */
+                       };
+                       ucc3pio:ucc_pin@03 {
+                               pio-map = <
+                       /* port  pin  dir  open_drain  assignment  has_irq */
+                                       0  d  2  0  1  0        /* RX_CLK (CLK9) */
+                                       3 18  2  0  1  0        /* TX_CLK (CLK10) */
+                                       1  0  1  0  1  0        /* TxD0 */
+                                       1  1  1  0  1  0        /* TxD1 */
+                                       1  2  1  0  1  0        /* TxD2 */
+                                       1  3  1  0  1  0        /* TxD3 */
+                                       1  4  2  0  1  0        /* RxD0 */
+                                       1  5  2  0  1  0        /* RxD1 */
+                                       1  6  2  0  1  0        /* RxD2 */
+                                       1  7  2  0  1  0        /* RxD3 */
+                                       1  8  2  0  1  0        /* RX_ER */
+                                       1  9  1  0  1  0        /* TX_ER */
+                                       1  a  2  0  1  0        /* RX_DV */
+                                       1  b  2  0  1  0        /* COL */
+                                       1  c  1  0  1  0        /* TX_EN */
+                                       1  d  2  0  1  0>;      /* CRS */
+                       };
+               };
+       };
+
+       qe@e0100000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               device_type = "qe";
+               model = "QE";
+               ranges = <0 e0100000 00100000>;
+               reg = <e0100000 480>;
+               brg-frequency = <0>;
+               bus-frequency = <BCD3D80>;
+
+               muram@10000 {
+                       device_type = "muram";
+                       ranges = <0 00010000 00004000>;
+
+                       data-only@0 {
+                               reg = <0 4000>;
+                       };
+               };
+
+               spi@4c0 {
+                       device_type = "spi";
+                       compatible = "fsl_spi";
+                       reg = <4c0 40>;
+                       interrupts = <2>;
+                       interrupt-parent = <&qeic>;
+                       mode = "cpu";
+               };
+
+               spi@500 {
+                       device_type = "spi";
+                       compatible = "fsl_spi";
+                       reg = <500 40>;
+                       interrupts = <1>;
+                       interrupt-parent = <&qeic>;
+                       mode = "cpu";
+               };
+
+               ucc@3000 {
+                       device_type = "network";
+                       compatible = "ucc_geth";
+                       model = "UCC";
+                       device-id = <2>;
+                       reg = <3000 200>;
+                       interrupts = <21>;
+                       interrupt-parent = <&qeic>;
+                       mac-address = [ 00 04 9f ef 03 02 ];
+                       rx-clock = <20>;
+                       tx-clock = <13>;
+                       phy-handle = <&phy00>;
+                       pio-handle = <&ucc2pio>;
+               };
+
+               ucc@2200 {
+                       device_type = "network";
+                       compatible = "ucc_geth";
+                       model = "UCC";
+                       device-id = <3>;
+                       reg = <2200 200>;
+                       interrupts = <22>;
+                       interrupt-parent = <&qeic>;
+                       mac-address = [ 00 04 9f ef 03 01 ];
+                       rx-clock = <19>;
+                       tx-clock = <1a>;
+                       phy-handle = <&phy04>;
+                       pio-handle = <&ucc3pio>;
+               };
+
+               mdio@3120 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <3120 18>;
+                       device_type = "mdio";
+                       compatible = "ucc_geth_phy";
+
+                       phy00:ethernet-phy@00 {
+                               interrupt-parent = <&pic>;
+                               interrupts = <0>;
+                               reg = <0>;
+                               device_type = "ethernet-phy";
+                               interface = <3>; //ENET_100_MII
+                       };
+                       phy04:ethernet-phy@04 {
+                               interrupt-parent = <&pic>;
+                               interrupts = <0>;
+                               reg = <4>;
+                               device_type = "ethernet-phy";
+                               interface = <3>;
+                       };
+               };
+
+               qeic:qeic@80 {
+                       interrupt-controller;
+                       device_type = "qeic";
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+                       reg = <80 80>;
+                       built-in;
+                       big-endian;
+                       interrupts = <20 8 21 8>; //high:32 low:33
+                       interrupt-parent = <&pic>;
+               };
+       };
+};
index 61b550bf1645df06b9425167b3132d6571db2d7a..db0d003032759d5f4df388377dc1d57bf682f45f 100644 (file)
@@ -15,7 +15,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index b2e1a5ec3779b60959b5cf6ef2961400f3173a1e..f636528a3c72f0077570899d308906ad90c52ea9 100644 (file)
@@ -15,7 +15,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index e4b43c24bc0bb54750c6ec9bd2fa864702e000e5..07bcc5194d2babd0d9f24e312986fc634af43c4c 100644 (file)
@@ -16,7 +16,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index 4fe45c02184898f9dde59a8f94e5077cab5e8974..7f578eb5708280d0159ae62c9807861a530a61a7 100644 (file)
@@ -21,7 +21,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index 3c0917fa791cff3f512350db29ccf06dac022309..f261d647ac856ac2dd25ee935ec934d1faddb530 100644 (file)
@@ -17,7 +17,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index 2a1ae760ab3a9fa349015deb31f2a06cb45b8b2c..5fdcb69554f28551b33711b2c1794fd762c45963 100644 (file)
@@ -17,7 +17,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts
new file mode 100644 (file)
index 0000000..6b08460
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * MPC8544 DS Device Tree Source
+ *
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/ {
+       model = "MPC8544DS";
+       compatible = "MPC8544DS", "MPC85xxDS";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #cpus = <1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8544@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <20>;       // 32 bytes
+                       i-cache-line-size = <20>;       // 32 bytes
+                       d-cache-size = <8000>;          // L1, 32K
+                       i-cache-size = <8000>;          // L1, 32K
+                       timebase-frequency = <0>;
+                       bus-frequency = <0>;
+                       clock-frequency = <0>;
+                       32-bit;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <00000000 00000000>;      // Filled by U-Boot
+       };
+
+       soc8544@e0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               #interrupt-cells = <2>;
+               device_type = "soc";
+               ranges = <0 e0000000 00100000>;
+               reg = <e0000000 00100000>;      // CCSRBAR 1M
+               bus-frequency = <0>;            // Filled out by uboot.
+
+               i2c@3000 {
+                       device_type = "i2c";
+                       compatible = "fsl-i2c";
+                       reg = <3000 100>;
+                       interrupts = <1b 2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+               };
+
+               mdio@24520 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       device_type = "mdio";
+                       compatible = "gianfar";
+                       reg = <24520 20>;
+                       phy0: ethernet-phy@0 {
+                               interrupt-parent = <&mpic>;
+                               interrupts = <3a 1>;
+                               reg = <0>;
+                               device_type = "ethernet-phy";
+                       };
+                       phy1: ethernet-phy@1 {
+                               interrupt-parent = <&mpic>;
+                               interrupts = <3a 1>;
+                               reg = <1>;
+                               device_type = "ethernet-phy";
+                       };
+               };
+
+               ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       device_type = "network";
+                       model = "TSEC";
+                       compatible = "gianfar";
+                       reg = <24000 1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <d 2 e 2 12 2>;
+                       interrupt-parent = <&mpic>;
+                       phy-handle = <&phy0>;
+               };
+
+               ethernet@26000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       device_type = "network";
+                       model = "TSEC";
+                       compatible = "gianfar";
+                       reg = <26000 1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <f 2 10 2 11 2>;
+                       interrupt-parent = <&mpic>;
+                       phy-handle = <&phy1>;
+               };
+
+               serial@4500 {
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <4500 100>;
+                       clock-frequency = <0>;
+                       interrupts = <1a 2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               serial@4600 {
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <4600 100>;
+                       clock-frequency = <0>;
+                       interrupts = <1a 2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               mpic: pic@40000 {
+                       clock-frequency = <0>;
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <40000 40000>;
+                       built-in;
+                       compatible = "chrp,open-pic";
+                       device_type = "open-pic";
+                       big-endian;
+               };
+       };
+};
index 7eb5d81d5eec60cb80a8b149970ae60e6f38e362..b2b2200d0425302db75c1607d2f12b2fac62d0b0 100644 (file)
@@ -17,7 +17,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index 5f9c102a0ab422ada16bd03bafc1944082a6d22d..68a4795720dcb617ff628a9d4451d870ade29097 100644 (file)
@@ -17,7 +17,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index 10502638b0e977f06f472c6c76d3fe1524ad6dd9..1f2afe9291d216a106ba13c82f0c91f1e0fb462f 100644 (file)
@@ -17,7 +17,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index bf49d8c997b9c7be09d382e54508eaabb96cb3c5..7361b36749cb3383666630c2877ddab86291172d 100644 (file)
@@ -21,7 +21,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
index 8a4995a85ba035f28865aacf96a4cca758d89259..260b264c869eeffc0b8aaebc52d25edca645fb23 100644 (file)
@@ -17,7 +17,6 @@
        #size-cells = <1>;
 
        cpus {
-               #cpus = <2>;
                #address-cells = <1>;
                #size-cells = <0>;
 
                        };
 
                };
+
+               pci@9000 {
+                       compatible = "86xx";
+                       device_type = "pci";
+                       #interrupt-cells = <1>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       reg = <9000 1000>;
+                       bus-range = <0 ff>;
+                       ranges = <02000000 0 a0000000 a0000000 0 20000000
+                                 01000000 0 00000000 e3000000 0 00100000>;
+                       clock-frequency = <1fca055>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <19 2>;
+                       interrupt-map-mask = <f800 0 0 7>;
+                       interrupt-map = <
+                               /* IDSEL 0x0 */
+                               0000 0 0 1 &mpic 44 1
+                               0000 0 0 2 &mpic 45 1
+                               0000 0 0 3 &mpic 46 1
+                               0000 0 0 4 &mpic 47 1
+                               >;
+               };
+
                mpic: pic@40000 {
                        clock-frequency = <0>;
                        interrupt-controller;
index 2b56b5df451a31ab9b2c7e6d5d6124b916e3c569..c0d06fd129278894b3fefec1a5b5edcfd9098aa7 100644 (file)
@@ -18,7 +18,6 @@
        linux,phandle = <100>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
                linux,phandle = <200>;
index faecd08c54dae3afddb6bf2aea8dfc5a24f5000a..110bf617060389a5a0ffbd68d607b61da1e1234a 100644 (file)
@@ -18,7 +18,6 @@
        linux,phandle = <100>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
                linux,phandle = <200>;
index d4828fcf1cb9f72a7075244e602c3f89c16026ce..1941bc50d4c57bf80c8845a31bc0fe5a9c153f4d 100644 (file)
@@ -146,4 +146,12 @@ typedef struct elf64_phdr {
 #define ELFOSABI_NONE  0
 #define ELFOSABI_LINUX 3
 
+struct elf_info {
+       unsigned long loadsize;
+       unsigned long memsize;
+       unsigned long elfoffset;
+};
+int parse_elf64(void *hdr, struct elf_info *info);
+int parse_elf32(void *hdr, struct elf_info *info);
+
 #endif                         /* _PPC_BOOT_ELF_H_ */
diff --git a/arch/powerpc/boot/elf_util.c b/arch/powerpc/boot/elf_util.c
new file mode 100644 (file)
index 0000000..7454aa4
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * Updates for PPC64 by Todd Inglett, Dave Engebretsen & Peter Bergner.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+
+int parse_elf64(void *hdr, struct elf_info *info)
+{
+       Elf64_Ehdr *elf64 = hdr;
+       Elf64_Phdr *elf64ph;
+       unsigned int i;
+
+       if (!(elf64->e_ident[EI_MAG0]  == ELFMAG0       &&
+             elf64->e_ident[EI_MAG1]  == ELFMAG1       &&
+             elf64->e_ident[EI_MAG2]  == ELFMAG2       &&
+             elf64->e_ident[EI_MAG3]  == ELFMAG3       &&
+             elf64->e_ident[EI_CLASS] == ELFCLASS64    &&
+             elf64->e_ident[EI_DATA]  == ELFDATA2MSB   &&
+             elf64->e_type            == ET_EXEC       &&
+             elf64->e_machine         == EM_PPC64))
+               return 0;
+
+       elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
+                                (unsigned long)elf64->e_phoff);
+       for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
+               if (elf64ph->p_type == PT_LOAD)
+                       break;
+       if (i >= (unsigned int)elf64->e_phnum)
+               return 0;
+
+       info->loadsize = (unsigned long)elf64ph->p_filesz;
+       info->memsize = (unsigned long)elf64ph->p_memsz;
+       info->elfoffset = (unsigned long)elf64ph->p_offset;
+
+       return 1;
+}
+
+int parse_elf32(void *hdr, struct elf_info *info)
+{
+       Elf32_Ehdr *elf32 = hdr;
+       Elf32_Phdr *elf32ph;
+       unsigned int i;
+
+       if (!(elf32->e_ident[EI_MAG0]  == ELFMAG0       &&
+             elf32->e_ident[EI_MAG1]  == ELFMAG1       &&
+             elf32->e_ident[EI_MAG2]  == ELFMAG2       &&
+             elf32->e_ident[EI_MAG3]  == ELFMAG3       &&
+             elf32->e_ident[EI_CLASS] == ELFCLASS32    &&
+             elf32->e_ident[EI_DATA]  == ELFDATA2MSB   &&
+             elf32->e_type            == ET_EXEC       &&
+             elf32->e_machine         == EM_PPC))
+               return 0;
+
+       elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
+       for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
+               if (elf32ph->p_type == PT_LOAD)
+                       break;
+       if (i >= elf32->e_phnum)
+               return 0;
+
+       info->loadsize = elf32ph->p_filesz;
+       info->memsize = elf32ph->p_memsz;
+       info->elfoffset = elf32ph->p_offset;
+       return 1;
+}
index c76c194715b211056c3c6d658d1538bd0904c505..d00fbd92a4585819cf7b4da042d325c4a3d187c4 100644 (file)
 
 #define _ALIGN(x, al)  (((x) + (al) - 1) & ~((al) - 1))
 
+static char *ft_root_node(struct ft_cxt *cxt)
+{
+       return cxt->rgn[FT_STRUCT].start;
+}
+
 /* Routines for keeping node ptrs returned by ft_find_device current */
 /* First entry not used b/c it would return 0 and be taken as NULL/error */
-static void *ft_node_add(struct ft_cxt *cxt, char *node)
+static void *ft_get_phandle(struct ft_cxt *cxt, char *node)
 {
        unsigned int i;
 
+       if (!node)
+               return NULL;
+
        for (i = 1; i < cxt->nodes_used; i++)   /* already there? */
                if (cxt->node_tbl[i] == node)
                        return (void *)i;
@@ -238,7 +246,7 @@ static int ft_shuffle(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
                        if (rgn == FT_STRUCT)
                                ft_node_update_before(cxt, p, -nextra);
                }
-               *p -= nextra;
+               *pp -= nextra;
                cxt->rgn[rgn].start -= nextra;
                cxt->rgn[rgn].size += nextra;
                return 1;
@@ -253,8 +261,14 @@ static int ft_make_space(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
        char *str, *next;
        enum ft_rgn_id r;
 
-       if (!cxt->isordered && !ft_reorder(cxt, nextra))
-               return 0;
+       if (!cxt->isordered) {
+               unsigned long rgn_off = *pp - cxt->rgn[rgn].start;
+
+               if (!ft_reorder(cxt, nextra))
+                       return 0;
+
+               *pp = cxt->rgn[rgn].start + rgn_off;
+       }
        if (ft_shuffle(cxt, pp, rgn, nextra))
                return 1;
 
@@ -415,7 +429,7 @@ int ft_prop(struct ft_cxt *cxt, const char *name, const void *data,
 {
        int off, len;
 
-       off = lookup_string(cxt, name);
+       off = map_string(cxt, name);
        if (off == NO_STRING)
                return -1;
 
@@ -590,7 +604,7 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size)
 
 void ft_begin_tree(struct ft_cxt *cxt)
 {
-       cxt->p = cxt->rgn[FT_STRUCT].start;
+       cxt->p = ft_root_node(cxt);
 }
 
 void ft_end_tree(struct ft_cxt *cxt)
@@ -636,8 +650,21 @@ void *ft_find_device(struct ft_cxt *cxt, const char *srch_path)
        /* require absolute path */
        if (srch_path[0] != '/')
                return NULL;
-       node = ft_find_descendent(cxt, cxt->rgn[FT_STRUCT].start, srch_path);
-       return ft_node_add(cxt, node);
+       node = ft_find_descendent(cxt, ft_root_node(cxt), srch_path);
+       return ft_get_phandle(cxt, node);
+}
+
+void *ft_find_device_rel(struct ft_cxt *cxt, const void *top,
+                         const char *srch_path)
+{
+       char *node;
+
+       node = ft_node_ph2node(cxt, top);
+       if (node == NULL)
+               return NULL;
+
+       node = ft_find_descendent(cxt, node, srch_path);
+       return ft_get_phandle(cxt, node);
 }
 
 void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
@@ -701,23 +728,18 @@ void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
        return NULL;
 }
 
-void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
+void *__ft_get_parent(struct ft_cxt *cxt, void *node)
 {
-       void *node;
        int d;
        struct ft_atom atom;
        char *p;
 
-       node = ft_node_ph2node(cxt, phandle);
-       if (node == NULL)
-               return NULL;
-
        for (d = 0; cxt->genealogy[d] != NULL; ++d)
                if (cxt->genealogy[d] == node)
-                       return cxt->genealogy[d > 0 ? d - 1 : 0];
+                       return d > 0 ? cxt->genealogy[d - 1] : NULL;
 
        /* have to do it the hard way... */
-       p = cxt->rgn[FT_STRUCT].start;
+       p = ft_root_node(cxt);
        d = 0;
        while ((p = ft_next(cxt, p, &atom)) != NULL) {
                switch (atom.tag) {
@@ -726,7 +748,7 @@ void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
                        if (node == atom.data) {
                                /* found it */
                                cxt->genealogy[d + 1] = NULL;
-                               return d > 0 ? cxt->genealogy[d - 1] : node;
+                               return d > 0 ? cxt->genealogy[d - 1] : NULL;
                        }
                        ++d;
                        break;
@@ -738,41 +760,131 @@ void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
        return NULL;
 }
 
-int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
-               void *buf, const unsigned int buflen)
+void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
 {
-       struct ft_atom atom;
-       void *node;
-       char *p;
-       int depth;
-       unsigned int size;
-
-       node = ft_node_ph2node(cxt, phandle);
+       void *node = ft_node_ph2node(cxt, phandle);
        if (node == NULL)
-               return -1;
+               return NULL;
 
-       depth = 0;
-       p = (char *)node;
+       node = __ft_get_parent(cxt, node);
+       return ft_get_phandle(cxt, node);
+}
 
-       while ((p = ft_next(cxt, p, &atom)) != NULL) {
+static const void *__ft_get_prop(struct ft_cxt *cxt, void *node,
+                                 const char *propname, unsigned int *len)
+{
+       struct ft_atom atom;
+       int depth = 0;
+
+       while ((node = ft_next(cxt, node, &atom)) != NULL) {
                switch (atom.tag) {
                case OF_DT_BEGIN_NODE:
                        ++depth;
                        break;
+
                case OF_DT_PROP:
-                       if ((depth != 1) || strcmp(atom.name, propname))
+                       if (depth != 1 || strcmp(atom.name, propname))
                                break;
-                       size = min(atom.size, buflen);
-                       memcpy(buf, atom.data, size);
-                       return atom.size;
+
+                       if (len)
+                               *len = atom.size;
+
+                       return atom.data;
+
                case OF_DT_END_NODE:
                        if (--depth <= 0)
-                               return -1;
+                               return NULL;
                }
        }
+
+       return NULL;
+}
+
+int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
+               void *buf, const unsigned int buflen)
+{
+       const void *data;
+       unsigned int size;
+
+       void *node = ft_node_ph2node(cxt, phandle);
+       if (!node)
+               return -1;
+
+       data = __ft_get_prop(cxt, node, propname, &size);
+       if (data) {
+               unsigned int clipped_size = min(size, buflen);
+               memcpy(buf, data, clipped_size);
+               return size;
+       }
+
        return -1;
 }
 
+void *__ft_find_node_by_prop_value(struct ft_cxt *cxt, void *prev,
+                                   const char *propname, const char *propval,
+                                   unsigned int proplen)
+{
+       struct ft_atom atom;
+       char *p = ft_root_node(cxt);
+       char *next;
+       int past_prev = prev ? 0 : 1;
+       int depth = -1;
+
+       while ((next = ft_next(cxt, p, &atom)) != NULL) {
+               const void *data;
+               unsigned int size;
+
+               switch (atom.tag) {
+               case OF_DT_BEGIN_NODE:
+                       depth++;
+
+                       if (prev == p) {
+                               past_prev = 1;
+                               break;
+                       }
+
+                       if (!past_prev || depth < 1)
+                               break;
+
+                       data = __ft_get_prop(cxt, p, propname, &size);
+                       if (!data || size != proplen)
+                               break;
+                       if (memcmp(data, propval, size))
+                               break;
+
+                       return p;
+
+               case OF_DT_END_NODE:
+                       if (depth-- == 0)
+                               return NULL;
+
+                       break;
+               }
+
+               p = next;
+       }
+
+       return NULL;
+}
+
+void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
+                                 const char *propname, const char *propval,
+                                 int proplen)
+{
+       void *node = NULL;
+
+       if (prev) {
+               node = ft_node_ph2node(cxt, prev);
+
+               if (!node)
+                       return NULL;
+       }
+
+       node = __ft_find_node_by_prop_value(cxt, node, propname,
+                                           propval, proplen);
+       return ft_get_phandle(cxt, node);
+}
+
 int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
                const void *buf, const unsigned int buflen)
 {
@@ -849,19 +961,26 @@ int ft_del_prop(struct ft_cxt *cxt, const void *phandle, const char *propname)
        return -1;
 }
 
-void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path)
+void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name)
 {
        struct ft_atom atom;
        char *p, *next;
        int depth = 0;
 
-       p = cxt->rgn[FT_STRUCT].start;
+       if (parent) {
+               p = ft_node_ph2node(cxt, parent);
+               if (!p)
+                       return NULL;
+       } else {
+               p = ft_root_node(cxt);
+       }
+
        while ((next = ft_next(cxt, p, &atom)) != NULL) {
                switch (atom.tag) {
                case OF_DT_BEGIN_NODE:
                        ++depth;
-                       if (depth == 1 && strcmp(atom.name, path) == 0)
-                               /* duplicate node path, return error */
+                       if (depth == 1 && strcmp(atom.name, name) == 0)
+                               /* duplicate node name, return error */
                                return NULL;
                        break;
                case OF_DT_END_NODE:
@@ -870,7 +989,7 @@ void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path)
                                break;
                        /* end of node, insert here */
                        cxt->p = p;
-                       ft_begin_node(cxt, path);
+                       ft_begin_node(cxt, name);
                        ft_end_node(cxt);
                        return p;
                }
index b9cd9f61f351e47df2032c6328fbfefafdf007ec..cb26325d72db9cc84562199819af862f0f2ec76c 100644 (file)
@@ -97,10 +97,17 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size);
 void ft_dump_blob(const void *bphp);
 void ft_merge_blob(struct ft_cxt *cxt, void *blob);
 void *ft_find_device(struct ft_cxt *cxt, const char *srch_path);
+void *ft_find_device_rel(struct ft_cxt *cxt, const void *top,
+                         const char *srch_path);
 void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path);
 int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
                void *buf, const unsigned int buflen);
 int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
                const void *buf, const unsigned int buflen);
+void *ft_get_parent(struct ft_cxt *cxt, const void *phandle);
+void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
+                                 const char *propname, const char *propval,
+                                 int proplen);
+void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name);
 
 #endif /* FLATDEVTREE_H */
index 04da38fa477f541f020080348279c14e255267c4..4341e6558c1a73f4e4eced0416c4471c9cbb6d01 100644 (file)
 
 static struct ft_cxt cxt;
 
-static void *ft_finddevice(const char *name)
+static void *fdtm_finddevice(const char *name)
 {
        return ft_find_device(&cxt, name);
 }
 
-static int ft_getprop(const void *phandle, const char *propname, void *buf,
-               const int buflen)
+static int fdtm_getprop(const void *phandle, const char *propname,
+                        void *buf, const int buflen)
 {
        return ft_get_prop(&cxt, phandle, propname, buf, buflen);
 }
 
-static int ft_setprop(const void *phandle, const char *propname,
-               const void *buf, const int buflen)
+static int fdtm_setprop(const void *phandle, const char *propname,
+                        const void *buf, const int buflen)
 {
        return ft_set_prop(&cxt, phandle, propname, buf, buflen);
 }
 
-static unsigned long ft_finalize(void)
+static void *fdtm_get_parent(const void *phandle)
+{
+       return ft_get_parent(&cxt, phandle);
+}
+
+static void *fdtm_create_node(const void *phandle, const char *name)
+{
+       return ft_create_node(&cxt, phandle, name);
+}
+
+static void *fdtm_find_node_by_prop_value(const void *prev,
+                                          const char *propname,
+                                          const char *propval,
+                                          int proplen)
+{
+       return ft_find_node_by_prop_value(&cxt, prev, propname,
+                                         propval, proplen);
+}
+
+static unsigned long fdtm_finalize(void)
 {
        ft_end_tree(&cxt);
        return (unsigned long)cxt.bph;
@@ -41,10 +60,13 @@ static unsigned long ft_finalize(void)
 
 int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device)
 {
-       dt_ops.finddevice = ft_finddevice;
-       dt_ops.getprop = ft_getprop;
-       dt_ops.setprop = ft_setprop;
-       dt_ops.finalize = ft_finalize;
+       dt_ops.finddevice = fdtm_finddevice;
+       dt_ops.getprop = fdtm_getprop;
+       dt_ops.setprop = fdtm_setprop;
+       dt_ops.get_parent = fdtm_get_parent;
+       dt_ops.create_node = fdtm_create_node;
+       dt_ops.find_node_by_prop_value = fdtm_find_node_by_prop_value;
+       dt_ops.finalize = fdtm_finalize;
 
        return ft_open(&cxt, dt_blob, max_size, max_find_device,
                        platform_ops.realloc);
diff --git a/arch/powerpc/boot/gunzip_util.c b/arch/powerpc/boot/gunzip_util.c
new file mode 100644 (file)
index 0000000..df8ab07
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Based on earlier work, Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+#include "gunzip_util.h"
+
+#define HEAD_CRC       2
+#define EXTRA_FIELD    4
+#define ORIG_NAME      8
+#define COMMENT                0x10
+#define RESERVED       0xe0
+
+/**
+ * gunzip_start - prepare to decompress gzip data
+ * @state:     decompressor state structure to be initialized
+ * @src:       buffer containing gzip compressed or uncompressed data
+ * @srclen:    size in bytes of the buffer at src
+ *
+ * If the buffer at @src contains a gzip header, this function
+ * initializes zlib to decompress the data, storing the decompression
+ * state in @state.  The other functions in this file can then be used
+ * to decompress data from the gzipped stream.
+ *
+ * If the buffer at @src does not contain a gzip header, it is assumed
+ * to contain uncompressed data.  The buffer information is recorded
+ * in @state and the other functions in this file will simply copy
+ * data from the uncompressed data stream at @src.
+ *
+ * Any errors, such as bad compressed data, cause an error to be
+ * printed an the platform's exit() function to be called.
+ */
+void gunzip_start(struct gunzip_state *state, void *src, int srclen)
+{
+       char *hdr = src;
+       int hdrlen = 0;
+
+       memset(state, 0, sizeof(*state));
+
+       /* Check for gzip magic number */
+       if ((hdr[0] == 0x1f) && (hdr[1] == 0x8b)) {
+               /* gzip data, initialize zlib parameters */
+               int r, flags;
+
+               state->s.workspace = state->scratch;
+               if (zlib_inflate_workspacesize() > sizeof(state->scratch))
+                       fatal("insufficient scratch space for gunzip\n\r");
+
+               /* skip header */
+               hdrlen = 10;
+               flags = hdr[3];
+               if (hdr[2] != Z_DEFLATED || (flags & RESERVED) != 0)
+                       fatal("bad gzipped data\n\r");
+               if ((flags & EXTRA_FIELD) != 0)
+                       hdrlen = 12 + hdr[10] + (hdr[11] << 8);
+               if ((flags & ORIG_NAME) != 0)
+                       while (hdr[hdrlen++] != 0)
+                               ;
+               if ((flags & COMMENT) != 0)
+                       while (hdr[hdrlen++] != 0)
+                               ;
+               if ((flags & HEAD_CRC) != 0)
+                       hdrlen += 2;
+               if (hdrlen >= srclen)
+                       fatal("gunzip_start: ran out of data in header\n\r");
+
+               r = zlib_inflateInit2(&state->s, -MAX_WBITS);
+               if (r != Z_OK)
+                       fatal("inflateInit2 returned %d\n\r", r);
+       }
+
+       state->s.next_in = src + hdrlen;
+       state->s.avail_in = srclen - hdrlen;
+}
+
+/**
+ * gunzip_partial - extract bytes from a gzip data stream
+ * @state:     gzip state structure previously initialized by gunzip_start()
+ * @dst:       buffer to store extracted data
+ * @dstlen:    maximum number of bytes to extract
+ *
+ * This function extracts at most @dstlen bytes from the data stream
+ * previously associated with @state by gunzip_start(), decompressing
+ * if necessary.  Exactly @dstlen bytes are extracted unless the data
+ * stream doesn't contain enough bytes, in which case the entire
+ * remainder of the stream is decompressed.
+ *
+ * Returns the actual number of bytes extracted.  If any errors occur,
+ * such as a corrupted compressed stream, an error is printed an the
+ * platform's exit() function is called.
+ */
+int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen)
+{
+       int len;
+
+       if (state->s.workspace) {
+               /* gunzipping */
+               int r;
+
+               state->s.next_out = dst;
+               state->s.avail_out = dstlen;
+               r = zlib_inflate(&state->s, Z_FULL_FLUSH);
+               if (r != Z_OK && r != Z_STREAM_END)
+                       fatal("inflate returned %d msg: %s\n\r", r, state->s.msg);
+               len = state->s.next_out - (unsigned char *)dst;
+       } else {
+               /* uncompressed image */
+               len = min(state->s.avail_in, (unsigned)dstlen);
+               memcpy(dst, state->s.next_in, len);
+               state->s.next_in += len;
+               state->s.avail_in -= len;
+       }
+       return len;
+}
+
+/**
+ * gunzip_exactly - extract a fixed number of bytes from a gzip data stream
+ * @state:     gzip state structure previously initialized by gunzip_start()
+ * @dst:       buffer to store extracted data
+ * @dstlen:    number of bytes to extract
+ *
+ * This function extracts exactly @dstlen bytes from the data stream
+ * previously associated with @state by gunzip_start(), decompressing
+ * if necessary.
+ *
+ * If there are less @dstlen bytes available in the data stream, or if
+ * any other errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+void gunzip_exactly(struct gunzip_state *state, void *dst, int dstlen)
+{
+       int len;
+
+       len  = gunzip_partial(state, dst, dstlen);
+       if (len < dstlen)
+               fatal("\n\rgunzip_exactly: ran out of data!"
+                               " Wanted %d, got %d.\n\r", dstlen, len);
+}
+
+/**
+ * gunzip_discard - discard bytes from a gzip data stream
+ * @state:     gzip state structure previously initialized by gunzip_start()
+ * @len:       number of bytes to discard
+ *
+ * This function extracts, then discards exactly @len bytes from the
+ * data stream previously associated with @state by gunzip_start().
+ * Subsequent gunzip_partial(), gunzip_exactly() or gunzip_finish()
+ * calls will extract the data following the discarded bytes in the
+ * data stream.
+ *
+ * If there are less @len bytes available in the data stream, or if
+ * any other errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+void gunzip_discard(struct gunzip_state *state, int len)
+{
+       static char discard_buf[128];
+
+       while (len > sizeof(discard_buf)) {
+               gunzip_exactly(state, discard_buf, sizeof(discard_buf));
+               len -= sizeof(discard_buf);
+       }
+
+       if (len > 0)
+               gunzip_exactly(state, discard_buf, len);
+}
+
+/**
+ * gunzip_finish - extract all remaining bytes from a gzip data stream
+ * @state:     gzip state structure previously initialized by gunzip_start()
+ * @dst:       buffer to store extracted data
+ * @dstlen:    maximum number of bytes to extract
+ *
+ * This function extracts all remaining data, or at most @dstlen
+ * bytes, from the stream previously associated with @state by
+ * gunzip_start().  zlib is then shut down, so it is an error to use
+ * any of the functions in this file on @state until it is
+ * re-initialized with another call to gunzip_start().
+ *
+ * If any errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen)
+{
+       int len;
+
+       if (state->s.workspace) {
+               len = gunzip_partial(state, dst, dstlen);
+               zlib_inflateEnd(&state->s);
+       } else {
+               /* uncompressed image */
+               len = min(state->s.avail_in, (unsigned)dstlen);
+               memcpy(dst, state->s.next_in, len);
+       }
+
+       return len;
+}
diff --git a/arch/powerpc/boot/gunzip_util.h b/arch/powerpc/boot/gunzip_util.h
new file mode 100644 (file)
index 0000000..b3dfa6e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Decompression convenience functions
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef _PPC_BOOT_GUNZIP_UTIL_H_
+#define _PPC_BOOT_GUNZIP_UTIL_H_
+
+#include "zlib.h"
+
+/*
+ * These functions are designed to make life easy for decompressing
+ * kernel images, initrd images or any other gzip compressed image,
+ * particularly if its useful to decompress part of the image (e.g. to
+ * examine headers) before decompressing the remainder.
+ *
+ * To use:
+ *     - declare a gunzip_state structure
+ *     - use gunzip_start() to initialize the state, associating it
+ *       with a stream of compressed data
+ *     - use gunzip_partial(), gunzip_exactly() and gunzip_discard()
+ *       in any combination to extract pieces of data from the stream
+ *     - Finally use gunzip_finish() to extract the tail of the
+ *       compressed stream and wind up zlib
+ */
+
+/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
+#define GUNZIP_SCRATCH_SIZE    46912
+
+struct gunzip_state {
+       z_stream s;
+       char scratch[46912];
+};
+
+void gunzip_start(struct gunzip_state *state, void *src, int srclen);
+int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen);
+void gunzip_exactly(struct gunzip_state *state, void *dst, int len);
+void gunzip_discard(struct gunzip_state *state, int len);
+int gunzip_finish(struct gunzip_state *state, void *dst, int len);
+
+#endif /* _PPC_BOOT_GUNZIP_UTIL_H_ */
index 6f6b50d238b6fa17a19f62552c2560610967927b..56b56a8d4b2334081dbc63452697da21cd5c8078 100644 (file)
 #include "page.h"
 #include "string.h"
 #include "stdio.h"
-#include "zlib.h"
 #include "ops.h"
+#include "gunzip_util.h"
 #include "flatdevtree.h"
-
-extern void flush_cache(void *, unsigned long);
+#include "reg.h"
 
 extern char _start[];
 extern char __bss_start[];
@@ -30,304 +29,173 @@ extern char _initrd_end[];
 extern char _dtb_start[];
 extern char _dtb_end[];
 
+static struct gunzip_state gzstate;
+
 struct addr_range {
-       unsigned long addr;
+       void *addr;
        unsigned long size;
-       unsigned long memsize;
 };
-static struct addr_range vmlinux;
-static struct addr_range vmlinuz;
-static struct addr_range initrd;
-
-static unsigned long elfoffset;
-static int is_64bit;
-
-/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
-static char scratch[46912];
-static char elfheader[256];
 
 typedef void (*kernel_entry_t)(unsigned long, unsigned long, void *);
 
 #undef DEBUG
 
-#define HEAD_CRC       2
-#define EXTRA_FIELD    4
-#define ORIG_NAME      8
-#define COMMENT                0x10
-#define RESERVED       0xe0
-
-static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+static struct addr_range prep_kernel(void)
 {
-       z_stream s;
-       int r, i, flags;
-
-       /* skip header */
-       i = 10;
-       flags = src[3];
-       if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
-               printf("bad gzipped data\n\r");
-               exit();
-       }
-       if ((flags & EXTRA_FIELD) != 0)
-               i = 12 + src[10] + (src[11] << 8);
-       if ((flags & ORIG_NAME) != 0)
-               while (src[i++] != 0)
-                       ;
-       if ((flags & COMMENT) != 0)
-               while (src[i++] != 0)
-                       ;
-       if ((flags & HEAD_CRC) != 0)
-               i += 2;
-       if (i >= *lenp) {
-               printf("gunzip: ran out of data in header\n\r");
-               exit();
-       }
+       char elfheader[256];
+       void *vmlinuz_addr = _vmlinux_start;
+       unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
+       void *addr = 0;
+       struct elf_info ei;
+       int len;
 
-       if (zlib_inflate_workspacesize() > sizeof(scratch)) {
-               printf("gunzip needs more mem\n");
-               exit();
-       }
-       memset(&s, 0, sizeof(s));
-       s.workspace = scratch;
-       r = zlib_inflateInit2(&s, -MAX_WBITS);
-       if (r != Z_OK) {
-               printf("inflateInit2 returned %d\n\r", r);
-               exit();
-       }
-       s.next_in = src + i;
-       s.avail_in = *lenp - i;
-       s.next_out = dst;
-       s.avail_out = dstlen;
-       r = zlib_inflate(&s, Z_FULL_FLUSH);
-       if (r != Z_OK && r != Z_STREAM_END) {
-               printf("inflate returned %d msg: %s\n\r", r, s.msg);
-               exit();
+       /* gunzip the ELF header of the kernel */
+       gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
+       gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
+
+       if (!parse_elf64(elfheader, &ei) && !parse_elf32(elfheader, &ei))
+               fatal("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
+
+       if (platform_ops.image_hdr)
+               platform_ops.image_hdr(elfheader);
+
+       /* We need to alloc the memsize: gzip will expand the kernel
+        * text/data, then possible rubbish we don't care about. But
+        * the kernel bss must be claimed (it will be zero'd by the
+        * kernel itself)
+        */
+       printf("Allocating 0x%lx bytes for kernel ...\n\r", ei.memsize);
+
+       if (platform_ops.vmlinux_alloc) {
+               addr = platform_ops.vmlinux_alloc(ei.memsize);
+       } else {
+               if ((unsigned long)_start < ei.memsize)
+                       fatal("Insufficient memory for kernel at address 0!"
+                              " (_start=%p)\n\r", _start);
        }
-       *lenp = s.next_out - (unsigned char *) dst;
-       zlib_inflateEnd(&s);
-}
 
-static int is_elf64(void *hdr)
-{
-       Elf64_Ehdr *elf64 = hdr;
-       Elf64_Phdr *elf64ph;
-       unsigned int i;
-
-       if (!(elf64->e_ident[EI_MAG0]  == ELFMAG0       &&
-             elf64->e_ident[EI_MAG1]  == ELFMAG1       &&
-             elf64->e_ident[EI_MAG2]  == ELFMAG2       &&
-             elf64->e_ident[EI_MAG3]  == ELFMAG3       &&
-             elf64->e_ident[EI_CLASS] == ELFCLASS64    &&
-             elf64->e_ident[EI_DATA]  == ELFDATA2MSB   &&
-             elf64->e_type            == ET_EXEC       &&
-             elf64->e_machine         == EM_PPC64))
-               return 0;
-
-       elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
-                                (unsigned long)elf64->e_phoff);
-       for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
-               if (elf64ph->p_type == PT_LOAD)
-                       break;
-       if (i >= (unsigned int)elf64->e_phnum)
-               return 0;
-
-       elfoffset = (unsigned long)elf64ph->p_offset;
-       vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
-       vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
-
-       is_64bit = 1;
-       return 1;
-}
+       /* Finally, gunzip the kernel */
+       printf("gunzipping (0x%p <- 0x%p:0x%p)...", addr,
+              vmlinuz_addr, vmlinuz_addr+vmlinuz_size);
+       /* discard up to the actual load data */
+       gunzip_discard(&gzstate, ei.elfoffset - sizeof(elfheader));
+       len = gunzip_finish(&gzstate, addr, ei.loadsize);
+       if (len != ei.loadsize)
+               fatal("ran out of data!  only got 0x%x of 0x%lx bytes.\n\r",
+                               len, ei.loadsize);
+       printf("done 0x%x bytes\n\r", len);
 
-static int is_elf32(void *hdr)
-{
-       Elf32_Ehdr *elf32 = hdr;
-       Elf32_Phdr *elf32ph;
-       unsigned int i;
-
-       if (!(elf32->e_ident[EI_MAG0]  == ELFMAG0       &&
-             elf32->e_ident[EI_MAG1]  == ELFMAG1       &&
-             elf32->e_ident[EI_MAG2]  == ELFMAG2       &&
-             elf32->e_ident[EI_MAG3]  == ELFMAG3       &&
-             elf32->e_ident[EI_CLASS] == ELFCLASS32    &&
-             elf32->e_ident[EI_DATA]  == ELFDATA2MSB   &&
-             elf32->e_type            == ET_EXEC       &&
-             elf32->e_machine         == EM_PPC))
-               return 0;
-
-       elf32 = (Elf32_Ehdr *)elfheader;
-       elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
-       for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
-               if (elf32ph->p_type == PT_LOAD)
-                       break;
-       if (i >= elf32->e_phnum)
-               return 0;
-
-       elfoffset = elf32ph->p_offset;
-       vmlinux.size = elf32ph->p_filesz + elf32ph->p_offset;
-       vmlinux.memsize = elf32ph->p_memsz + elf32ph->p_offset;
-       return 1;
+       flush_cache(addr, ei.loadsize);
+
+       return (struct addr_range){addr, ei.memsize};
 }
 
-static void prep_kernel(unsigned long a1, unsigned long a2)
+static struct addr_range prep_initrd(struct addr_range vmlinux, void *chosen,
+                                    unsigned long initrd_addr,
+                                    unsigned long initrd_size)
 {
-       int len;
-
-       vmlinuz.addr = (unsigned long)_vmlinux_start;
-       vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
-
-       /* gunzip the ELF header of the kernel */
-       if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
-               len = vmlinuz.size;
-               gunzip(elfheader, sizeof(elfheader),
-                               (unsigned char *)vmlinuz.addr, &len);
-       } else
-               memcpy(elfheader, (const void *)vmlinuz.addr,
-                      sizeof(elfheader));
-
-       if (!is_elf64(elfheader) && !is_elf32(elfheader)) {
-               printf("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
-               exit();
+       /* If we have an image attached to us, it overrides anything
+        * supplied by the loader. */
+       if (_initrd_end > _initrd_start) {
+               printf("Attached initrd image at 0x%p-0x%p\n\r",
+                      _initrd_start, _initrd_end);
+               initrd_addr = (unsigned long)_initrd_start;
+               initrd_size = _initrd_end - _initrd_start;
+       } else if (initrd_size > 0) {
+               printf("Using loader supplied ramdisk at 0x%lx-0x%lx\n\r",
+                      initrd_addr, initrd_addr + initrd_size);
        }
-       if (platform_ops.image_hdr)
-               platform_ops.image_hdr(elfheader);
 
-       /* We need to alloc the memsize plus the file offset since gzip
-        * will expand the header (file offset), then the kernel, then
-        * possible rubbish we don't care about. But the kernel bss must
-        * be claimed (it will be zero'd by the kernel itself)
-        */
-       printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize);
-       vmlinux.addr = (unsigned long)malloc(vmlinux.memsize);
-       if (vmlinux.addr == 0) {
-               printf("Can't allocate memory for kernel image !\n\r");
-               exit();
-       }
+       /* If there's no initrd at all, we're done */
+       if (! initrd_size)
+               return (struct addr_range){0, 0};
 
        /*
-        * Now find the initrd
-        *
-        * First see if we have an image attached to us.  If so
-        * allocate memory for it and copy it there.
+        * If the initrd is too low it will be clobbered when the
+        * kernel relocates to its final location.  In this case,
+        * allocate a safer place and move it.
         */
-       initrd.size = (unsigned long)(_initrd_end - _initrd_start);
-       initrd.memsize = initrd.size;
-       if (initrd.size > 0) {
+       if (initrd_addr < vmlinux.size) {
+               void *old_addr = (void *)initrd_addr;
+
                printf("Allocating 0x%lx bytes for initrd ...\n\r",
-                      initrd.size);
-               initrd.addr = (unsigned long)malloc((u32)initrd.size);
-               if (initrd.addr == 0) {
-                       printf("Can't allocate memory for initial "
-                                       "ramdisk !\n\r");
-                       exit();
-               }
-               printf("initial ramdisk moving 0x%lx <- 0x%lx "
-                       "(0x%lx bytes)\n\r", initrd.addr,
-                       (unsigned long)_initrd_start, initrd.size);
-               memmove((void *)initrd.addr, (void *)_initrd_start,
-                       initrd.size);
-               printf("initrd head: 0x%lx\n\r",
-                               *((unsigned long *)initrd.addr));
-       } else if (a2 != 0) {
-               /* Otherwise, see if yaboot or another loader gave us an initrd */
-               initrd.addr = a1;
-               initrd.memsize = initrd.size = a2;
-               printf("Using loader supplied initrd at 0x%lx (0x%lx bytes)\n\r",
-                      initrd.addr, initrd.size);
+                      initrd_size);
+               initrd_addr = (unsigned long)malloc(initrd_size);
+               if (! initrd_addr)
+                       fatal("Can't allocate memory for initial "
+                              "ramdisk !\n\r");
+               printf("Relocating initrd 0x%lx <- 0x%p (0x%lx bytes)\n\r",
+                      initrd_addr, old_addr, initrd_size);
+               memmove((void *)initrd_addr, old_addr, initrd_size);
        }
 
-       /* Eventually gunzip the kernel */
-       if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
-               printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
-                      vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
-               len = vmlinuz.size;
-               gunzip((void *)vmlinux.addr, vmlinux.memsize,
-                       (unsigned char *)vmlinuz.addr, &len);
-               printf("done 0x%lx bytes\n\r", len);
-       } else {
-               memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,
-                       vmlinuz.size);
-       }
+       printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd_addr));
 
-       /* Skip over the ELF header */
-#ifdef DEBUG
-       printf("... skipping 0x%lx bytes of ELF header\n\r",
-                       elfoffset);
-#endif
-       vmlinux.addr += elfoffset;
+       /* Tell the kernel initrd address via device tree */
+       setprop_val(chosen, "linux,initrd-start", (u32)(initrd_addr));
+       setprop_val(chosen, "linux,initrd-end", (u32)(initrd_addr+initrd_size));
 
-       flush_cache((void *)vmlinux.addr, vmlinux.size);
+       return (struct addr_range){(void *)initrd_addr, initrd_size};
 }
 
 /* A buffer that may be edited by tools operating on a zImage binary so as to
  * edit the command line passed to vmlinux (by setting /chosen/bootargs).
  * The buffer is put in it's own section so that tools may locate it easier.
  */
-static char builtin_cmdline[COMMAND_LINE_SIZE]
+static char cmdline[COMMAND_LINE_SIZE]
        __attribute__((__section__("__builtin_cmdline")));
 
-static void get_cmdline(char *buf, int size)
+static void prep_cmdline(void *chosen)
 {
-       void *devp;
-       int len = strlen(builtin_cmdline);
-
-       buf[0] = '\0';
-
-       if (len > 0) { /* builtin_cmdline overrides dt's /chosen/bootargs */
-               len = min(len, size-1);
-               strncpy(buf, builtin_cmdline, len);
-               buf[len] = '\0';
-       }
-       else if ((devp = finddevice("/chosen")))
-               getprop(devp, "bootargs", buf, size);
-}
+       if (cmdline[0] == '\0')
+               getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
 
-static void set_cmdline(char *buf)
-{
-       void *devp;
+       printf("\n\rLinux/PowerPC load: %s", cmdline);
+       /* If possible, edit the command line */
+       if (console_ops.edit_cmdline)
+               console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
+       printf("\n\r");
 
-       if ((devp = finddevice("/chosen")))
-               setprop(devp, "bootargs", buf, strlen(buf) + 1);
+       /* Put the command line back into the devtree for the kernel */
+       setprop_str(chosen, "bootargs", cmdline);
 }
 
 struct platform_ops platform_ops;
 struct dt_ops dt_ops;
 struct console_ops console_ops;
+struct loader_info loader_info;
 
-void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
+void start(void)
 {
+       struct addr_range vmlinux, initrd;
        kernel_entry_t kentry;
-       char cmdline[COMMAND_LINE_SIZE];
        unsigned long ft_addr = 0;
+       void *chosen;
 
-       memset(__bss_start, 0, _end - __bss_start);
-       memset(&platform_ops, 0, sizeof(platform_ops));
-       memset(&dt_ops, 0, sizeof(dt_ops));
-       memset(&console_ops, 0, sizeof(console_ops));
+       /* Do this first, because malloc() could clobber the loader's
+        * command line.  Only use the loader command line if a
+        * built-in command line wasn't set by an external tool */
+       if ((loader_info.cmdline_len > 0) && (cmdline[0] == '\0'))
+               memmove(cmdline, loader_info.cmdline,
+                       min(loader_info.cmdline_len, COMMAND_LINE_SIZE-1));
 
-       if (platform_init(promptr, _dtb_start, _dtb_end))
-               exit();
        if (console_ops.open && (console_ops.open() < 0))
                exit();
        if (platform_ops.fixups)
                platform_ops.fixups();
 
        printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r",
-              _start, sp);
+              _start, get_sp());
 
-       prep_kernel(a1, a2);
+       /* Ensure that the device tree has a /chosen node */
+       chosen = finddevice("/chosen");
+       if (!chosen)
+               chosen = create_node(NULL, "chosen");
 
-       /* If cmdline came from zimage wrapper or if we can edit the one
-        * in the dt, print it out and edit it, if possible.
-        */
-       if ((strlen(builtin_cmdline) > 0) || console_ops.edit_cmdline) {
-               get_cmdline(cmdline, COMMAND_LINE_SIZE);
-               printf("\n\rLinux/PowerPC load: %s", cmdline);
-               if (console_ops.edit_cmdline)
-                       console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
-               printf("\n\r");
-               set_cmdline(cmdline);
-       }
+       vmlinux = prep_kernel();
+       initrd = prep_initrd(vmlinux, chosen,
+                            loader_info.initrd_addr, loader_info.initrd_size);
+       prep_cmdline(chosen);
 
        printf("Finalizing device tree...");
        if (dt_ops.finalize)
@@ -335,7 +203,7 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
        if (ft_addr)
                printf(" flat tree at 0x%lx\n\r", ft_addr);
        else
-               printf(" using OF tree (promptr=%p)\n\r", promptr);
+               printf(" using OF tree (promptr=%p)\n\r", loader_info.promptr);
 
        if (console_ops.close)
                console_ops.close();
@@ -344,10 +212,9 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
        if (ft_addr)
                kentry(ft_addr, 0, NULL);
        else
-               /* XXX initrd addr/size should be passed in properties */
-               kentry(initrd.addr, initrd.size, promptr);
+               kentry((unsigned long)initrd.addr, initrd.size,
+                      loader_info.promptr);
 
-       /* console closed so printf below may not work */
-       printf("Error: Linux kernel returned to zImage boot wrapper!\n\r");
-       exit();
+       /* console closed so printf in fatal below may not work */
+       fatal("Error: Linux kernel returned to zImage boot wrapper!\n\r");
 }
index 1ffe72e35cdc8102d2d14c63b0b0132994678e60..f8f1b2f31412accf4bdfded110af68c813b4a7b7 100644 (file)
@@ -55,10 +55,15 @@ static u8 ns16550_tstc(void)
 int ns16550_console_init(void *devp, struct serial_console_data *scdp)
 {
        int n;
+       unsigned long reg_phys;
 
        n = getprop(devp, "virtual-reg", &reg_base, sizeof(reg_base));
-       if (n != sizeof(reg_base))
-               return -1;
+       if (n != sizeof(reg_base)) {
+               if (!dt_xlate_reg(devp, 0, &reg_phys, NULL))
+                       return -1;
+
+               reg_base = (void *)reg_phys;
+       }
 
        n = getprop(devp, "reg-shift", &reg_shift, sizeof(reg_shift));
        if (n != sizeof(reg_shift))
index 0182f384f3e6cc80d2111ad9682070ce553069a0..d16ee3e3f868eb2592822d63ecff77e07faeccc9 100644 (file)
@@ -173,7 +173,7 @@ static void *claim(unsigned long virt, unsigned long size, unsigned long align)
        return (void *) virt;
 }
 
-static void *of_try_claim(u32 size)
+static void *of_try_claim(unsigned long size)
 {
        unsigned long addr = 0;
 
@@ -208,6 +208,16 @@ static void of_image_hdr(const void *hdr)
        }
 }
 
+static void *of_vmlinux_alloc(unsigned long size)
+{
+       void *p = malloc(size);
+
+       if (!p)
+               fatal("Can't allocate memory for kernel image!\n\r");
+
+       return p;
+}
+
 static void of_exit(void)
 {
        call_prom("exit", 0, 0);
@@ -256,11 +266,12 @@ static void of_console_write(char *buf, int len)
        call_prom("write", 3, 1, of_stdout_handle, buf, len);
 }
 
-int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end)
+void platform_init(unsigned long a1, unsigned long a2, void *promptr)
 {
        platform_ops.image_hdr = of_image_hdr;
        platform_ops.malloc = of_try_claim;
        platform_ops.exit = of_exit;
+       platform_ops.vmlinux_alloc = of_vmlinux_alloc;
 
        dt_ops.finddevice = of_finddevice;
        dt_ops.getprop = of_getprop;
@@ -270,5 +281,9 @@ int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end)
        console_ops.write = of_console_write;
 
        prom = (int (*)(void *))promptr;
-       return 0;
+       loader_info.promptr = promptr;
+       if (a1 && a2 && a2 != 0xdeadbeef) {
+               loader_info.initrd_addr = a1;
+               loader_info.initrd_size = a2;
+       }
 }
index 8abb6516bb7c1833a90fb8341ac459751728b921..73bd47a3a079e269c18a657d4d17baaa3b5d25a6 100644 (file)
@@ -11,7 +11,9 @@
 #ifndef _PPC_BOOT_OPS_H_
 #define _PPC_BOOT_OPS_H_
 
+#include <stddef.h>
 #include "types.h"
+#include "string.h"
 
 #define        COMMAND_LINE_SIZE       512
 #define        MAX_PATH_LEN            256
 struct platform_ops {
        void    (*fixups)(void);
        void    (*image_hdr)(const void *);
-       void *  (*malloc)(u32 size);
+       void *  (*malloc)(unsigned long size);
        void    (*free)(void *ptr);
        void *  (*realloc)(void *ptr, unsigned long size);
        void    (*exit)(void);
+       void *  (*vmlinux_alloc)(unsigned long size);
 };
 extern struct platform_ops platform_ops;
 
@@ -35,6 +38,12 @@ struct dt_ops {
                        const int buflen);
        int     (*setprop)(const void *phandle, const char *name,
                        const void *buf, const int buflen);
+       void *(*get_parent)(const void *phandle);
+       /* The node must not already exist. */
+       void *(*create_node)(const void *parent, const char *name);
+       void *(*find_node_by_prop_value)(const void *prev,
+                                        const char *propname,
+                                        const char *propval, int proplen);
        unsigned long (*finalize)(void);
 };
 extern struct dt_ops dt_ops;
@@ -58,13 +67,23 @@ struct serial_console_data {
        void            (*close)(void);
 };
 
-int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end);
+struct loader_info {
+       void *promptr;
+       unsigned long initrd_addr, initrd_size;
+       char *cmdline;
+       int cmdline_len;
+};
+extern struct loader_info loader_info;
+
+void start(void);
 int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device);
 int serial_console_init(void);
 int ns16550_console_init(void *devp, struct serial_console_data *scdp);
-void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
-               u32 max_allocs);
-
+void *simple_alloc_init(char *base, unsigned long heap_size,
+                       unsigned long granularity, unsigned long max_allocs);
+extern void flush_cache(void *, unsigned long);
+int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
+int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
 
 static inline void *finddevice(const char *name)
 {
@@ -76,12 +95,76 @@ static inline int getprop(void *devp, const char *name, void *buf, int buflen)
        return (dt_ops.getprop) ? dt_ops.getprop(devp, name, buf, buflen) : -1;
 }
 
-static inline int setprop(void *devp, const char *name, void *buf, int buflen)
+static inline int setprop(void *devp, const char *name,
+                          const void *buf, int buflen)
 {
        return (dt_ops.setprop) ? dt_ops.setprop(devp, name, buf, buflen) : -1;
 }
+#define setprop_val(devp, name, val) \
+       do { \
+               typeof(val) x = (val); \
+               setprop((devp), (name), &x, sizeof(x)); \
+       } while (0)
+
+static inline int setprop_str(void *devp, const char *name, const char *buf)
+{
+       if (dt_ops.setprop)
+               return dt_ops.setprop(devp, name, buf, strlen(buf) + 1);
+
+       return -1;
+}
+
+static inline void *get_parent(const char *devp)
+{
+       return dt_ops.get_parent ? dt_ops.get_parent(devp) : NULL;
+}
+
+static inline void *create_node(const void *parent, const char *name)
+{
+       return dt_ops.create_node ? dt_ops.create_node(parent, name) : NULL;
+}
+
 
-static inline void *malloc(u32 size)
+static inline void *find_node_by_prop_value(const void *prev,
+                                            const char *propname,
+                                            const char *propval, int proplen)
+{
+       if (dt_ops.find_node_by_prop_value)
+               return dt_ops.find_node_by_prop_value(prev, propname,
+                                                     propval, proplen);
+
+       return NULL;
+}
+
+static inline void *find_node_by_prop_value_str(const void *prev,
+                                                const char *propname,
+                                                const char *propval)
+{
+       return find_node_by_prop_value(prev, propname, propval,
+                                      strlen(propval) + 1);
+}
+
+static inline void *find_node_by_devtype(const void *prev,
+                                         const char *type)
+{
+       return find_node_by_prop_value_str(prev, "device_type", type);
+}
+
+void dt_fixup_memory(u64 start, u64 size);
+void dt_fixup_cpu_clocks(u32 cpufreq, u32 tbfreq, u32 busfreq);
+void dt_fixup_clock(const char *path, u32 freq);
+void __dt_fixup_mac_addresses(u32 startindex, ...);
+#define dt_fixup_mac_addresses(...) \
+       __dt_fixup_mac_addresses(0, __VA_ARGS__, NULL)
+
+
+static inline void *find_node_by_linuxphandle(const u32 linuxphandle)
+{
+       return find_node_by_prop_value(NULL, "linux,phandle",
+                       (char *)&linuxphandle, sizeof(u32));
+}
+
+static inline void *malloc(unsigned long size)
 {
        return (platform_ops.malloc) ? platform_ops.malloc(size) : NULL;
 }
@@ -98,5 +181,11 @@ static inline void exit(void)
                platform_ops.exit();
        for(;;);
 }
+#define fatal(args...) { printf(args); exit(); }
+
+
+#define BSS_STACK(size) \
+       static char _bss_stack[size]; \
+       void *_platform_stack_top = _bss_stack + sizeof(_bss_stack);
 
 #endif /* _PPC_BOOT_OPS_H_ */
diff --git a/arch/powerpc/boot/ppcboot.h b/arch/powerpc/boot/ppcboot.h
new file mode 100644 (file)
index 0000000..5290ff2
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * This interface is used for compatibility with old U-boots *ONLY*.
+ * Please do not imitate or extend this.
+ */
+
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __PPCBOOT_H__
+#define __PPCBOOT_H__
+
+/*
+ * Board information passed to kernel from PPCBoot
+ *
+ * include/asm-ppc/ppcboot.h
+ */
+
+#include "types.h"
+
+typedef struct bd_info {
+       unsigned long   bi_memstart;    /* start of DRAM memory */
+       unsigned long   bi_memsize;     /* size  of DRAM memory in bytes */
+       unsigned long   bi_flashstart;  /* start of FLASH memory */
+       unsigned long   bi_flashsize;   /* size  of FLASH memory */
+       unsigned long   bi_flashoffset; /* reserved area for startup monitor */
+       unsigned long   bi_sramstart;   /* start of SRAM memory */
+       unsigned long   bi_sramsize;    /* size  of SRAM memory */
+#if defined(TARGET_8xx) || defined(TARGET_CPM2) || defined(TARGET_85xx) ||\
+       defined(TARGET_83xx)
+       unsigned long   bi_immr_base;   /* base of IMMR register */
+#endif
+#if defined(TARGET_PPC_MPC52xx)
+       unsigned long   bi_mbar_base;   /* base of internal registers */
+#endif
+       unsigned long   bi_bootflags;   /* boot / reboot flag (for LynxOS) */
+       unsigned long   bi_ip_addr;     /* IP Address */
+       unsigned char   bi_enetaddr[6]; /* Ethernet address */
+       unsigned short  bi_ethspeed;    /* Ethernet speed in Mbps */
+       unsigned long   bi_intfreq;     /* Internal Freq, in MHz */
+       unsigned long   bi_busfreq;     /* Bus Freq, in MHz */
+#if defined(TARGET_CPM2)
+       unsigned long   bi_cpmfreq;     /* CPM_CLK Freq, in MHz */
+       unsigned long   bi_brgfreq;     /* BRG_CLK Freq, in MHz */
+       unsigned long   bi_sccfreq;     /* SCC_CLK Freq, in MHz */
+       unsigned long   bi_vco;         /* VCO Out from PLL, in MHz */
+#endif
+#if defined(TARGET_PPC_MPC52xx)
+       unsigned long   bi_ipbfreq;     /* IPB Bus Freq, in MHz */
+       unsigned long   bi_pcifreq;     /* PCI Bus Freq, in MHz */
+#endif
+       unsigned long   bi_baudrate;    /* Console Baudrate */
+#if defined(TARGET_4xx)
+       unsigned char   bi_s_version[4];        /* Version of this structure */
+       unsigned char   bi_r_version[32];       /* Version of the ROM (IBM) */
+       unsigned int    bi_procfreq;    /* CPU (Internal) Freq, in Hz */
+       unsigned int    bi_plb_busfreq; /* PLB Bus speed, in Hz */
+       unsigned int    bi_pci_busfreq; /* PCI Bus speed, in Hz */
+       unsigned char   bi_pci_enetaddr[6];     /* PCI Ethernet MAC address */
+#endif
+#if defined(TARGET_HYMOD)
+       hymod_conf_t    bi_hymod_conf;  /* hymod configuration information */
+#endif
+#if defined(TARGET_EVB64260) || defined(TARGET_405EP) || defined(TARGET_44x) || \
+       defined(TARGET_85xx) || defined(TARGET_83xx)
+       /* second onboard ethernet port */
+       unsigned char   bi_enet1addr[6];
+#define HAVE_ENET1ADDR
+#endif
+#if defined(TARGET_EVB64260) || defined(TARGET_440GX) || defined(TARGET_85xx)
+       /* third onboard ethernet ports */
+       unsigned char   bi_enet2addr[6];
+#define HAVE_ENET2ADDR
+#endif
+#if defined(TARGET_440GX)
+       /* fourth onboard ethernet ports */
+       unsigned char   bi_enet3addr[6];
+#define HAVE_ENET3ADDR
+#endif
+#if defined(TARGET_4xx)
+       unsigned int    bi_opbfreq;             /* OB clock in Hz */
+       int             bi_iic_fast[2];         /* Use fast i2c mode */
+#endif
+#if defined(TARGET_440GX)
+       int             bi_phynum[4];           /* phy mapping */
+       int             bi_phymode[4];          /* phy mode */
+#endif
+} bd_t;
+
+#define bi_tbfreq      bi_intfreq
+
+#endif /* __PPCBOOT_H__ */
diff --git a/arch/powerpc/boot/reg.h b/arch/powerpc/boot/reg.h
new file mode 100644 (file)
index 0000000..d3cd9ee
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _PPC_BOOT_REG_H
+#define _PPC_BOOT_REG_H
+/*
+ * Copyright 2007 Davud Gibson, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+static inline u32 mfpvr(void)
+{
+       u32 pvr;
+       asm volatile ("mfpvr    %0" : "=r"(pvr));
+       return pvr;
+}
+
+register void *__stack_pointer asm("r1");
+#define get_sp()       (__stack_pointer)
+
+#endif /* _PPC_BOOT_REG_H */
index cfe3a7505ba08da51bd60cba7b1e228efe0b6660..65ec135d015798490560c3a5bf419cc08e42aa9e 100644 (file)
 #define        ENTRY_IN_USE    0x02
 
 static struct alloc_info {
-       u32     flags;
-       u32     base;
-       u32     size;
+       unsigned long   flags;
+       unsigned long   base;
+       unsigned long   size;
 } *alloc_tbl;
 
-static u32 tbl_entries;
-static u32 alloc_min;
-static u32 next_base;
-static u32 space_left;
+static unsigned long tbl_entries;
+static unsigned long alloc_min;
+static unsigned long next_base;
+static unsigned long space_left;
 
 /*
  * First time an entry is used, its base and size are set.
  * An entry can be freed and re-malloc'd but its base & size don't change.
  * Should be smart enough for needs of bootwrapper.
  */
-static void *simple_malloc(u32 size)
+static void *simple_malloc(unsigned long size)
 {
-       u32 i;
+       unsigned long i;
        struct alloc_info *p = alloc_tbl;
 
        if (size == 0)
@@ -67,13 +67,14 @@ err_out:
 
 static struct alloc_info *simple_find_entry(void *ptr)
 {
-       u32 i;
+       unsigned long i;
        struct alloc_info *p = alloc_tbl;
 
        for (i=0; i<tbl_entries; i++,p++) {
                if (!(p->flags & ENTRY_BEEN_USED))
                        break;
-               if ((p->flags & ENTRY_IN_USE) && (p->base == (u32)ptr))
+               if ((p->flags & ENTRY_IN_USE) &&
+                   (p->base == (unsigned long)ptr))
                        return p;
        }
        return NULL;
@@ -122,10 +123,10 @@ static void *simple_realloc(void *ptr, unsigned long size)
  * Returns addr of first byte after heap so caller can see if it took
  * too much space.  If so, change args & try again.
  */
-void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
-               u32 max_allocs)
+void *simple_alloc_init(char *base, unsigned long heap_size,
+                       unsigned long granularity, unsigned long max_allocs)
 {
-       u32 heap_base, tbl_size;
+       unsigned long heap_base, tbl_size;
 
        heap_size = _ALIGN_UP(heap_size, granularity);
        alloc_min = granularity;
@@ -136,7 +137,7 @@ void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
        alloc_tbl = (struct alloc_info *)_ALIGN_UP((unsigned long)base, 8);
        memset(alloc_tbl, 0, tbl_size);
 
-       heap_base = _ALIGN_UP((u32)alloc_tbl + tbl_size, alloc_min);
+       heap_base = _ALIGN_UP((unsigned long)alloc_tbl + tbl_size, alloc_min);
 
        next_base = heap_base;
        space_left = heap_size;
index 73b8a91bfb34810c7af186448f6c0baf61000e93..adffc58412d4afcd8cf2e25c579fc1abcfe6a689 100644 (file)
@@ -7,11 +7,12 @@
 #define        EINVAL          22      /* Invalid argument */
 #define ENOSPC         28      /* No space left on device */
 
-extern int printf(const char *fmt, ...);
+extern int printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 
 #define fprintf(fmt, args...)  printf(args)
 
-extern int sprintf(char *buf, const char *fmt, ...);
+extern int sprintf(char *buf, const char *fmt, ...)
+       __attribute__((format(printf, 2, 3)));
 
 extern int vsprintf(char *buf, const char *fmt, va_list args);
 
index 024e4d425c596b30fd9b31817d0dbc2bb0a4a990..5cedd901201f82552bcc27299be1ac4057069786 100755 (executable)
@@ -29,6 +29,7 @@ initrd=
 dtb=
 dts=
 cacheit=
+gzip=.gz
 
 # cross-compilation prefix
 CROSS=
@@ -42,7 +43,7 @@ tmpdir=.
 usage() {
     echo 'Usage: wrapper [-o output] [-p platform] [-i initrd]' >&2
     echo '       [-d devtree] [-s tree.dts] [-c] [-C cross-prefix]' >&2
-    echo '       [-D datadir] [-W workingdir] [vmlinux]' >&2
+    echo '       [-D datadir] [-W workingdir] [--no-gzip] [vmlinux]' >&2
     exit 1
 }
 
@@ -91,6 +92,9 @@ while [ "$#" -gt 0 ]; do
        [ "$#" -gt 0 ] || usage
        tmpdir="$1"
        ;;
+    --no-gzip)
+        gzip=
+        ;;
     -?)
        usage
        ;;
@@ -137,31 +141,44 @@ miboot|uboot)
     ksection=image
     isection=initrd
     ;;
+cuboot*)
+    gzip=
+    ;;
 esac
 
 vmz="$tmpdir/`basename \"$kernel\"`.$ext"
-if [ -z "$cacheit" -o ! -f "$vmz.gz" -o "$vmz.gz" -ot "$kernel" ]; then
+if [ -z "$cacheit" -o ! -f "$vmz$gzip" -o "$vmz$gzip" -ot "$kernel" ]; then
     ${CROSS}objcopy $objflags "$kernel" "$vmz.$$"
-    gzip -f -9 "$vmz.$$"
+
+    if [ -n "$gzip" ]; then
+        gzip -f -9 "$vmz.$$"
+    fi
+
     if [ -n "$cacheit" ]; then
-       mv -f "$vmz.$$.gz" "$vmz.gz"
+       mv -f "$vmz.$$$gzip" "$vmz$gzip"
     else
        vmz="$vmz.$$"
     fi
 fi
 
+vmz="$vmz$gzip"
+
 case "$platform" in
-uboot)
-    rm -f "$ofile"
+uboot|cuboot*)
     version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \
        cut -d' ' -f3`
     if [ -n "$version" ]; then
        version="-n Linux-$version"
     fi
+esac
+
+case "$platform" in
+uboot)
+    rm -f "$ofile"
     mkimage -A ppc -O linux -T kernel -C gzip -a 00000000 -e 00000000 \
-       $version -d "$vmz.gz" "$ofile"
+       $version -d "$vmz" "$ofile"
     if [ -z "$cacheit" ]; then
-       rm -f $vmz.gz
+       rm -f "$vmz"
     fi
     exit 0
     ;;
@@ -173,9 +190,9 @@ addsec() {
        --set-section-flags=$3=contents,alloc,load,readonly,data
 }
 
-addsec $tmp "$vmz.gz" $ksection $object/empty.o
+addsec $tmp "$vmz" $ksection $object/empty.o
 if [ -z "$cacheit" ]; then
-    rm -f "$vmz.gz"
+    rm -f "$vmz"
 fi
 
 if [ -n "$initrd" ]; then
@@ -191,7 +208,7 @@ fi
 
 if [ "$platform" != "miboot" ]; then
     ${CROSS}ld -m elf32ppc -T $lds -o "$ofile" \
-       $object/crt0.o $platformo $tmp $object/wrapper.a
+       $platformo $tmp $object/wrapper.a
     rm $tmp
 fi
 
@@ -201,7 +218,19 @@ pseries|chrp)
     $object/addnote "$ofile"
     ;;
 pmaccoff)
-    ${CROSS}objcopy -O aixcoff-rs6000 --set-start 0x500000 "$ofile"
+    entry=`objdump -f "$ofile" | grep '^start address ' | \
+       cut -d' ' -f3`
+    ${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile"
     $object/hack-coff "$ofile"
     ;;
+cuboot*)
+    base=`${CROSS}nm "$ofile" | grep ' _start$' | cut -d' ' -f1`
+    entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | \
+           cut -d' ' -f3`
+    mv "$ofile" "$ofile".elf
+    ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin
+    gzip -f -9 "$ofile".bin
+    mkimage -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \
+            $version -d "$ofile".bin.gz "$ofile"
+    ;;
 esac
index a360905e54282b7908e55203d538dfb730746030..fe87a90ce7f1a606bba00f50597ac9677757598c 100644 (file)
@@ -1,5 +1,6 @@
 OUTPUT_ARCH(powerpc:common)
-ENTRY(_start)
+ENTRY(_zimage_start_opd)
+EXTERN(_zimage_start_opd)
 SECTIONS
 {
   . = (5*1024*1024);
index 4be3c6414b04d683ff015ff6cc2648da62fb0ee7..f6e380fdb388903a01394c1643f3a7b71ae2c455 100644 (file)
@@ -1,5 +1,6 @@
 OUTPUT_ARCH(powerpc:common)
 ENTRY(_zimage_start)
+EXTERN(_zimage_start)
 SECTIONS
 {
   . = (4*1024*1024);
index cf7e316ad4f6585b93b225137faf1383909329fd..6061e5f7696e560ebd4bc7562fcd480aaea2369d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Fri Mar  9 23:34:53 2007
+# Linux kernel version: 2.6.21-rc6
+# Mon Apr 23 20:46:48 2007
 #
 CONFIG_PPC64=y
 CONFIG_64BIT=y
@@ -139,11 +139,31 @@ CONFIG_PPC_MULTIPLATFORM=y
 # CONFIG_PPC_PMAC is not set
 # CONFIG_PPC_MAPLE is not set
 # CONFIG_PPC_PASEMI is not set
+CONFIG_PPC_CELLEB=y
+CONFIG_PPC_PS3=y
+
+#
+# PS3 Platform Options
+#
+# CONFIG_PS3_ADVANCED is not set
+CONFIG_PS3_HTAB_SIZE=20
+# CONFIG_PS3_DYNAMIC_DMA is not set
+CONFIG_PS3_USE_LPAR_ADDR=y
+CONFIG_PS3_VUART=y
+CONFIG_PS3_PS3AV=y
+CONFIG_PS3_SYS_MANAGER=y
 CONFIG_PPC_CELL=y
 CONFIG_PPC_CELL_NATIVE=y
 CONFIG_PPC_IBM_CELL_BLADE=y
-CONFIG_PPC_PS3=y
-CONFIG_PPC_CELLEB=y
+
+#
+# Cell Broadband Engine options
+#
+CONFIG_SPU_FS=m
+CONFIG_SPU_BASE=y
+CONFIG_CBE_RAS=y
+CONFIG_CBE_THERM=m
+CONFIG_CBE_CPUFREQ=m
 CONFIG_PPC_NATIVE=y
 CONFIG_UDBG_RTAS_CONSOLE=y
 CONFIG_PPC_UDBG_BEAT=y
@@ -174,26 +194,6 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 # CONFIG_WANT_EARLY_SERIAL is not set
 CONFIG_MPIC=y
 
-#
-# Cell Broadband Engine options
-#
-CONFIG_SPU_FS=m
-CONFIG_SPU_BASE=y
-CONFIG_CBE_RAS=y
-CONFIG_CBE_THERM=m
-CONFIG_CBE_CPUFREQ=m
-
-#
-# PS3 Platform Options
-#
-# CONFIG_PS3_ADVANCED is not set
-CONFIG_PS3_HTAB_SIZE=20
-# CONFIG_PS3_DYNAMIC_DMA is not set
-CONFIG_PS3_USE_LPAR_ADDR=y
-CONFIG_PS3_VUART=y
-CONFIG_PS3_PS3AV=y
-CONFIG_PS3_SYS_MANAGER=y
-
 #
 # Kernel options
 #
@@ -534,7 +534,6 @@ CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_AEC62XX=y
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -561,11 +560,10 @@ CONFIG_BLK_DEV_SIIMAGE=y
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_BLK_DEV_TC86C001 is not set
-CONFIG_BLK_DEV_IDE_CELLEB=y
+CONFIG_BLK_DEV_CELLEB=y
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -937,7 +935,7 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_HVC_DRIVER=y
 CONFIG_HVC_RTAS=y
-# CONFIG_HVC_BEAT is not set
+CONFIG_HVC_BEAT=y
 
 #
 # IPMI
@@ -1482,6 +1480,8 @@ CONFIG_NLS_ISO8859_15=m
 # Distributed Lock Manager
 #
 # CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
 
 #
 # Library routines
@@ -1540,6 +1540,7 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_DEBUGGER=y
 CONFIG_XMON=y
 CONFIG_XMON_DEFAULT=y
index 7724847f702a09a073cf61e952093ac6e233337b..3ccf19d8da3889b78424d9ddaa2e0802b208ce08 100644 (file)
@@ -143,7 +143,7 @@ CONFIG_PPC_NATIVE=y
 CONFIG_U3_DART=y
 # CONFIG_PPC_RTAS is not set
 # CONFIG_MMIO_NVRAM is not set
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
 # CONFIG_PPC_MPC106 is not set
 CONFIG_PPC_970_NAP=y
 # CONFIG_PPC_INDIRECT_IO is not set
index de97f2f0ae9691a7e476031600f9a3eb284fd08f..15366f0e489f9cbaac29d35a8c4d9b4f56937f95 100644 (file)
@@ -146,7 +146,7 @@ CONFIG_PPC_RTAS=y
 CONFIG_RTAS_PROC=y
 # CONFIG_RTAS_FLASH is not set
 # CONFIG_MMIO_NVRAM is not set
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
 # CONFIG_PPC_MPC106 is not set
 CONFIG_PPC_970_NAP=y
 # CONFIG_PPC_INDIRECT_IO is not set
diff --git a/arch/powerpc/configs/mpc832x_rdb_defconfig b/arch/powerpc/configs/mpc832x_rdb_defconfig
new file mode 100644 (file)
index 0000000..56fc0a8
--- /dev/null
@@ -0,0 +1,1292 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3
+# Mon Mar 12 17:32:19 2007
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_82xx is not set
+CONFIG_PPC_83xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_83xx=y
+CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_QUICC_ENGINE=y
+CONFIG_PPC_GEN550=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC8313_RDB is not set
+# CONFIG_MPC832x_MDS is not set
+CONFIG_MPC832x_RDB=y
+# CONFIG_MPC834x_MDS is not set
+# CONFIG_MPC834x_ITX is not set
+# CONFIG_MPC836x_MDS is not set
+CONFIG_PPC_MPC832x=y
+# CONFIG_MPIC is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI is not set
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_GIANFAR is not set
+CONFIG_UCC_GETH=y
+CONFIG_UGETH_NAPI=y
+# CONFIG_UGETH_MAGIC_PACKET is not set
+# CONFIG_UGETH_FILTERING is not set
+# CONFIG_UGETH_TX_ON_DEMOND is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_83xx_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PASEMI is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
+CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PCI=y
+CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_GTCO is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_LDM_PARTITION=y
+# CONFIG_LDM_DEBUG is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+CONFIG_NLS_ISO8859_8=y
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# QE Options
+#
+CONFIG_UCC_SLOW=y
+CONFIG_UCC_FAST=y
+CONFIG_UCC=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/mpc8544_ds_defconfig b/arch/powerpc/configs/mpc8544_ds_defconfig
new file mode 100644 (file)
index 0000000..b563513
--- /dev/null
@@ -0,0 +1,1077 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3
+# Mon Mar 19 17:18:49 2007
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_85xx=y
+CONFIG_E500=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+# CONFIG_SPE is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_IPC_NS=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_MPC85xx_CDS is not set
+# CONFIG_MPC85xx_MDS is not set
+CONFIG_MPC8544_DS=y
+CONFIG_MPC85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+CONFIG_MPIC=y
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="root=/dev/sda3 rw console=ttyS0,115200"
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_ARPD=y
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_FIB_RULES=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_PATA_PLATFORM is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+CONFIG_VITESSE_PHY=y
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_NVRAM=y
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+# CONFIG_DVB_CORE_ATTACH is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+
+#
+# DVB-T (terrestrial) frontends
+#
+
+#
+# DVB-C (cable) frontends
+#
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+
+#
+# Tuners/PLL support
+#
+
+#
+# Miscellaneous devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_CRAMFS=y
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
index a8da0aea3b8751951d4c47f66d0f68d7e557b88e..126b9f87df25a43f394fd6844606a880b9a02e7d 100644 (file)
@@ -152,7 +152,7 @@ CONFIG_RTAS_ERROR_LOGGING=y
 CONFIG_RTAS_PROC=y
 CONFIG_RTAS_FLASH=m
 CONFIG_MMIO_NVRAM=y
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
 CONFIG_IBMVIO=y
 # CONFIG_IBMEBUS is not set
 # CONFIG_PPC_MPC106 is not set
index 8120d428ebfdf0e2cf51beb8d2106a6bd1ddaa0a..e0fa80eca366bcf05af5afee30b7ceb4032a3342 100644 (file)
@@ -25,8 +25,8 @@ obj-$(CONFIG_PPC_970_NAP)     += idle_power4.o
 obj-$(CONFIG_PPC_OF)           += of_device.o of_platform.o prom_parse.o
 procfs-$(CONFIG_PPC64)         := proc_ppc64.o
 obj-$(CONFIG_PROC_FS)          += $(procfs-y)
-rtaspci-$(CONFIG_PPC64)                := rtas_pci.o
-obj-$(CONFIG_PPC_RTAS)         += rtas.o rtas-rtc.o $(rtaspci-y)
+rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI)  := rtas_pci.o
+obj-$(CONFIG_PPC_RTAS)         += rtas.o rtas-rtc.o $(rtaspci-y-y)
 obj-$(CONFIG_RTAS_FLASH)       += rtas_flash.o
 obj-$(CONFIG_RTAS_PROC)                += rtas-proc.o
 obj-$(CONFIG_LPARCFG)          += lparcfg.o
index 4734b5de599dd516fc612a72d9a1b3258edb544d..5c9ff7f5c44ef903822ee04585e1d47789c6282c 100644 (file)
@@ -241,7 +241,7 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr)
        if (user_mode(regs) && !access_ok(VERIFY_WRITE, p, size))
                return -EFAULT;
        for (i = 0; i < size / sizeof(long); ++i)
-               if (__put_user(0, p+i))
+               if (__put_user_inatomic(0, p+i))
                        return -EFAULT;
        return 1;
 }
@@ -288,7 +288,8 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
                } else {
                        unsigned long pc = regs->nip ^ (swiz & 4);
 
-                       if (__get_user(instr, (unsigned int __user *)pc))
+                       if (__get_user_inatomic(instr,
+                                               (unsigned int __user *)pc))
                                return -EFAULT;
                        if (swiz == 0 && (flags & SW))
                                instr = cpu_to_le32(instr);
@@ -324,27 +325,31 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
                               ((nb0 + 3) / 4) * sizeof(unsigned long));
 
                for (i = 0; i < nb; ++i, ++p)
-                       if (__get_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p)))
+                       if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
+                                               SWIZ_PTR(p)))
                                return -EFAULT;
                if (nb0 > 0) {
                        rptr = &regs->gpr[0];
                        addr += nb;
                        for (i = 0; i < nb0; ++i, ++p)
-                               if (__get_user(REG_BYTE(rptr, i ^ bswiz),
-                                              SWIZ_PTR(p)))
+                               if (__get_user_inatomic(REG_BYTE(rptr,
+                                                                i ^ bswiz),
+                                                       SWIZ_PTR(p)))
                                        return -EFAULT;
                }
 
        } else {
                for (i = 0; i < nb; ++i, ++p)
-                       if (__put_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p)))
+                       if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
+                                               SWIZ_PTR(p)))
                                return -EFAULT;
                if (nb0 > 0) {
                        rptr = &regs->gpr[0];
                        addr += nb;
                        for (i = 0; i < nb0; ++i, ++p)
-                               if (__put_user(REG_BYTE(rptr, i ^ bswiz),
-                                              SWIZ_PTR(p)))
+                               if (__put_user_inatomic(REG_BYTE(rptr,
+                                                                i ^ bswiz),
+                                                       SWIZ_PTR(p)))
                                        return -EFAULT;
                }
        }
@@ -398,7 +403,8 @@ int fix_alignment(struct pt_regs *regs)
 
                if (cpu_has_feature(CPU_FTR_PPC_LE) && (regs->msr & MSR_LE))
                        pc ^= 4;
-               if (unlikely(__get_user(instr, (unsigned int __user *)pc)))
+               if (unlikely(__get_user_inatomic(instr,
+                                                (unsigned int __user *)pc)))
                        return -EFAULT;
                if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE))
                        instr = cpu_to_le32(instr);
@@ -474,16 +480,16 @@ int fix_alignment(struct pt_regs *regs)
                p = (unsigned long) addr;
                switch (nb) {
                case 8:
-                       ret |= __get_user(data.v[0], SWIZ_PTR(p++));
-                       ret |= __get_user(data.v[1], SWIZ_PTR(p++));
-                       ret |= __get_user(data.v[2], SWIZ_PTR(p++));
-                       ret |= __get_user(data.v[3], SWIZ_PTR(p++));
+                       ret |= __get_user_inatomic(data.v[0], SWIZ_PTR(p++));
+                       ret |= __get_user_inatomic(data.v[1], SWIZ_PTR(p++));
+                       ret |= __get_user_inatomic(data.v[2], SWIZ_PTR(p++));
+                       ret |= __get_user_inatomic(data.v[3], SWIZ_PTR(p++));
                case 4:
-                       ret |= __get_user(data.v[4], SWIZ_PTR(p++));
-                       ret |= __get_user(data.v[5], SWIZ_PTR(p++));
+                       ret |= __get_user_inatomic(data.v[4], SWIZ_PTR(p++));
+                       ret |= __get_user_inatomic(data.v[5], SWIZ_PTR(p++));
                case 2:
-                       ret |= __get_user(data.v[6], SWIZ_PTR(p++));
-                       ret |= __get_user(data.v[7], SWIZ_PTR(p++));
+                       ret |= __get_user_inatomic(data.v[6], SWIZ_PTR(p++));
+                       ret |= __get_user_inatomic(data.v[7], SWIZ_PTR(p++));
                        if (unlikely(ret))
                                return -EFAULT;
                }
@@ -551,16 +557,16 @@ int fix_alignment(struct pt_regs *regs)
                p = (unsigned long) addr;
                switch (nb) {
                case 8:
-                       ret |= __put_user(data.v[0], SWIZ_PTR(p++));
-                       ret |= __put_user(data.v[1], SWIZ_PTR(p++));
-                       ret |= __put_user(data.v[2], SWIZ_PTR(p++));
-                       ret |= __put_user(data.v[3], SWIZ_PTR(p++));
+                       ret |= __put_user_inatomic(data.v[0], SWIZ_PTR(p++));
+                       ret |= __put_user_inatomic(data.v[1], SWIZ_PTR(p++));
+                       ret |= __put_user_inatomic(data.v[2], SWIZ_PTR(p++));
+                       ret |= __put_user_inatomic(data.v[3], SWIZ_PTR(p++));
                case 4:
-                       ret |= __put_user(data.v[4], SWIZ_PTR(p++));
-                       ret |= __put_user(data.v[5], SWIZ_PTR(p++));
+                       ret |= __put_user_inatomic(data.v[4], SWIZ_PTR(p++));
+                       ret |= __put_user_inatomic(data.v[5], SWIZ_PTR(p++));
                case 2:
-                       ret |= __put_user(data.v[6], SWIZ_PTR(p++));
-                       ret |= __put_user(data.v[7], SWIZ_PTR(p++));
+                       ret |= __put_user_inatomic(data.v[6], SWIZ_PTR(p++));
+                       ret |= __put_user_inatomic(data.v[7], SWIZ_PTR(p++));
                }
                if (unlikely(ret))
                        return -EFAULT;
index 030d300cd71c8be2e04000b089363e4787ad9d1e..0c5150c69175c014f065214d4440ce0b58ff0b59 100644 (file)
@@ -77,7 +77,6 @@ int main(void)
        DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid));
 #else /* CONFIG_PPC64 */
        DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
-       DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
        DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
        DEFINE(PT_PTRACED, PT_PTRACED);
@@ -140,6 +139,7 @@ int main(void)
        DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
        DEFINE(PACA_SLBSHADOWPTR, offsetof(struct paca_struct, slb_shadow_ptr));
        DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset));
+       DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
 
        DEFINE(SLBSHADOW_STACKVSID,
               offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid));
index 3678997339d6270cfcf5065979965ab4bf15fefa..e7b684689e0479336b8670835a7bb69421415089 100644 (file)
@@ -161,33 +161,33 @@ int btext_initialize(struct device_node *np)
        unsigned long address = 0;
        const u32 *prop;
 
-       prop = get_property(np, "linux,bootx-width", NULL);
+       prop = of_get_property(np, "linux,bootx-width", NULL);
        if (prop == NULL)
-               prop = get_property(np, "width", NULL);
+               prop = of_get_property(np, "width", NULL);
        if (prop == NULL)
                return -EINVAL;
        width = *prop;
-       prop = get_property(np, "linux,bootx-height", NULL);
+       prop = of_get_property(np, "linux,bootx-height", NULL);
        if (prop == NULL)
-               prop = get_property(np, "height", NULL);
+               prop = of_get_property(np, "height", NULL);
        if (prop == NULL)
                return -EINVAL;
        height = *prop;
-       prop = get_property(np, "linux,bootx-depth", NULL);
+       prop = of_get_property(np, "linux,bootx-depth", NULL);
        if (prop == NULL)
-               prop = get_property(np, "depth", NULL);
+               prop = of_get_property(np, "depth", NULL);
        if (prop == NULL)
                return -EINVAL;
        depth = *prop;
        pitch = width * ((depth + 7) / 8);
-       prop = get_property(np, "linux,bootx-linebytes", NULL);
+       prop = of_get_property(np, "linux,bootx-linebytes", NULL);
        if (prop == NULL)
-               prop = get_property(np, "linebytes", NULL);
+               prop = of_get_property(np, "linebytes", NULL);
        if (prop && *prop != 0xffffffffu)
                pitch = *prop;
        if (pitch == 1)
                pitch = 0x1000;
-       prop = get_property(np, "address", NULL);
+       prop = of_get_property(np, "address", NULL);
        if (prop)
                address = *prop;
 
@@ -219,7 +219,7 @@ int __init btext_find_display(int allow_nonstdout)
        struct device_node *np = NULL; 
        int rc = -ENODEV;
 
-       name = get_property(of_chosen, "linux,stdout-path", NULL);
+       name = of_get_property(of_chosen, "linux,stdout-path", NULL);
        if (name != NULL) {
                np = of_find_node_by_path(name);
                if (np != NULL) {
@@ -236,7 +236,7 @@ int __init btext_find_display(int allow_nonstdout)
                return rc;
 
        for (np = NULL; (np = of_find_node_by_type(np, "display"));) {
-               if (get_property(np, "linux,opened", NULL)) {
+               if (of_get_property(np, "linux,opened", NULL)) {
                        printk("trying %s ...\n", np->full_name);
                        rc = btext_initialize(np);
                        printk("result: %d\n", rc);
index 4047be25c4d2e9a4a00639dc12c05dca3362c543..d62cb9cae4e9dcfe5d2834c7b70ea5ad7fe5ee16 100644 (file)
@@ -34,7 +34,7 @@ _GLOBAL(__setup_cpu_pa6t)
        beqlr
 
        mfspr   r0,SPRN_HID5
-       ori     r0,r0,0x30
+       ori     r0,r0,0x38
        mtspr   SPRN_HID5,r0
 
        mfspr   r0,SPRN_LPCR
index e4006dc087ca3133b02639ea01b299d540bf56a3..9cb24d20f0f94e48866df01619dece8c369a5ff4 100644 (file)
@@ -389,6 +389,8 @@ static struct cpu_spec cpu_specs[] = {
                .pmc_type               = PPC_PMC_PA6T,
                .cpu_setup              = __setup_cpu_pa6t,
                .cpu_restore            = __restore_cpu_pa6t,
+               .oprofile_cpu_type      = "ppc64/pa6t",
+               .oprofile_type          = PPC_OPROFILE_PA6T,
                .platform               = "pa6t",
        },
        {       /* default match */
@@ -558,6 +560,18 @@ static struct cpu_spec cpu_specs[] = {
                .cpu_setup              = __setup_cpu_750cx,
                .platform               = "ppc750",
        },
+       {       /* 750CL */
+               .pvr_mask               = 0xfffff0f0,
+               .pvr_value              = 0x00087010,
+               .cpu_name               = "750CL",
+               .cpu_features           = CPU_FTRS_750CL,
+               .cpu_user_features      = COMMON_USER | PPC_FEATURE_PPC_LE,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .num_pmcs               = 4,
+               .cpu_setup              = __setup_cpu_750,
+               .platform               = "ppc750",
+       },
        {       /* 745/755 */
                .pvr_mask               = 0xfffff000,
                .pvr_value              = 0x00083000,
index c03e829fee3c17a2f3d29cc2fe51e93167fbc3b9..c29d1652a421d16143640dbb22f71aa113845f75 100644 (file)
@@ -191,7 +191,6 @@ stack_ovf:
 0:
 
 _GLOBAL(DoSyscall)
-       stw     r0,THREAD+LAST_SYSCALL(r2)
        stw     r3,ORIG_GPR3(r1)
        li      r12,0
        stw     r12,RESULT(r1)
index 97cedcd6c9b46e338bb28849b54fe72d03ff166f..1111fcec7673be71b6dd860a669886154d66a3c9 100644 (file)
@@ -278,8 +278,12 @@ exception_marker:
        beq-    1f;                                                        \
        ld      r1,PACAKSAVE(r13);      /* kernel stack to use          */ \
 1:     cmpdi   cr1,r1,0;               /* check if r1 is in userspace  */ \
-       bge-    cr1,bad_stack;          /* abort if it is               */ \
-       std     r9,_CCR(r1);            /* save CR in stackframe        */ \
+       bge-    cr1,2f;                 /* abort if it is               */ \
+       b       3f;                                                        \
+2:     li      r1,(n);                 /* will be reloaded later       */ \
+       sth     r1,PACA_TRAP_SAVE(r13);                                    \
+       b       bad_stack;                                                 \
+3:     std     r9,_CCR(r1);            /* save CR in stackframe        */ \
        std     r11,_NIP(r1);           /* save SRR0 in stackframe      */ \
        std     r12,_MSR(r1);           /* save SRR1 in stackframe      */ \
        std     r10,0(r1);              /* make stack chain pointer     */ \
@@ -940,6 +944,8 @@ bad_stack:
        SAVE_2GPRS(7,r1)
        SAVE_10GPRS(12,r1)
        SAVE_10GPRS(22,r1)
+       lhz     r12,PACA_TRAP_SAVE(r13)
+       std     r12,_TRAP(r1)
        addi    r11,r1,INT_FRAME_SIZE
        std     r11,0(r1)
        li      r12,0
@@ -1555,7 +1561,6 @@ _GLOBAL(generic_secondary_smp_init)
        
        /* turn on 64-bit mode */
        bl      .enable_64b_mode
-       isync
 
        /* Set up a paca value for this processor. Since we have the
         * physical cpu id in r24, we need to search the pacas to find
@@ -1735,10 +1740,6 @@ _STATIC(__boot_from_prom)
        /* We never return */
        trap
 
-/*
- * At this point, r3 contains the physical address we are running at,
- * returned by prom_init()
- */
 _STATIC(__after_prom_start)
 
 /*
@@ -1851,7 +1852,6 @@ __secondary_start_pmac_0:
 _GLOBAL(pmac_secondary_start)
        /* turn on 64-bit mode */
        bl      .enable_64b_mode
-       isync
 
        /* Copy some CPU settings from CPU 0 */
        bl      .__restore_cpu_ppc970
index 82bd2f10770f9a8d732f0bc287182f94fcf00eec..9a8c9af43b228d276d53093f7ed828b2e5bf4324 100644 (file)
@@ -2,36 +2,37 @@
  * IBM PowerPC IBM eBus Infrastructure Support.
  *
  * Copyright (c) 2005 IBM Corporation
+ *  Joachim Fenkes <fenkes@de.ibm.com>
  *  Heiko J Schick <schickhj@de.ibm.com>
- *    
+ *
  * All rights reserved.
  *
- * This source code is distributed under a dual license of GPL v2.0 and OpenIB 
- * BSD. 
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
  *
  * OpenIB BSD License
  *
- * Redistribution and use in source and binary forms, with or without 
- * modification, are permitted provided that the following conditions are met: 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
  *
- * Redistributions of source code must retain the above copyright notice, this 
- * list of conditions and the following disclaimer. 
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
  *
- * Redistributions in binary form must reproduce the above copyright notice, 
- * this list of conditions and the following disclaimer in the documentation 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
  * and/or other materials
- * provided with the distribution. 
+ * provided with the distribution.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <asm/ibmebus.h>
 #include <asm/abs_addr.h>
 
-static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */
-       .name = ibmebus_bus_device.ofdev.dev.bus_id,
-       .ofdev.dev.bus_id = "ibmebus",
-       .ofdev.dev.bus    = &ibmebus_bus_type,
+static struct device ibmebus_bus_device = { /* fake "parent" device */
+       .bus_id = "ibmebus",
 };
 
+struct bus_type ibmebus_bus_type;
+
 static void *ibmebus_alloc_coherent(struct device *dev,
                                    size_t size,
                                    dma_addr_t *dma_handle,
                                    gfp_t flag)
 {
        void *mem;
-       
+
        mem = kmalloc(size, flag);
        *dma_handle = (dma_addr_t)mem;
 
@@ -63,7 +64,7 @@ static void *ibmebus_alloc_coherent(struct device *dev,
 }
 
 static void ibmebus_free_coherent(struct device *dev,
-                                 size_t size, void *vaddr, 
+                                 size_t size, void *vaddr,
                                  dma_addr_t dma_handle)
 {
        kfree(vaddr);
@@ -79,7 +80,7 @@ static dma_addr_t ibmebus_map_single(struct device *dev,
 
 static void ibmebus_unmap_single(struct device *dev,
                                 dma_addr_t dma_addr,
-                                size_t size, 
+                                size_t size,
                                 enum dma_data_direction direction)
 {
        return;
@@ -90,13 +91,13 @@ static int ibmebus_map_sg(struct device *dev,
                          int nents, enum dma_data_direction direction)
 {
        int i;
-       
+
        for (i = 0; i < nents; i++) {
-               sg[i].dma_address = (dma_addr_t)page_address(sg[i].page) 
+               sg[i].dma_address = (dma_addr_t)page_address(sg[i].page)
                        + sg[i].offset;
                sg[i].dma_length = sg[i].length;
        }
-       
+
        return nents;
 }
 
@@ -128,15 +129,15 @@ static int ibmebus_bus_probe(struct device *dev)
        struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
        const struct of_device_id *id;
        int error = -ENODEV;
-       
+
        if (!ibmebusdrv->probe)
                return error;
-       
+
        id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev);
        if (id) {
                error = ibmebusdrv->probe(ibmebusdev, id);
        }
-       
+
        return error;
 }
 
@@ -144,11 +145,11 @@ static int ibmebus_bus_remove(struct device *dev)
 {
        struct ibmebus_dev *ibmebusdev    = to_ibmebus_dev(dev);
        struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
-       
+
        if (ibmebusdrv->remove) {
                return ibmebusdrv->remove(ibmebusdev);
        }
-       
+
        return 0;
 }
 
@@ -158,21 +159,12 @@ static void __devinit ibmebus_dev_release(struct device *dev)
        kfree(to_ibmebus_dev(dev));
 }
 
-static ssize_t ibmebusdev_show_name(struct device *dev, 
-                                   struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name);
-}
-static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name, 
-                  NULL);
-
-static struct ibmebus_dev* __devinit ibmebus_register_device_common(
+static int __devinit ibmebus_register_device_common(
        struct ibmebus_dev *dev, const char *name)
 {
        int err = 0;
 
-       dev->name = name;
-       dev->ofdev.dev.parent  = &ibmebus_bus_device.ofdev.dev;
+       dev->ofdev.dev.parent  = &ibmebus_bus_device;
        dev->ofdev.dev.bus     = &ibmebus_bus_type;
        dev->ofdev.dev.release = ibmebus_dev_release;
 
@@ -181,17 +173,15 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_common(
        dev->ofdev.dev.archdata.numa_node = of_node_to_nid(dev->ofdev.node);
 
        /* An ibmebusdev is based on a of_device. We have to change the
-        * bus type to use our own DMA mapping operations. 
-        */       
+        * bus type to use our own DMA mapping operations.
+        */
        if ((err = of_device_register(&dev->ofdev)) != 0) {
                printk(KERN_ERR "%s: failed to register device (%d).\n",
                       __FUNCTION__, err);
-               return NULL;
+               return -ENODEV;
        }
-       
-       device_create_file(&dev->ofdev.dev, &dev_attr_name);
-       
-       return dev;
+
+       return 0;
 }
 
 static struct ibmebus_dev* __devinit ibmebus_register_device_node(
@@ -201,35 +191,35 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
        const char *loc_code;
        int length;
 
-       loc_code = get_property(dn, "ibm,loc-code", NULL);
+       loc_code = of_get_property(dn, "ibm,loc-code", NULL);
        if (!loc_code) {
                 printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n",
                       __FUNCTION__, dn->name ? dn->name : "<unknown>");
-               return NULL;
+               return ERR_PTR(-EINVAL);
         }
-       
+
        if (strlen(loc_code) == 0) {
                printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n",
                       __FUNCTION__);
-               return NULL;
+               return ERR_PTR(-EINVAL);
        }
 
        dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL);
        if (!dev) {
-               return NULL;
+               return ERR_PTR(-ENOMEM);
        }
 
        dev->ofdev.node = of_node_get(dn);
-       
+
        length = strlen(loc_code);
-       memcpy(dev->ofdev.dev.bus_id, loc_code 
-               + (length - min(length, BUS_ID_SIZE - 1)), 
+       memcpy(dev->ofdev.dev.bus_id, loc_code
+               + (length - min(length, BUS_ID_SIZE - 1)),
                min(length, BUS_ID_SIZE - 1));
 
        /* Register with generic device framework. */
-       if (ibmebus_register_device_common(dev, dn->name) == NULL) {
+       if (ibmebus_register_device_common(dev, dn->name) != 0) {
                kfree(dev);
-               return NULL;
+               return ERR_PTR(-ENODEV);
        }
 
        return dev;
@@ -238,17 +228,16 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
 static void ibmebus_probe_of_nodes(char* name)
 {
        struct device_node *dn = NULL;
-       
+
        while ((dn = of_find_node_by_name(dn, name))) {
-               if (ibmebus_register_device_node(dn) == NULL) {
+               if (IS_ERR(ibmebus_register_device_node(dn))) {
                        of_node_put(dn);
-                       
                        return;
                }
        }
-       
+
        of_node_put(dn);
-       
+
        return;
 }
 
@@ -262,17 +251,21 @@ static void ibmebus_add_devices_by_id(struct of_device_id *idt)
        return;
 }
 
-static int ibmebus_match_helper(struct device *dev, void *data)
+static int ibmebus_match_name(struct device *dev, void *data)
 {
-       if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0)
+       const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+       const char *name;
+
+       name = of_get_property(ebus_dev->ofdev.node, "name", NULL);
+
+       if (name && (strcmp(data, name) == 0))
                return 1;
-       
+
        return 0;
 }
 
 static int ibmebus_unregister_device(struct device *dev)
 {
-       device_remove_file(dev, &dev_attr_name);
        of_device_unregister(to_of_device(dev));
 
        return 0;
@@ -281,17 +274,16 @@ static int ibmebus_unregister_device(struct device *dev)
 static void ibmebus_remove_devices_by_id(struct of_device_id *idt)
 {
        struct device *dev;
-       
+
        while (strlen(idt->name) > 0) {
-               while ((dev = bus_find_device(&ibmebus_bus_type, NULL, 
+               while ((dev = bus_find_device(&ibmebus_bus_type, NULL,
                                              (void*)idt->name,
-                                             ibmebus_match_helper))) {
+                                             ibmebus_match_name))) {
                        ibmebus_unregister_device(dev);
                }
                idt++;
-               
        }
-       
+
        return;
 }
 
@@ -307,30 +299,33 @@ int ibmebus_register_driver(struct ibmebus_driver *drv)
        if ((err = driver_register(&drv->driver) != 0))
                return err;
 
+       /* remove all supported devices first, in case someone
+        * probed them manually before registering the driver */
+       ibmebus_remove_devices_by_id(drv->id_table);
        ibmebus_add_devices_by_id(drv->id_table);
-       
+
        return 0;
 }
 EXPORT_SYMBOL(ibmebus_register_driver);
 
 void ibmebus_unregister_driver(struct ibmebus_driver *drv)
-{      
+{
        driver_unregister(&drv->driver);
        ibmebus_remove_devices_by_id(drv->id_table);
 }
 EXPORT_SYMBOL(ibmebus_unregister_driver);
 
 int ibmebus_request_irq(struct ibmebus_dev *dev,
-                       u32 ist, 
+                       u32 ist,
                        irq_handler_t handler,
                        unsigned long irq_flags, const char * devname,
                        void *dev_id)
 {
        unsigned int irq = irq_create_mapping(NULL, ist);
-       
+
        if (irq == NO_IRQ)
                return -EINVAL;
-       
+
        return request_irq(irq, handler,
                           irq_flags, devname, dev_id);
 }
@@ -339,56 +334,163 @@ EXPORT_SYMBOL(ibmebus_request_irq);
 void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id)
 {
        unsigned int irq = irq_find_mapping(NULL, ist);
-       
+
        free_irq(irq, dev_id);
 }
 EXPORT_SYMBOL(ibmebus_free_irq);
 
 static int ibmebus_bus_match(struct device *dev, struct device_driver *drv)
-{      
+{
        const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
        struct ibmebus_driver *ebus_drv    = to_ibmebus_driver(drv);
        const struct of_device_id *ids     = ebus_drv->id_table;
        const struct of_device_id *found_id;
-       
+
        if (!ids)
                return 0;
-       
+
        found_id = of_match_device(ids, &ebus_dev->ofdev);
        if (found_id)
                return 1;
-       
+
        return 0;
 }
 
+static ssize_t name_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+       const char *name = of_get_property(ebus_dev->ofdev.node, "name", NULL);
+       return sprintf(buf, "%s\n", name);
+}
+
+static struct device_attribute ibmebus_dev_attrs[] = {
+       __ATTR_RO(name),
+       __ATTR_NULL
+};
+
+static int ibmebus_match_path(struct device *dev, void *data)
+{
+       int rc;
+       struct device_node *dn =
+               of_node_get(to_ibmebus_dev(dev)->ofdev.node);
+
+       rc = (dn->full_name && (strcasecmp((char*)data, dn->full_name) == 0));
+
+       of_node_put(dn);
+       return rc;
+}
+
+static char *ibmebus_chomp(const char *in, size_t count)
+{
+       char *out = (char*)kmalloc(count + 1, GFP_KERNEL);
+       if (!out)
+               return NULL;
+
+       memcpy(out, in, count);
+       out[count] = '\0';
+       if (out[count - 1] == '\n')
+               out[count - 1] = '\0';
+
+       return out;
+}
+
+static ssize_t ibmebus_store_probe(struct bus_type *bus,
+                                  const char *buf, size_t count)
+{
+       struct device_node *dn = NULL;
+       struct ibmebus_dev *dev;
+       char *path;
+       ssize_t rc;
+
+       path = ibmebus_chomp(buf, count);
+       if (!path)
+               return -ENOMEM;
+
+       if (bus_find_device(&ibmebus_bus_type, NULL, path,
+                            ibmebus_match_path)) {
+               printk(KERN_WARNING "%s: %s has already been probed\n",
+                      __FUNCTION__, path);
+               rc = -EINVAL;
+               goto out;
+       }
+
+       if ((dn = of_find_node_by_path(path))) {
+               dev = ibmebus_register_device_node(dn);
+               of_node_put(dn);
+               rc = IS_ERR(dev) ? PTR_ERR(dev) : count;
+       } else {
+               printk(KERN_WARNING "%s: no such device node: %s\n",
+                      __FUNCTION__, path);
+               rc = -ENODEV;
+       }
+
+out:
+       kfree(path);
+       return rc;
+}
+
+static ssize_t ibmebus_store_remove(struct bus_type *bus,
+                                   const char *buf, size_t count)
+{
+       struct device *dev;
+       char *path;
+
+       path = ibmebus_chomp(buf, count);
+       if (!path)
+               return -ENOMEM;
+
+       if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
+                                  ibmebus_match_path))) {
+               ibmebus_unregister_device(dev);
+
+               kfree(path);
+               return count;
+       } else {
+               printk(KERN_WARNING "%s: %s not on the bus\n",
+                      __FUNCTION__, path);
+
+               kfree(path);
+               return -ENODEV;
+       }
+}
+
+static struct bus_attribute ibmebus_bus_attrs[] = {
+       __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe),
+       __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove),
+       __ATTR_NULL
+};
+
 struct bus_type ibmebus_bus_type = {
-       .name = "ibmebus",
-       .match = ibmebus_bus_match,
+       .name      = "ibmebus",
+       .match     = ibmebus_bus_match,
+       .dev_attrs = ibmebus_dev_attrs,
+       .bus_attrs = ibmebus_bus_attrs
 };
 EXPORT_SYMBOL(ibmebus_bus_type);
 
 static int __init ibmebus_bus_init(void)
 {
        int err;
-       
+
        printk(KERN_INFO "IBM eBus Device Driver\n");
-       
+
        err = bus_register(&ibmebus_bus_type);
        if (err) {
                printk(KERN_ERR ":%s: failed to register IBM eBus.\n",
                       __FUNCTION__);
                return err;
        }
-       
-       err = device_register(&ibmebus_bus_device.ofdev.dev);
+
+       err = device_register(&ibmebus_bus_device);
        if (err) {
-               printk(KERN_WARNING "%s: device_register returned %i\n", 
+               printk(KERN_WARNING "%s: device_register returned %i\n",
                       __FUNCTION__, err);
                bus_unregister(&ibmebus_bus_type);
 
                return err;
        }
-       
+
        return 0;
 }
 __initcall(ibmebus_bus_init);
index 95edad4faf26697d61e019f3007c18d0a47f41fa..c08ceca6277d0ef816e7760957615d5b3b91bdda 100644 (file)
@@ -47,6 +47,8 @@ static int novmerge = 0;
 static int novmerge = 1;
 #endif
 
+static int protect4gb = 1;
+
 static inline unsigned long iommu_num_pages(unsigned long vaddr,
                                            unsigned long slen)
 {
@@ -58,6 +60,16 @@ static inline unsigned long iommu_num_pages(unsigned long vaddr,
        return npages;
 }
 
+static int __init setup_protect4gb(char *str)
+{
+       if (strcmp(str, "on") == 0)
+               protect4gb = 1;
+       else if (strcmp(str, "off") == 0)
+               protect4gb = 0;
+
+       return 1;
+}
+
 static int __init setup_iommu(char *str)
 {
        if (!strcmp(str, "novmerge"))
@@ -67,6 +79,7 @@ static int __init setup_iommu(char *str)
        return 1;
 }
 
+__setup("protect4gb=", setup_protect4gb);
 __setup("iommu=", setup_iommu);
 
 static unsigned long iommu_range_alloc(struct iommu_table *tbl,
@@ -429,6 +442,9 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
 struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
 {
        unsigned long sz;
+       unsigned long start_index, end_index;
+       unsigned long entries_per_4g;
+       unsigned long index;
        static int welcomed = 0;
        struct page *page;
 
@@ -450,7 +466,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
 
 #ifdef CONFIG_CRASH_DUMP
        if (ppc_md.tce_get) {
-               unsigned long index, tceval;
+               unsigned long tceval;
                unsigned long tcecount = 0;
 
                /*
@@ -480,6 +496,23 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
        ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
 #endif
 
+       /*
+        * DMA cannot cross 4 GB boundary.  Mark last entry of each 4
+        * GB chunk as reserved.
+        */
+       if (protect4gb) {
+               entries_per_4g = 0x100000000l >> IOMMU_PAGE_SHIFT;
+
+               /* Mark the last bit before a 4GB boundary as used */
+               start_index = tbl->it_offset | (entries_per_4g - 1);
+               start_index -= tbl->it_offset;
+
+               end_index = tbl->it_size;
+
+               for (index = start_index; index < end_index - 1; index += entries_per_4g)
+                       __set_bit(index, tbl->it_map);
+       }
+
        if (!welcomed) {
                printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
                       novmerge ? "disabled" : "enabled");
index 1009308268505753fa506eba009aac6d5b92735a..6c83fe229e6089f6c5221d72f84f342968f7eeac 100644 (file)
@@ -394,7 +394,7 @@ EXPORT_SYMBOL(do_softirq);
 #ifdef CONFIG_PPC_MERGE
 
 static LIST_HEAD(irq_hosts);
-static spinlock_t irq_big_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(irq_big_lock);
 static DEFINE_PER_CPU(unsigned int, irq_radix_reader);
 static unsigned int irq_radix_writer;
 struct irq_map_entry irq_map[NR_IRQS];
index dd2886f97e983848ad8dfc1403e5740b87a1961d..ef647e7a9dc3513cdedd057fe7e626e07dc16278 100644 (file)
@@ -59,12 +59,14 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
        }
 
        if (!ret) {
-               memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+               memcpy(p->ainsn.insn, p->addr,
+                               MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
                p->opcode = *p->addr;
                flush_icache_range((unsigned long)p->ainsn.insn,
                        (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
        }
 
+       p->ainsn.boostable = 0;
        return ret;
 }
 
@@ -232,6 +234,38 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
                return 1;
 
 ss_probe:
+       if (p->ainsn.boostable >= 0) {
+               unsigned int insn = *p->ainsn.insn;
+
+               /* regs->nip is also adjusted if emulate_step returns 1 */
+               ret = emulate_step(regs, insn);
+               if (ret > 0) {
+                       /*
+                        * Once this instruction has been boosted
+                        * successfully, set the boostable flag
+                        */
+                       if (unlikely(p->ainsn.boostable == 0))
+                               p->ainsn.boostable = 1;
+
+                       if (p->post_handler)
+                               p->post_handler(p, regs, 0);
+
+                       kcb->kprobe_status = KPROBE_HIT_SSDONE;
+                       reset_current_kprobe();
+                       preempt_enable_no_resched();
+                       return 1;
+               } else if (ret < 0) {
+                       /*
+                        * We don't allow kprobes on mtmsr(d)/rfi(d), etc.
+                        * So, we should never get here... but, its still
+                        * good to catch them, just in case...
+                        */
+                       printk("Can't step on instruction %x\n", insn);
+                       BUG();
+               } else if (ret == 0)
+                       /* This instruction can't be boosted */
+                       p->ainsn.boostable = -1;
+       }
        prepare_singlestep(p, regs);
        kcb->kprobe_status = KPROBE_HIT_SS;
        return 1;
index 325f490a10cccbfdafff8503e44dd12ba6b6f968..63dd2c3ad95e0c200716404aba1e0b0045c2eb97 100644 (file)
@@ -44,12 +44,12 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
        int index;
 
        /* get clock freq. if present */
-       clk = get_property(np, "clock-frequency", NULL);
+       clk = of_get_property(np, "clock-frequency", NULL);
        if (clk && *clk)
                clock = *clk;
 
        /* get default speed if present */
-       spd = get_property(np, "current-speed", NULL);
+       spd = of_get_property(np, "current-speed", NULL);
 
        /* If we have a location index, then try to use it */
        if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)
@@ -121,11 +121,11 @@ static int __init add_legacy_soc_port(struct device_node *np,
        /* We only support ports that have a clock frequency properly
         * encoded in the device-tree.
         */
-       if (get_property(np, "clock-frequency", NULL) == NULL)
+       if (of_get_property(np, "clock-frequency", NULL) == NULL)
                return -1;
 
        /* if rtas uses this device, don't try to use it as well */
-       if (get_property(np, "used-by-rtas", NULL) != NULL)
+       if (of_get_property(np, "used-by-rtas", NULL) != NULL)
                return -1;
 
        /* Get the address */
@@ -157,7 +157,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
        DBG(" -> add_legacy_isa_port(%s)\n", np->full_name);
 
        /* Get the ISA port number */
-       reg = get_property(np, "reg", NULL);
+       reg = of_get_property(np, "reg", NULL);
        if (reg == NULL)
                return -1;
 
@@ -168,7 +168,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
        /* Now look for an "ibm,aix-loc" property that gives us ordering
         * if any...
         */
-       typep = get_property(np, "ibm,aix-loc", NULL);
+       typep = of_get_property(np, "ibm,aix-loc", NULL);
 
        /* If we have a location index, then use it */
        if (typep && *typep == 'S')
@@ -206,7 +206,7 @@ static int __init add_legacy_pci_port(struct device_node *np,
         * compatible UARTs on PCI need all sort of quirks (port offsets
         * etc...) that this code doesn't know about
         */
-       if (get_property(np, "clock-frequency", NULL) == NULL)
+       if (of_get_property(np, "clock-frequency", NULL) == NULL)
                return -1;
 
        /* Get the PCI address. Assume BAR 0 */
@@ -232,7 +232,7 @@ static int __init add_legacy_pci_port(struct device_node *np,
         * we get to their "reg" property
         */
        if (np != pci_dev) {
-               const u32 *reg = get_property(np, "reg", NULL);
+               const u32 *reg = of_get_property(np, "reg", NULL);
                if (reg && (*reg < 4))
                        index = lindex = *reg;
        }
@@ -296,7 +296,7 @@ void __init find_legacy_serial_ports(void)
        DBG(" -> find_legacy_serial_port()\n");
 
        /* Now find out if one of these is out firmware console */
-       path = get_property(of_chosen, "linux,stdout-path", NULL);
+       path = of_get_property(of_chosen, "linux,stdout-path", NULL);
        if (path != NULL) {
                stdout = of_find_node_by_path(path);
                if (stdout)
@@ -529,7 +529,7 @@ static int __init check_legacy_serial_console(void)
        }
        /* We are getting a weird phandle from OF ... */
        /* ... So use the full path instead */
-       name = get_property(of_chosen, "linux,stdout-path", NULL);
+       name = of_get_property(of_chosen, "linux,stdout-path", NULL);
        if (name == NULL) {
                DBG(" no linux,stdout-path !\n");
                return -ENODEV;
@@ -541,12 +541,12 @@ static int __init check_legacy_serial_console(void)
        }
        DBG("stdout is %s\n", prom_stdout->full_name);
 
-       name = get_property(prom_stdout, "name", NULL);
+       name = of_get_property(prom_stdout, "name", NULL);
        if (!name) {
                DBG(" stdout package has no name !\n");
                goto not_found;
        }
-       spd = get_property(prom_stdout, "current-speed", NULL);
+       spd = of_get_property(prom_stdout, "current-speed", NULL);
        if (spd)
                speed = *spd;
 
index 89486b631284d29cfd5d03b01a905bf0dd0c35cc..c492cee90e0f15a33492927982c995fcc5eecdeb 100644 (file)
@@ -130,30 +130,31 @@ static int iseries_lparcfg_data(struct seq_file *m, void *v)
 /*
  * Methods used to fetch LPAR data when running on a pSeries platform.
  */
-/* find a better place for this function... */
 static void log_plpar_hcall_return(unsigned long rc, char *tag)
 {
-       if (rc == 0)            /* success, return */
+       switch(rc) {
+       case 0:
                return;
-/* check for null tag ? */
-       if (rc == H_HARDWARE)
-               printk(KERN_INFO
-                      "plpar-hcall (%s) failed with hardware fault\n", tag);
-       else if (rc == H_FUNCTION)
-               printk(KERN_INFO
-                      "plpar-hcall (%s) failed; function not allowed\n", tag);
-       else if (rc == H_AUTHORITY)
-               printk(KERN_INFO
-                      "plpar-hcall (%s) failed; not authorized to this"
-                      " function\n", tag);
-       else if (rc == H_PARAMETER)
-               printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n",
-                      tag);
-       else
-               printk(KERN_INFO
-                      "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n",
-                      tag, rc);
-
+       case H_HARDWARE:
+               printk(KERN_INFO "plpar-hcall (%s) "
+                               "Hardware fault\n", tag);
+               return;
+       case H_FUNCTION:
+               printk(KERN_INFO "plpar-hcall (%s) "
+                               "Function not allowed\n", tag);
+               return;
+       case H_AUTHORITY:
+               printk(KERN_INFO "plpar-hcall (%s) "
+                               "Not authorized to this function\n", tag);
+               return;
+       case H_PARAMETER:
+               printk(KERN_INFO "plpar-hcall (%s) "
+                               "Bad parameter(s)\n",tag);
+               return;
+       default:
+               printk(KERN_INFO "plpar-hcall (%s) "
+                               "Unexpected rc(0x%lx)\n", tag, rc);
+       }
 }
 
 /*
@@ -321,15 +322,16 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
        struct device_node *rtas_node;
        const int *lrdrp = NULL;
 
-       rtas_node = find_path_device("/rtas");
+       rtas_node = of_find_node_by_path("/rtas");
        if (rtas_node)
-               lrdrp = get_property(rtas_node, "ibm,lrdr-capacity", NULL);
+               lrdrp = of_get_property(rtas_node, "ibm,lrdr-capacity", NULL);
 
        if (lrdrp == NULL) {
                partition_potential_processors = vdso_data->processorCount;
        } else {
                partition_potential_processors = *(lrdrp + 4);
        }
+       of_node_put(rtas_node);
 
        partition_active_processors = lparcfg_count_active_processors();
 
@@ -537,25 +539,27 @@ static int lparcfg_data(struct seq_file *m, void *v)
 
        seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
 
-       rootdn = find_path_device("/");
+       rootdn = of_find_node_by_path("/");
        if (rootdn) {
-               tmp = get_property(rootdn, "model", NULL);
+               tmp = of_get_property(rootdn, "model", NULL);
                if (tmp) {
                        model = tmp;
                        /* Skip "IBM," - see platforms/iseries/dt.c */
                        if (firmware_has_feature(FW_FEATURE_ISERIES))
                                model += 4;
                }
-               tmp = get_property(rootdn, "system-id", NULL);
+               tmp = of_get_property(rootdn, "system-id", NULL);
                if (tmp) {
                        system_id = tmp;
                        /* Skip "IBM," - see platforms/iseries/dt.c */
                        if (firmware_has_feature(FW_FEATURE_ISERIES))
                                system_id += 4;
                }
-               lp_index_ptr = get_property(rootdn, "ibm,partition-no", NULL);
+               lp_index_ptr = of_get_property(rootdn, "ibm,partition-no",
+                                       NULL);
                if (lp_index_ptr)
                        lp_index = *lp_index_ptr;
+               of_node_put(rootdn);
        }
        seq_printf(m, "serial_number=%s\n", system_id);
        seq_printf(m, "system_type=%s\n", model);
index a24b09c27718b0f5ece5ae90ecc3ad0e059d49ed..704375bda73a928446bb87ba68e492659be093a0 100644 (file)
@@ -72,8 +72,8 @@ int default_machine_kexec_prepare(struct kimage *image)
        /* We also should not overwrite the tce tables */
        for (node = of_find_node_by_type(NULL, "pci"); node != NULL;
                        node = of_find_node_by_type(node, "pci")) {
-               basep = get_property(node, "linux,tce-base", NULL);
-               sizep = get_property(node, "linux,tce-size", NULL);
+               basep = of_get_property(node, "linux,tce-base", NULL);
+               sizep = of_get_property(node, "linux,tce-size", NULL);
                if (basep == NULL || sizep == NULL)
                        continue;
 
@@ -294,19 +294,19 @@ static unsigned long htab_base, kernel_end;
 static struct property htab_base_prop = {
        .name = "linux,htab-base",
        .length = sizeof(unsigned long),
-       .value = (unsigned char *)&htab_base,
+       .value = &htab_base,
 };
 
 static struct property htab_size_prop = {
        .name = "linux,htab-size",
        .length = sizeof(unsigned long),
-       .value = (unsigned char *)&htab_size_bytes,
+       .value = &htab_size_bytes,
 };
 
 static struct property kernel_end_prop = {
        .name = "linux,kernel-end",
        .length = sizeof(unsigned long),
-       .value = (unsigned char *)&kernel_end,
+       .value = &kernel_end,
 };
 
 static void __init export_htab_values(void)
@@ -335,7 +335,7 @@ static void __init export_htab_values(void)
 static struct property crashk_base_prop = {
        .name = "linux,crashkernel-base",
        .length = sizeof(unsigned long),
-       .value = (unsigned char *)&crashk_res.start,
+       .value = &crashk_res.start,
 };
 
 static unsigned long crashk_size;
@@ -343,7 +343,7 @@ static unsigned long crashk_size;
 static struct property crashk_size_prop = {
        .name = "linux,crashkernel-size",
        .length = sizeof(unsigned long),
-       .value = (unsigned char *)&crashk_size,
+       .value = &crashk_size,
 };
 
 static void __init export_crashk_values(void)
index 412bea3cf813279bd64d8820ed12e593327fa457..98decf8ebff44831dae7704fa431beca76a87cbb 100644 (file)
@@ -734,10 +734,6 @@ _GLOBAL(abs)
        sub     r3,r3,r4
        blr
 
-_GLOBAL(_get_SP)
-       mr      r3,r1           /* Close enough */
-       blr
-
 /*
  * Create a kernel thread
  *   kernel_thread(fn, arg, flags)
index e921514e655bd45a2b96438151e2a2f07d66b10e..0c8ea7659d928701bc92fcfff78685d81dc99453 100644 (file)
@@ -120,6 +120,117 @@ void of_device_unregister(struct of_device *ofdev)
 }
 
 
+static ssize_t of_device_get_modalias(struct of_device *ofdev,
+                                       char *str, ssize_t len)
+{
+       const char *compat;
+       int cplen, i;
+       ssize_t tsize, csize, repend;
+
+       /* Name & Type */
+       csize = snprintf(str, len, "of:N%sT%s",
+                               ofdev->node->name, ofdev->node->type);
+
+       /* Get compatible property if any */
+       compat = of_get_property(ofdev->node, "compatible", &cplen);
+       if (!compat)
+               return csize;
+
+       /* Find true end (we tolerate multiple \0 at the end */
+       for (i=(cplen-1); i>=0 && !compat[i]; i--)
+               cplen--;
+       if (!cplen)
+               return csize;
+       cplen++;
+
+       /* Check space (need cplen+1 chars including final \0) */
+       tsize = csize + cplen;
+       repend = tsize;
+
+       if (csize>=len)         /* @ the limit, all is already filled */
+               return tsize;
+
+       if (tsize>=len) {               /* limit compat list */
+               cplen = len-csize-1;
+               repend = len;
+       }
+
+       /* Copy and do char replacement */
+       memcpy(&str[csize+1], compat, cplen);
+       for (i=csize; i<repend; i++) {
+               char c = str[i];
+               if (c=='\0')
+                       str[i] = 'C';
+               else if (c==' ')
+                       str[i] = '_';
+       }
+
+       return tsize;
+}
+
+int of_device_uevent(struct device *dev,
+               char **envp, int num_envp, char *buffer, int buffer_size)
+{
+       struct of_device *ofdev;
+       const char *compat;
+       int i = 0, length = 0, seen = 0, cplen, sl;
+
+       if (!dev)
+               return -ENODEV;
+
+       ofdev = to_of_device(dev);
+
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "OF_NAME=%s", ofdev->node->name))
+               return -ENOMEM;
+
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "OF_TYPE=%s", ofdev->node->type))
+               return -ENOMEM;
+
+        /* Since the compatible field can contain pretty much anything
+         * it's not really legal to split it out with commas. We split it
+         * up using a number of environment variables instead. */
+
+       compat = of_get_property(ofdev->node, "compatible", &cplen);
+       while (compat && *compat && cplen > 0) {
+               if (add_uevent_var(envp, num_envp, &i,
+                                  buffer, buffer_size, &length,
+                                  "OF_COMPATIBLE_%d=%s", seen, compat))
+                       return -ENOMEM;
+
+               sl = strlen (compat) + 1;
+               compat += sl;
+               cplen -= sl;
+               seen++;
+       }
+
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "OF_COMPATIBLE_N=%d", seen))
+               return -ENOMEM;
+
+       /* modalias is trickier, we add it in 2 steps */
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "MODALIAS="))
+               return -ENOMEM;
+
+       sl = of_device_get_modalias(ofdev, &buffer[length-1],
+                                       buffer_size-length);
+       if (sl >= (buffer_size-length))
+               return -ENOMEM;
+
+       length += sl;
+
+       envp[i] = NULL;
+
+       return 0;
+}
+
+
 EXPORT_SYMBOL(of_match_node);
 EXPORT_SYMBOL(of_match_device);
 EXPORT_SYMBOL(of_device_register);
@@ -127,3 +238,4 @@ EXPORT_SYMBOL(of_device_unregister);
 EXPORT_SYMBOL(of_dev_get);
 EXPORT_SYMBOL(of_dev_put);
 EXPORT_SYMBOL(of_release_dev);
+EXPORT_SYMBOL(of_device_uevent);
index 9e7a4d249f03036728d20035f9c632bef713d539..908ed7926db4e60ee3e3a4c2d3459b165ebbbc3c 100644 (file)
@@ -133,6 +133,7 @@ static int of_platform_device_resume(struct device * dev)
 struct bus_type of_platform_bus_type = {
        .name   = "of_platform",
        .match  = of_platform_bus_match,
+       .uevent = of_device_uevent,
        .probe  = of_platform_device_probe,
        .remove = of_platform_device_remove,
        .suspend        = of_platform_device_suspend,
@@ -177,7 +178,7 @@ static void of_platform_make_bus_id(struct of_device *dev)
         * and 'D' for MMIO DCRs.
         */
 #ifdef CONFIG_PPC_DCR
-       reg = get_property(node, "dcr-reg", NULL);
+       reg = of_get_property(node, "dcr-reg", NULL);
        if (reg) {
 #ifdef CONFIG_PPC_DCR_NATIVE
                snprintf(name, BUS_ID_SIZE, "d%x.%s",
@@ -197,7 +198,7 @@ static void of_platform_make_bus_id(struct of_device *dev)
        /*
         * For MMIO, get the physical address
         */
-       reg = get_property(node, "reg", NULL);
+       reg = of_get_property(node, "reg", NULL);
        if (reg) {
                addr = of_translate_address(node, reg);
                if (addr != OF_BAD_ADDR) {
index d8ef2e1005051c3408b5105a80b376c2f43d4d66..f022862de34458b90a402a6c20330819aec7ff09 100644 (file)
@@ -637,7 +637,7 @@ make_one_node_map(struct device_node* node, u8 pci_bus)
 
        if (pci_bus >= pci_bus_count)
                return;
-       bus_range = get_property(node, "bus-range", &len);
+       bus_range = of_get_property(node, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                printk(KERN_WARNING "Can't get bus-range for %s, "
                       "assuming it starts at 0\n", node->full_name);
@@ -649,17 +649,20 @@ make_one_node_map(struct device_node* node, u8 pci_bus)
                struct pci_dev* dev;
                const unsigned int *class_code, *reg;
        
-               class_code = get_property(node, "class-code", NULL);
+               class_code = of_get_property(node, "class-code", NULL);
                if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
                        (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
                        continue;
-               reg = get_property(node, "reg", NULL);
+               reg = of_get_property(node, "reg", NULL);
                if (!reg)
                        continue;
-               dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff));
-               if (!dev || !dev->subordinate)
+               dev = pci_get_bus_and_slot(pci_bus, ((reg[0] >> 8) & 0xff));
+               if (!dev || !dev->subordinate) {
+                       pci_dev_put(dev);
                        continue;
+               }
                make_one_node_map(node, dev->subordinate->number);
+               pci_dev_put(dev);
        }
 }
        
@@ -669,6 +672,7 @@ pcibios_make_OF_bus_map(void)
        int i;
        struct pci_controller* hose;
        struct property *map_prop;
+       struct device_node *dn;
 
        pci_to_OF_bus_map = kmalloc(pci_bus_count, GFP_KERNEL);
        if (!pci_to_OF_bus_map) {
@@ -690,12 +694,13 @@ pcibios_make_OF_bus_map(void)
                        continue;
                make_one_node_map(node, hose->first_busno);
        }
-       map_prop = of_find_property(find_path_device("/"),
-                       "pci-OF-bus-map", NULL);
+       dn = of_find_node_by_path("/");
+       map_prop = of_find_property(dn, "pci-OF-bus-map", NULL);
        if (map_prop) {
                BUG_ON(pci_bus_count > map_prop->length);
                memcpy(map_prop->value, pci_to_OF_bus_map, pci_bus_count);
        }
+       of_node_put(dn);
 #ifdef DEBUG
        printk("PCI->OF bus map:\n");
        for (i=0; i<pci_bus_count; i++) {
@@ -724,7 +729,7 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
                 * a fake root for all functions of a multi-function device,
                 * we go down them as well.
                 */
-               class_code = get_property(node, "class-code", NULL);
+               class_code = of_get_property(node, "class-code", NULL);
                if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
                        (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
                        strcmp(node->name, "multifunc-device"))
@@ -744,7 +749,7 @@ static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
        unsigned int psize;
 
        while ((np = of_get_next_child(parent, np)) != NULL) {
-               reg = get_property(np, "reg", &psize);
+               reg = of_get_property(np, "reg", &psize);
                if (reg == NULL || psize < 4)
                        continue;
                if (((reg[0] >> 8) & 0xff) == devfn)
@@ -859,7 +864,7 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
        if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child,
                        find_OF_pci_device_filter, (void *)node))
                return -ENODEV;
-       reg = get_property(node, "reg", NULL);
+       reg = of_get_property(node, "reg", NULL);
        if (!reg)
                return -ENODEV;
        *bus = (reg[0] >> 16) & 0xff;
@@ -895,14 +900,14 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
        int rlen = 0, orig_rlen;
        int memno = 0;
        struct resource *res;
-       int np, na = prom_n_addr_cells(dev);
+       int np, na = of_n_addr_cells(dev);
        np = na + 5;
 
        /* First we try to merge ranges to fix a problem with some pmacs
         * that can have more than 3 ranges, fortunately using contiguous
         * addresses -- BenH
         */
-       dt_ranges = get_property(dev, "ranges", &rlen);
+       dt_ranges = of_get_property(dev, "ranges", &rlen);
        if (!dt_ranges)
                return;
        /* Sanity check, though hopefully that never happens */
@@ -1006,14 +1011,19 @@ void __init
 pci_create_OF_bus_map(void)
 {
        struct property* of_prop;
-       
+       struct device_node *dn;
+
        of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256);
-       if (of_prop && find_path_device("/")) {
+       if (!of_prop)
+               return;
+       dn = of_find_node_by_path("/");
+       if (dn) {
                memset(of_prop, -1, sizeof(struct property) + 256);
                of_prop->name = "pci-OF-bus-map";
                of_prop->length = 256;
-               of_prop->value = (unsigned char *)&of_prop[1];
-               prom_add_property(find_path_device("/"), of_prop);
+               of_prop->value = &of_prop[1];
+               prom_add_property(dn, of_prop);
+               of_node_put(dn);
        }
 }
 
index 7e97d71a5f8fa17f08d04e01b623bca7534c1044..60d7d4baa227bb6359e79ece0123ab9b89d03ee3 100644 (file)
@@ -61,8 +61,7 @@ void iSeries_pcibios_init(void);
 
 LIST_HEAD(hose_list);
 
-struct dma_mapping_ops *pci_dma_ops;
-EXPORT_SYMBOL(pci_dma_ops);
+static struct dma_mapping_ops *pci_dma_ops;
 
 int global_phb_number;         /* Global phb counter */
 
@@ -70,6 +69,17 @@ int global_phb_number;               /* Global phb counter */
 struct pci_dev *ppc64_isabridge_dev = NULL;
 EXPORT_SYMBOL_GPL(ppc64_isabridge_dev);
 
+void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
+{
+       pci_dma_ops = dma_ops;
+}
+
+struct dma_mapping_ops *get_pci_dma_ops(void)
+{
+       return pci_dma_ops;
+}
+EXPORT_SYMBOL(get_pci_dma_ops);
+
 static void fixup_broken_pcnet32(struct pci_dev* dev)
 {
        if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
@@ -258,7 +268,7 @@ static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
        const u32 *prop;
        int len;
 
-       prop = get_property(np, name, &len);
+       prop = of_get_property(np, name, &len);
        if (prop && len >= 4)
                return *prop;
        return def;
@@ -291,7 +301,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
        u32 i;
        int proplen;
 
-       addrs = get_property(node, "assigned-addresses", &proplen);
+       addrs = of_get_property(node, "assigned-addresses", &proplen);
        if (!addrs)
                return;
        DBG("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
@@ -333,7 +343,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
        dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
        if (!dev)
                return NULL;
-       type = get_property(node, "device_type", NULL);
+       type = of_get_property(node, "device_type", NULL);
        if (type == NULL)
                type = "";
 
@@ -397,7 +407,7 @@ void __devinit of_scan_bus(struct device_node *node,
 
        while ((child = of_get_next_child(node, child)) != NULL) {
                DBG("  * %s\n", child->full_name);
-               reg = get_property(child, "reg", &reglen);
+               reg = of_get_property(child, "reg", &reglen);
                if (reg == NULL || reglen < 20)
                        continue;
                devfn = (reg[0] >> 8) & 0xff;
@@ -430,13 +440,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
        DBG("of_scan_pci_bridge(%s)\n", node->full_name);
 
        /* parse bus-range property */
-       busrange = get_property(node, "bus-range", &len);
+       busrange = of_get_property(node, "bus-range", &len);
        if (busrange == NULL || len != 8) {
                printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
                       node->full_name);
                return;
        }
-       ranges = get_property(node, "ranges", &len);
+       ranges = of_get_property(node, "ranges", &len);
        if (ranges == NULL) {
                printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
                       node->full_name);
@@ -900,7 +910,7 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
        unsigned int size;
        int rlen = 0;
 
-       range = get_property(isa_node, "ranges", &rlen);
+       range = of_get_property(isa_node, "ranges", &rlen);
        if (range == NULL || (rlen < sizeof(struct isa_range))) {
                printk(KERN_ERR "no ISA ranges or unexpected isa range size,"
                       "mapping 64k\n");
@@ -947,7 +957,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
        int rlen = 0;
        int memno = 0;
        struct resource *res;
-       int np, na = prom_n_addr_cells(dev);
+       int np, na = of_n_addr_cells(dev);
        unsigned long pci_addr, cpu_phys_addr;
 
        np = na + 5;
@@ -960,7 +970,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
         *                      (size depending on dev->n_addr_cells)
         *   cells 4+5 or 5+6:  the size of the range
         */
-       ranges = get_property(dev, "ranges", &rlen);
+       ranges = of_get_property(dev, "ranges", &rlen);
        if (ranges == NULL)
                return;
        hose->io_base_phys = 0;
index 68df018dae0ea63b03fbbdcb8df2921a0be70ab4..d7d36df9c053fb36c7ccbf1c763d7e15234980a0 100644 (file)
@@ -40,7 +40,8 @@
 static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
 {
        struct pci_controller *phb = data;
-       const int *type = get_property(dn, "ibm,pci-config-space-type", NULL);
+       const int *type =
+               of_get_property(dn, "ibm,pci-config-space-type", NULL);
        const u32 *regs;
        struct pci_dn *pdn;
 
@@ -54,14 +55,14 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
        dn->data = pdn;
        pdn->node = dn;
        pdn->phb = phb;
-       regs = get_property(dn, "reg", NULL);
+       regs = of_get_property(dn, "reg", NULL);
        if (regs) {
                /* First register entry is addr (00BBSS00)  */
                pdn->busno = (regs[0] >> 16) & 0xff;
                pdn->devfn = (regs[0] >> 8) & 0xff;
        }
        if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-               const u32 *busp = get_property(dn, "linux,subbus", NULL);
+               const u32 *busp = of_get_property(dn, "linux,subbus", NULL);
                if (busp)
                        pdn->bussubno = *busp;
        }
@@ -100,7 +101,7 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
                u32 class;
 
                nextdn = NULL;
-               classp = get_property(dn, "class-code", NULL);
+               classp = of_get_property(dn, "class-code", NULL);
                class = classp ? *classp : 0;
 
                if (pre && ((ret = pre(dn, data)) != NULL))
index 2f8e9c02c92a7142ea43e76f850c09807165624f..ff252aaead122edd17354a3b4716223eea2fecba 100644 (file)
@@ -20,7 +20,6 @@
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/ide.h>
 #include <asm/atomic.h>
 #include <asm/checksum.h>
 #include <asm/pgtable.h>
index e53b2988d1bfc9144a1771ab9585fa21c4e568e7..e509aae2feb37925a17b10bef5735dccd0b1be60 100644 (file)
@@ -305,9 +305,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
                set_dabr(new->thread.dabr);
                __get_cpu_var(current_dabr) = new->thread.dabr;
        }
-
-       flush_tlb_pending();
-#endif
+#endif /* CONFIG_PPC64 */
 
        new_thread = &new->thread;
        old_thread = &current->thread;
@@ -402,11 +400,11 @@ static void printbits(unsigned long val, struct regbit *bits)
 }
 
 #ifdef CONFIG_PPC64
-#define REG            "%016lX"
+#define REG            "%016lx"
 #define REGS_PER_LINE  4
 #define LAST_VOLATILE  13
 #else
-#define REG            "%08lX"
+#define REG            "%08lx"
 #define REGS_PER_LINE  8
 #define LAST_VOLATILE  12
 #endif
@@ -421,7 +419,7 @@ void show_regs(struct pt_regs * regs)
               regs, regs->trap, print_tainted(), init_utsname()->release);
        printk("MSR: "REG" ", regs->msr);
        printbits(regs->msr, msr_bits);
-       printk("  CR: %08lX  XER: %08lX\n", regs->ccr, regs->xer);
+       printk("  CR: %08lx  XER: %08lx\n", regs->ccr, regs->xer);
        trap = TRAP(regs);
        if (trap == 0x300 || trap == 0x600)
                printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr);
@@ -572,7 +570,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        kregs->nip = *((unsigned long *)ret_from_fork);
 #else
        kregs->nip = (unsigned long)ret_from_fork;
-       p->thread.last_syscall = -1;
 #endif
 
        return 0;
@@ -823,6 +820,35 @@ out:
        return error;
 }
 
+#ifdef CONFIG_IRQSTACKS
+static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
+                                 unsigned long nbytes)
+{
+       unsigned long stack_page;
+       unsigned long cpu = task_cpu(p);
+
+       /*
+        * Avoid crashing if the stack has overflowed and corrupted
+        * task_cpu(p), which is in the thread_info struct.
+        */
+       if (cpu < NR_CPUS && cpu_possible(cpu)) {
+               stack_page = (unsigned long) hardirq_ctx[cpu];
+               if (sp >= stack_page + sizeof(struct thread_struct)
+                   && sp <= stack_page + THREAD_SIZE - nbytes)
+                       return 1;
+
+               stack_page = (unsigned long) softirq_ctx[cpu];
+               if (sp >= stack_page + sizeof(struct thread_struct)
+                   && sp <= stack_page + THREAD_SIZE - nbytes)
+                       return 1;
+       }
+       return 0;
+}
+
+#else
+#define valid_irq_stack(sp, p, nb)     0
+#endif /* CONFIG_IRQSTACKS */
+
 int validate_sp(unsigned long sp, struct task_struct *p,
                       unsigned long nbytes)
 {
@@ -832,19 +858,7 @@ int validate_sp(unsigned long sp, struct task_struct *p,
            && sp <= stack_page + THREAD_SIZE - nbytes)
                return 1;
 
-#ifdef CONFIG_IRQSTACKS
-       stack_page = (unsigned long) hardirq_ctx[task_cpu(p)];
-       if (sp >= stack_page + sizeof(struct thread_struct)
-           && sp <= stack_page + THREAD_SIZE - nbytes)
-               return 1;
-
-       stack_page = (unsigned long) softirq_ctx[task_cpu(p)];
-       if (sp >= stack_page + sizeof(struct thread_struct)
-           && sp <= stack_page + THREAD_SIZE - nbytes)
-               return 1;
-#endif
-
-       return 0;
+       return valid_irq_stack(sp, p, nbytes);
 }
 
 #ifdef CONFIG_PPC64
index 8d52b23348bd0b6cb2322fc9f87d626914268a51..caef555f2dc06a1f1b20e225d3b272d36c378ee9 100644 (file)
@@ -390,18 +390,19 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
                if (allnextpp) {
                        pp->name = "name";
                        pp->length = sz;
-                       pp->value = (unsigned char *)(pp + 1);
+                       pp->value = pp + 1;
                        *prev_pp = pp;
                        prev_pp = &pp->next;
                        memcpy(pp->value, ps, sz - 1);
                        ((char *)pp->value)[sz - 1] = 0;
-                       DBG("fixed up name for %s -> %s\n", pathp, pp->value);
+                       DBG("fixed up name for %s -> %s\n", pathp,
+                               (char *)pp->value);
                }
        }
        if (allnextpp) {
                *prev_pp = NULL;
-               np->name = get_property(np, "name", NULL);
-               np->type = get_property(np, "device_type", NULL);
+               np->name = of_get_property(np, "name", NULL);
+               np->type = of_get_property(np, "device_type", NULL);
 
                if (!np->name)
                        np->name = "<NULL>";
@@ -719,6 +720,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
                                            const char *uname, int depth, void *data)
 {
        unsigned long *lprop;
+       u32 *prop;
        unsigned long l;
        char *p;
 
@@ -760,6 +762,22 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
                crashk_res.end = crashk_res.start + *lprop - 1;
 #endif
 
+#ifdef CONFIG_BLK_DEV_INITRD
+       DBG("Looking for initrd properties... ");
+       prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
+       if (prop) {
+               initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
+               prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
+               if (prop) {
+                       initrd_end = (unsigned long)__va(of_read_ulong(prop, l/4));
+                       initrd_below_start_ok = 1;
+               } else {
+                       initrd_start = 0;
+               }
+       }
+       DBG("initrd_start=0x%lx  initrd_end=0x%lx\n", initrd_start, initrd_end);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
        /* Retreive command line */
        p = of_get_flat_dt_prop(node, "bootargs", &l);
        if (p != NULL && l > 0)
@@ -926,6 +944,12 @@ static void __init early_reserve_mem(void)
        self_size = initial_boot_params->totalsize;
        lmb_reserve(self_base, self_size);
 
+#ifdef CONFIG_BLK_DEV_INITRD
+       /* then reserve the initrd, if any */
+       if (initrd_start && (initrd_end > initrd_start))
+               lmb_reserve(__pa(initrd_start), initrd_end - initrd_start);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
 #ifdef CONFIG_PPC32
        /* 
         * Handle the case where we might be booting from an old kexec
@@ -954,9 +978,6 @@ static void __init early_reserve_mem(void)
                size = *(reserve_map++);
                if (size == 0)
                        break;
-               /* skip if the reservation is for the blob */
-               if (base == self_base && size == self_size)
-                       continue;
                DBG("reserving: %llx -> %llx\n", base, size);
                lmb_reserve(base, size);
        }
@@ -1021,102 +1042,46 @@ void __init early_init_devtree(void *params)
 
 #undef printk
 
-int
-prom_n_addr_cells(struct device_node* np)
+int of_n_addr_cells(struct device_node* np)
 {
        const int *ip;
        do {
                if (np->parent)
                        np = np->parent;
-               ip = get_property(np, "#address-cells", NULL);
+               ip = of_get_property(np, "#address-cells", NULL);
                if (ip != NULL)
                        return *ip;
        } while (np->parent);
        /* No #address-cells property for the root node, default to 1 */
        return 1;
 }
-EXPORT_SYMBOL(prom_n_addr_cells);
+EXPORT_SYMBOL(of_n_addr_cells);
 
-int
-prom_n_size_cells(struct device_node* np)
+int of_n_size_cells(struct device_node* np)
 {
        const int* ip;
        do {
                if (np->parent)
                        np = np->parent;
-               ip = get_property(np, "#size-cells", NULL);
+               ip = of_get_property(np, "#size-cells", NULL);
                if (ip != NULL)
                        return *ip;
        } while (np->parent);
        /* No #size-cells property for the root node, default to 1 */
        return 1;
 }
-EXPORT_SYMBOL(prom_n_size_cells);
-
-/**
- * Construct and return a list of the device_nodes with a given name.
- */
-struct device_node *find_devices(const char *name)
-{
-       struct device_node *head, **prevp, *np;
-
-       prevp = &head;
-       for (np = allnodes; np != 0; np = np->allnext) {
-               if (np->name != 0 && strcasecmp(np->name, name) == 0) {
-                       *prevp = np;
-                       prevp = &np->next;
-               }
-       }
-       *prevp = NULL;
-       return head;
-}
-EXPORT_SYMBOL(find_devices);
-
-/**
- * Construct and return a list of the device_nodes with a given type.
- */
-struct device_node *find_type_devices(const char *type)
-{
-       struct device_node *head, **prevp, *np;
-
-       prevp = &head;
-       for (np = allnodes; np != 0; np = np->allnext) {
-               if (np->type != 0 && strcasecmp(np->type, type) == 0) {
-                       *prevp = np;
-                       prevp = &np->next;
-               }
-       }
-       *prevp = NULL;
-       return head;
-}
-EXPORT_SYMBOL(find_type_devices);
-
-/**
- * Returns all nodes linked together
- */
-struct device_node *find_all_nodes(void)
-{
-       struct device_node *head, **prevp, *np;
-
-       prevp = &head;
-       for (np = allnodes; np != 0; np = np->allnext) {
-               *prevp = np;
-               prevp = &np->next;
-       }
-       *prevp = NULL;
-       return head;
-}
-EXPORT_SYMBOL(find_all_nodes);
+EXPORT_SYMBOL(of_n_size_cells);
 
 /** Checks if the given "compat" string matches one of the strings in
  * the device's "compatible" property
  */
-int device_is_compatible(const struct device_node *device, const char *compat)
+int of_device_is_compatible(const struct device_node *device,
+               const char *compat)
 {
        const char* cp;
        int cplen, l;
 
-       cp = get_property(device, "compatible", &cplen);
+       cp = of_get_property(device, "compatible", &cplen);
        if (cp == NULL)
                return 0;
        while (cplen > 0) {
@@ -1129,7 +1094,7 @@ int device_is_compatible(const struct device_node *device, const char *compat)
 
        return 0;
 }
-EXPORT_SYMBOL(device_is_compatible);
+EXPORT_SYMBOL(of_device_is_compatible);
 
 
 /**
@@ -1143,51 +1108,13 @@ int machine_is_compatible(const char *compat)
 
        root = of_find_node_by_path("/");
        if (root) {
-               rc = device_is_compatible(root, compat);
+               rc = of_device_is_compatible(root, compat);
                of_node_put(root);
        }
        return rc;
 }
 EXPORT_SYMBOL(machine_is_compatible);
 
-/**
- * Construct and return a list of the device_nodes with a given type
- * and compatible property.
- */
-struct device_node *find_compatible_devices(const char *type,
-                                           const char *compat)
-{
-       struct device_node *head, **prevp, *np;
-
-       prevp = &head;
-       for (np = allnodes; np != 0; np = np->allnext) {
-               if (type != NULL
-                   && !(np->type != 0 && strcasecmp(np->type, type) == 0))
-                       continue;
-               if (device_is_compatible(np, compat)) {
-                       *prevp = np;
-                       prevp = &np->next;
-               }
-       }
-       *prevp = NULL;
-       return head;
-}
-EXPORT_SYMBOL(find_compatible_devices);
-
-/**
- * Find the device_node with a given full_name.
- */
-struct device_node *find_path_device(const char *path)
-{
-       struct device_node *np;
-
-       for (np = allnodes; np != 0; np = np->allnext)
-               if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
-                       return np;
-       return NULL;
-}
-EXPORT_SYMBOL(find_path_device);
-
 /*******
  *
  * New implementation of the OF "find" APIs, return a refcounted
@@ -1280,7 +1207,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
                if (type != NULL
                    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
                        continue;
-               if (device_is_compatible(np, compatible) && of_node_get(np))
+               if (of_device_is_compatible(np, compatible) && of_node_get(np))
                        break;
        }
        of_node_put(from);
@@ -1527,8 +1454,8 @@ static int of_finish_dynamic_node(struct device_node *node)
        int err = 0;
        const phandle *ibm_phandle;
 
-       node->name = get_property(node, "name", NULL);
-       node->type = get_property(node, "device_type", NULL);
+       node->name = of_get_property(node, "name", NULL);
+       node->type = of_get_property(node, "device_type", NULL);
 
        if (!parent) {
                err = -ENODEV;
@@ -1542,7 +1469,7 @@ static int of_finish_dynamic_node(struct device_node *node)
                return -ENODEV;
 
        /* fix up new node's linux_phandle field */
-       if ((ibm_phandle = get_property(node, "ibm,phandle", NULL)))
+       if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL)))
                node->linux_phandle = *ibm_phandle;
 
 out:
@@ -1605,13 +1532,13 @@ EXPORT_SYMBOL(of_find_property);
  * Find a property with a given name for a given node
  * and return the value.
  */
-const void *get_property(const struct device_node *np, const char *name,
+const void *of_get_property(const struct device_node *np, const char *name,
                         int *lenp)
 {
        struct property *pp = of_find_property(np,name,lenp);
        return pp ? pp->value : NULL;
 }
-EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(of_get_property);
 
 /*
  * Add a property to a node
@@ -1742,10 +1669,10 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
                /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
                 * fallback to "reg" property and assume no threads
                 */
-               intserv = get_property(np, "ibm,ppc-interrupt-server#s",
+               intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
                                &plen);
                if (intserv == NULL) {
-                       const u32 *reg = get_property(np, "reg", NULL);
+                       const u32 *reg = of_get_property(np, "reg", NULL);
                        if (reg == NULL)
                                continue;
                        if (*reg == hardid) {
index 4fb5938ce6d389b8b01b9eac48a35b37159cd26b..e27d9d1b6e67232b75d9e99c50a70d051b282866 100644 (file)
@@ -2035,39 +2035,50 @@ static void __init fixup_device_tree_maple(void)
 #endif
 
 #ifdef CONFIG_PPC_CHRP
-/* Pegasos and BriQ lacks the "ranges" property in the isa node */
+/*
+ * Pegasos and BriQ lacks the "ranges" property in the isa node
+ * Pegasos needs decimal IRQ 14/15, not hexadecimal
+ */
 static void __init fixup_device_tree_chrp(void)
 {
-       phandle isa;
-       u32 isa_ranges[6];
+       phandle ph;
+       u32 prop[6];
        u32 rloc = 0x01006000; /* IO space; PCI device = 12 */
        char *name;
        int rc;
 
        name = "/pci@80000000/isa@c";
-       isa = call_prom("finddevice", 1, 1, ADDR(name));
-       if (!PHANDLE_VALID(isa)) {
+       ph = call_prom("finddevice", 1, 1, ADDR(name));
+       if (!PHANDLE_VALID(ph)) {
                name = "/pci@ff500000/isa@6";
-               isa = call_prom("finddevice", 1, 1, ADDR(name));
+               ph = call_prom("finddevice", 1, 1, ADDR(name));
                rloc = 0x01003000; /* IO space; PCI device = 6 */
        }
-       if (!PHANDLE_VALID(isa))
-               return;
-
-       rc = prom_getproplen(isa, "ranges");
-       if (rc != 0 && rc != PROM_ERROR)
-               return;
-
-       prom_printf("Fixing up missing ISA range on Pegasos...\n");
+       if (PHANDLE_VALID(ph)) {
+               rc = prom_getproplen(ph, "ranges");
+               if (rc == 0 || rc == PROM_ERROR) {
+                       prom_printf("Fixing up missing ISA range on Pegasos...\n");
+
+                       prop[0] = 0x1;
+                       prop[1] = 0x0;
+                       prop[2] = rloc;
+                       prop[3] = 0x0;
+                       prop[4] = 0x0;
+                       prop[5] = 0x00010000;
+                       prom_setprop(ph, name, "ranges", prop, sizeof(prop));
+               }
+       }
 
-       isa_ranges[0] = 0x1;
-       isa_ranges[1] = 0x0;
-       isa_ranges[2] = rloc;
-       isa_ranges[3] = 0x0;
-       isa_ranges[4] = 0x0;
-       isa_ranges[5] = 0x00010000;
-       prom_setprop(isa, name, "ranges",
-                       isa_ranges, sizeof(isa_ranges));
+       name = "/pci@80000000/ide@C,1";
+       ph = call_prom("finddevice", 1, 1, ADDR(name));
+       if (PHANDLE_VALID(ph)) {
+               prom_printf("Fixing up IDE interrupt on Pegasos...\n");
+               prop[0] = 14;
+               prop[1] = 0x0;
+               prop[2] = 15;
+               prop[3] = 0x0;
+               prom_setprop(ph, name, "interrupts", prop, 4*sizeof(u32));
+       }
 }
 #else
 #define fixup_device_tree_chrp()
index 91b443c9a48857239b35428a85fe86e8953f5f8d..aa40a5307294b2a8442a3f4de0990386065c6b3f 100644 (file)
@@ -68,9 +68,9 @@ static void of_bus_default_count_cells(struct device_node *dev,
                                       int *addrc, int *sizec)
 {
        if (addrc)
-               *addrc = prom_n_addr_cells(dev);
+               *addrc = of_n_addr_cells(dev);
        if (sizec)
-               *sizec = prom_n_size_cells(dev);
+               *sizec = of_n_size_cells(dev);
 }
 
 static u64 of_bus_default_map(u32 *addr, const u32 *range,
@@ -196,7 +196,7 @@ const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
                return NULL;
 
        /* Get "reg" or "assigned-addresses" property */
-       prop = get_property(dev, bus->addresses, &psize);
+       prop = of_get_property(dev, bus->addresses, &psize);
        if (prop == NULL)
                return NULL;
        psize /= 4;
@@ -438,7 +438,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
         * to translate addresses that aren't supposed to be translated in
         * the first place. --BenH.
         */
-       ranges = get_property(parent, "ranges", &rlen);
+       ranges = of_get_property(parent, "ranges", &rlen);
        if (ranges == NULL || rlen == 0) {
                offset = of_read_number(addr, na);
                memset(addr, 0, pna * 4);
@@ -578,7 +578,7 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
                return NULL;
 
        /* Get "reg" or "assigned-addresses" property */
-       prop = get_property(dev, bus->addresses, &psize);
+       prop = of_get_property(dev, bus->addresses, &psize);
        if (prop == NULL)
                return NULL;
        psize /= 4;
@@ -650,17 +650,17 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
        /* busno is always one cell */
        *busno = *(dma_window++);
 
-       prop = get_property(dn, "ibm,#dma-address-cells", NULL);
+       prop = of_get_property(dn, "ibm,#dma-address-cells", NULL);
        if (!prop)
-               prop = get_property(dn, "#address-cells", NULL);
+               prop = of_get_property(dn, "#address-cells", NULL);
 
-       cells = prop ? *(u32 *)prop : prom_n_addr_cells(dn);
+       cells = prop ? *(u32 *)prop : of_n_addr_cells(dn);
        *phys = of_read_number(dma_window, cells);
 
        dma_window += cells;
 
-       prop = get_property(dn, "ibm,#dma-size-cells", NULL);
-       cells = prop ? *(u32 *)prop : prom_n_size_cells(dn);
+       prop = of_get_property(dn, "ibm,#dma-size-cells", NULL);
+       cells = prop ? *(u32 *)prop : of_n_size_cells(dn);
        *size = of_read_number(dma_window, cells);
 }
 
@@ -680,7 +680,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child)
                return NULL;
 
        do {
-               parp = get_property(child, "interrupt-parent", NULL);
+               parp = of_get_property(child, "interrupt-parent", NULL);
                if (parp == NULL)
                        p = of_get_parent(child);
                else {
@@ -691,7 +691,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child)
                }
                of_node_put(child);
                child = p;
-       } while (p && get_property(p, "#interrupt-cells", NULL) == NULL);
+       } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
 
        return p;
 }
@@ -716,7 +716,7 @@ void of_irq_map_init(unsigned int flags)
                struct device_node *np;
 
                for(np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
-                       if (get_property(np, "interrupt-controller", NULL)
+                       if (of_get_property(np, "interrupt-controller", NULL)
                            == NULL)
                                continue;
                        /* Skip /chosen/interrupt-controller */
@@ -755,7 +755,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
         * is none, we are nice and just walk up the tree
         */
        do {
-               tmp = get_property(ipar, "#interrupt-cells", NULL);
+               tmp = of_get_property(ipar, "#interrupt-cells", NULL);
                if (tmp != NULL) {
                        intsize = *tmp;
                        break;
@@ -779,7 +779,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
         */
        old = of_node_get(ipar);
        do {
-               tmp = get_property(old, "#address-cells", NULL);
+               tmp = of_get_property(old, "#address-cells", NULL);
                tnode = of_get_parent(old);
                of_node_put(old);
                old = tnode;
@@ -795,7 +795,8 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
                /* Now check if cursor is an interrupt-controller and if it is
                 * then we are done
                 */
-               if (get_property(ipar, "interrupt-controller", NULL) != NULL) {
+               if (of_get_property(ipar, "interrupt-controller", NULL) !=
+                               NULL) {
                        DBG(" -> got it !\n");
                        memcpy(out_irq->specifier, intspec,
                               intsize * sizeof(u32));
@@ -806,7 +807,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
                }
 
                /* Now look for an interrupt-map */
-               imap = get_property(ipar, "interrupt-map", &imaplen);
+               imap = of_get_property(ipar, "interrupt-map", &imaplen);
                /* No interrupt map, check for an interrupt parent */
                if (imap == NULL) {
                        DBG(" -> no map, getting parent\n");
@@ -816,7 +817,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
                imaplen /= sizeof(u32);
 
                /* Look for a mask */
-               imask = get_property(ipar, "interrupt-map-mask", NULL);
+               imask = of_get_property(ipar, "interrupt-map-mask", NULL);
 
                /* If we were passed no "reg" property and we attempt to parse
                 * an interrupt-map, then #address-cells must be 0.
@@ -863,15 +864,13 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
                        /* Get #interrupt-cells and #address-cells of new
                         * parent
                         */
-                       tmp = get_property(newpar, "#interrupt-cells",
-                                                 NULL);
+                       tmp = of_get_property(newpar, "#interrupt-cells", NULL);
                        if (tmp == NULL) {
                                DBG(" -> parent lacks #interrupt-cells !\n");
                                goto fail;
                        }
                        newintsize = *tmp;
-                       tmp = get_property(newpar, "#address-cells",
-                                                 NULL);
+                       tmp = of_get_property(newpar, "#address-cells", NULL);
                        newaddrsize = (tmp == NULL) ? 0 : *tmp;
 
                        DBG(" -> newintsize=%d, newaddrsize=%d\n",
@@ -928,7 +927,7 @@ static int of_irq_map_oldworld(struct device_node *device, int index,
         * everything together on these)
         */
        while (device) {
-               ints = get_property(device, "AAPL,interrupts", &intlen);
+               ints = of_get_property(device, "AAPL,interrupts", &intlen);
                if (ints != NULL)
                        break;
                device = device->parent;
@@ -970,13 +969,13 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq
                return of_irq_map_oldworld(device, index, out_irq);
 
        /* Get the interrupts property */
-       intspec = get_property(device, "interrupts", &intlen);
+       intspec = of_get_property(device, "interrupts", &intlen);
        if (intspec == NULL)
                return -EINVAL;
        intlen /= sizeof(u32);
 
        /* Get the reg property (if any) */
-       addr = get_property(device, "reg", NULL);
+       addr = of_get_property(device, "reg", NULL);
 
        /* Look for the interrupt parent. */
        p = of_irq_find_parent(device);
@@ -984,7 +983,7 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq
                return -EINVAL;
 
        /* Get size of interrupt specifier */
-       tmp = get_property(p, "#interrupt-cells", NULL);
+       tmp = of_get_property(p, "#interrupt-cells", NULL);
        if (tmp == NULL) {
                of_node_put(p);
                return -EINVAL;
index 6cbf2ae5d7aae8c914e6bb8f8b428c8862fa3f70..190b7ed1dbfb10c0756de46fae00b982fcaab44e 100644 (file)
@@ -450,7 +450,7 @@ static int ppc_rtas_sensors_show(struct seq_file *m, void *v)
                int llen, offs;
 
                sprintf (rstr, SENSOR_PREFIX"%04d", p->token);
-               loc = get_property(rtas_node, rstr, &llen);
+               loc = of_get_property(rtas_node, rstr, &llen);
 
                /* A sensor may have multiple instances */
                for (j = 0, offs = 0; j <= p->quant; j++) {
@@ -477,7 +477,7 @@ static int ppc_rtas_find_all_sensors(void)
        const unsigned int *utmp;
        int len, i;
 
-       utmp = get_property(rtas_node, "rtas-sensors", &len);
+       utmp = of_get_property(rtas_node, "rtas-sensors", &len);
        if (utmp == NULL) {
                printk (KERN_ERR "error: could not get rtas-sensors\n");
                return 1;
index 9d0735a54564cc62e3df51253727028e48eeaa5e..214780798289212eda799ebcbdde8025602e7c53 100644 (file)
@@ -192,18 +192,19 @@ void rtas_progress(char *s, unsigned short hex)
 
        if (display_width == 0) {
                display_width = 0x10;
-               if ((root = find_path_device("/rtas"))) {
-                       if ((p = get_property(root,
+               if ((root = of_find_node_by_path("/rtas"))) {
+                       if ((p = of_get_property(root,
                                        "ibm,display-line-length", NULL)))
                                display_width = *p;
-                       if ((p = get_property(root,
+                       if ((p = of_get_property(root,
                                        "ibm,form-feed", NULL)))
                                form_feed = *p;
-                       if ((p = get_property(root,
+                       if ((p = of_get_property(root,
                                        "ibm,display-number-of-lines", NULL)))
                                display_lines = *p;
-                       row_width = get_property(root,
+                       row_width = of_get_property(root,
                                        "ibm,display-truncation-length", NULL);
+                       of_node_put(root);
                }
                display_character = rtas_token("display-character");
                set_indicator = rtas_token("set-indicator");
@@ -298,7 +299,7 @@ int rtas_token(const char *service)
        const int *tokp;
        if (rtas.dev == NULL)
                return RTAS_UNKNOWN_SERVICE;
-       tokp = get_property(rtas.dev, service, NULL);
+       tokp = of_get_property(rtas.dev, service, NULL);
        return tokp ? *tokp : RTAS_UNKNOWN_SERVICE;
 }
 EXPORT_SYMBOL(rtas_token);
@@ -832,12 +833,12 @@ void __init rtas_initialize(void)
        if (rtas.dev) {
                const u32 *basep, *entryp, *sizep;
 
-               basep = get_property(rtas.dev, "linux,rtas-base", NULL);
-               sizep = get_property(rtas.dev, "rtas-size", NULL);
+               basep = of_get_property(rtas.dev, "linux,rtas-base", NULL);
+               sizep = of_get_property(rtas.dev, "rtas-size", NULL);
                if (basep != NULL && sizep != NULL) {
                        rtas.base = *basep;
                        rtas.size = *sizep;
-                       entryp = get_property(rtas.dev,
+                       entryp = of_get_property(rtas.dev,
                                        "linux,rtas-entry", NULL);
                        if (entryp == NULL) /* Ugh */
                                rtas.entry = rtas.base;
index ace9f4c86e670f7e8a66cec053b553e27317b506..f2286822be0948c5dad8e0df0cd9b80aa4851650 100644 (file)
@@ -60,7 +60,7 @@ static int of_device_available(struct device_node * dn)
 {
         const char *status;
 
-        status = get_property(dn, "status", NULL);
+        status = of_get_property(dn, "status", NULL);
 
         if (!status)
                 return 1;
@@ -177,7 +177,7 @@ struct pci_ops rtas_pci_ops = {
 
 int is_python(struct device_node *dev)
 {
-       const char *model = get_property(dev, "model", NULL);
+       const char *model = of_get_property(dev, "model", NULL);
 
        if (model && strstr(model, "Python"))
                return 1;
@@ -247,7 +247,7 @@ static int phb_set_bus_ranges(struct device_node *dev,
        const int *bus_range;
        unsigned int len;
 
-       bus_range = get_property(dev, "bus-range", &len);
+       bus_range = of_get_property(dev, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                return 1;
        }
@@ -274,7 +274,7 @@ int __devinit rtas_setup_phb(struct pci_controller *phb)
        return 0;
 }
 
-unsigned long __init find_and_init_phbs(void)
+void __init find_and_init_phbs(void)
 {
        struct device_node *node;
        struct pci_controller *phb;
@@ -309,18 +309,16 @@ unsigned long __init find_and_init_phbs(void)
        if (of_chosen) {
                const int *prop;
 
-               prop = get_property(of_chosen,
+               prop = of_get_property(of_chosen,
                                "linux,pci-probe-only", NULL);
                if (prop)
                        pci_probe_only = *prop;
 
-               prop = get_property(of_chosen,
+               prop = of_get_property(of_chosen,
                                "linux,pci-assign-all-buses", NULL);
                if (prop)
                        pci_assign_all_buses = *prop;
        }
-
-       return 0;
 }
 
 /* RPA-specific bits for removing PHBs */
index 89cfaf49d3de8aa3ae8b53cd878ee574929d0be1..370803722e4773f9f69a09e8b2fa8d7ab8d3d3f0 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/delay.h>
 #include <linux/initrd.h>
 #include <linux/platform_device.h>
-#include <linux/ide.h>
 #include <linux/seq_file.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
@@ -304,26 +303,8 @@ struct seq_operations cpuinfo_op = {
 void __init check_for_initrd(void)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
-       const unsigned int *prop;
-       int len;
-
-       DBG(" -> check_for_initrd()\n");
-
-       if (of_chosen) {
-               prop = get_property(of_chosen, "linux,initrd-start", &len);
-               if (prop != NULL) {
-                       initrd_start = (unsigned long)
-                               __va(of_read_ulong(prop, len / 4));
-                       prop = get_property(of_chosen,
-                                       "linux,initrd-end", &len);
-                       if (prop != NULL) {
-                               initrd_end = (unsigned long)
-                                       __va(of_read_ulong(prop, len / 4));
-                               initrd_below_start_ok = 1;
-                       } else
-                               initrd_start = 0;
-               }
-       }
+       DBG(" -> check_for_initrd()  initrd_start=0x%lx  initrd_end=0x%lx\n",
+           initrd_start, initrd_end);
 
        /* If we were passed an initrd, set the ROOT_DEV properly if the values
         * look sensible. If not, clear initrd reference.
@@ -371,11 +352,12 @@ void __init smp_setup_cpu_maps(void)
                const int *intserv;
                int j, len = sizeof(u32), nthreads = 1;
 
-               intserv = get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+               intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s",
+                               &len);
                if (intserv)
                        nthreads = len / sizeof(int);
                else {
-                       intserv = get_property(dn, "reg", NULL);
+                       intserv = of_get_property(dn, "reg", NULL);
                        if (!intserv)
                                intserv = &cpu; /* assume logical == phys */
                }
@@ -398,10 +380,10 @@ void __init smp_setup_cpu_maps(void)
                int num_addr_cell, num_size_cell, maxcpus;
                const unsigned int *ireg;
 
-               num_addr_cell = prom_n_addr_cells(dn);
-               num_size_cell = prom_n_size_cells(dn);
+               num_addr_cell = of_n_addr_cells(dn);
+               num_size_cell = of_n_size_cells(dn);
 
-               ireg = get_property(dn, "ibm,lrdr-capacity", NULL);
+               ireg = of_get_property(dn, "ibm,lrdr-capacity", NULL);
 
                if (!ireg)
                        goto out;
@@ -496,11 +478,39 @@ void probe_machine(void)
        printk(KERN_INFO "Using %s machine description\n", ppc_md.name);
 }
 
+/* Match a class of boards, not a specific device configuration. */
 int check_legacy_ioport(unsigned long base_port)
 {
-       if (ppc_md.check_legacy_ioport == NULL)
-               return 0;
-       return ppc_md.check_legacy_ioport(base_port);
+       struct device_node *parent, *np = NULL;
+       int ret = -ENODEV;
+
+       switch(base_port) {
+       case I8042_DATA_REG:
+               np = of_find_node_by_type(NULL, "8042");
+               break;
+       case FDC_BASE: /* FDC1 */
+               np = of_find_node_by_type(NULL, "fdc");
+               break;
+#ifdef CONFIG_PPC_PREP
+       case _PIDXR:
+       case _PNPWRP:
+       case PNPBIOS_BASE:
+               /* implement me */
+#endif
+       default:
+               /* ipmi is supposed to fail here */
+               break;
+       }
+       if (!np)
+               return ret;
+       parent = of_get_parent(np);
+       if (parent) {
+               if (strcmp(parent->type, "isa") == 0)
+                       ret = 0;
+               of_node_put(parent);
+       }
+       of_node_put(np);
+       return ret;
 }
 EXPORT_SYMBOL(check_legacy_ioport);
 
index 44a6a3c47feb5a4f666be6ba4a0c402ffbe74526..35f8f443c14f6c9dd383d967889577c9588d4363 100644 (file)
@@ -92,7 +92,8 @@ unsigned long __init early_init(unsigned long dt_ptr)
 
        /* First zero the BSS -- use memset_io, some platforms don't have
         * caches on yet */
-       memset_io((void __iomem *)PTRRELOC(&__bss_start), 0, _end - __bss_start);
+       memset_io((void __iomem *)PTRRELOC(&__bss_start), 0,
+                       __bss_stop - __bss_start);
 
        /*
         * Identify the CPU type and fix up code sections
@@ -195,18 +196,22 @@ EXPORT_SYMBOL(nvram_sync);
 
 #endif /* CONFIG_NVRAM */
 
-static struct cpu cpu_devices[NR_CPUS];
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
 int __init ppc_init(void)
 {
-       int i;
+       int cpu;
 
        /* clear the progress line */
-       if ( ppc_md.progress ) ppc_md.progress("             ", 0xffff);
+       if (ppc_md.progress)
+               ppc_md.progress("             ", 0xffff);
 
        /* register CPU devices */
-       for_each_possible_cpu(i)
-               register_cpu(&cpu_devices[i], i);
+       for_each_possible_cpu(cpu) {
+               struct cpu *c = &per_cpu(cpu_devices, cpu);
+               c->hotpluggable = 1;
+               register_cpu(c, cpu);
+       }
 
        /* call platform init */
        if (ppc_md.init != NULL) {
index 3733de30e84dc07f6a52df31bf3f4506d31ca3ca..22083ce3cc30c9106766afc641b8436df42c3e84 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/initrd.h>
-#include <linux/ide.h>
 #include <linux/seq_file.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
@@ -110,7 +109,7 @@ static void check_smt_enabled(void)
        dn = of_find_node_by_path("/options");
 
        if (dn) {
-               smt_option = get_property(dn, "ibm,smt-enabled", NULL);
+               smt_option = of_get_property(dn, "ibm,smt-enabled", NULL);
 
                 if (smt_option) {
                        if (!strcmp(smt_option, "on"))
@@ -305,10 +304,10 @@ static void __init initialize_cache_info(void)
 
                        size = 0;
                        lsize = cur_cpu_spec->dcache_bsize;
-                       sizep = get_property(np, "d-cache-size", NULL);
+                       sizep = of_get_property(np, "d-cache-size", NULL);
                        if (sizep != NULL)
                                size = *sizep;
-                       lsizep = get_property(np, dc, NULL);
+                       lsizep = of_get_property(np, dc, NULL);
                        if (lsizep != NULL)
                                lsize = *lsizep;
                        if (sizep == 0 || lsizep == 0)
@@ -322,10 +321,10 @@ static void __init initialize_cache_info(void)
 
                        size = 0;
                        lsize = cur_cpu_spec->icache_bsize;
-                       sizep = get_property(np, "i-cache-size", NULL);
+                       sizep = of_get_property(np, "i-cache-size", NULL);
                        if (sizep != NULL)
                                size = *sizep;
-                       lsizep = get_property(np, ic, NULL);
+                       lsizep = of_get_property(np, ic, NULL);
                        if (lsizep != NULL)
                                lsize = *lsizep;
                        if (sizep == 0 || lsizep == 0)
index 924d692bc8f9249fd5b0feb091b195bfd08fbfa7..d8e503b2e1af8d6ed9ece6358b61f083eeb2e712 100644 (file)
@@ -428,10 +428,6 @@ void generic_mach_cpu_die(void)
        smp_wmb();
        while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
                cpu_relax();
-
-#ifdef CONFIG_PPC64
-       flush_tlb_pending();
-#endif
        cpu_set(cpu, cpu_online_map);
        local_irq_enable();
 }
index 673e8d9df7f58e0067d9eee854c5e789741d90e0..047246ad4f6559887756b780abff120c36ceb417 100644 (file)
 #include <asm/ppc-pci.h>
 #include <asm/syscalls.h>
 
-/* readdir & getdents */
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
-#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
-
 struct old_linux_dirent32 {
        u32             d_ino;
        u32             d_offset;
index d57818aea081b2a16e4b179d085cf53cdb39c033..933e214c33e8a835ed1614afa399b37b9506ceda 100644 (file)
@@ -66,16 +66,17 @@ static int __init smt_setup(void)
        if (!cpu_has_feature(CPU_FTR_SMT))
                return -ENODEV;
 
-       options = find_path_device("/options");
+       options = of_find_node_by_path("/options");
        if (!options)
                return -ENODEV;
 
-       val = get_property(options, "ibm,smt-snooze-delay", NULL);
+       val = of_get_property(options, "ibm,smt-snooze-delay", NULL);
        if (!smt_snooze_cmdline && val) {
                for_each_possible_cpu(cpu)
                        per_cpu(smt_snooze_delay, cpu) = *val;
        }
 
+       of_node_put(options);
        return 0;
 }
 __initcall(smt_setup);
@@ -189,12 +190,12 @@ SYSFS_PMCSETUP(purr, SPRN_PURR);
 SYSFS_PMCSETUP(spurr, SPRN_SPURR);
 SYSFS_PMCSETUP(dscr, SPRN_DSCR);
 
-SYSFS_PMCSETUP(pa6t_pmc0, PA6T_SPRN_PMC0);
-SYSFS_PMCSETUP(pa6t_pmc1, PA6T_SPRN_PMC1);
-SYSFS_PMCSETUP(pa6t_pmc2, PA6T_SPRN_PMC2);
-SYSFS_PMCSETUP(pa6t_pmc3, PA6T_SPRN_PMC3);
-SYSFS_PMCSETUP(pa6t_pmc4, PA6T_SPRN_PMC4);
-SYSFS_PMCSETUP(pa6t_pmc5, PA6T_SPRN_PMC5);
+SYSFS_PMCSETUP(pa6t_pmc0, SPRN_PA6T_PMC0);
+SYSFS_PMCSETUP(pa6t_pmc1, SPRN_PA6T_PMC1);
+SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2);
+SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3);
+SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4);
+SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5);
 
 
 static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
index f6f0c6b07c4cf335e41357def28b7388bf07d793..7cedef8f5f70c2ae397c057746200a02da31f5cf 100644 (file)
@@ -834,7 +834,7 @@ static int __init get_freq(char *name, int cells, unsigned long *val)
        cpu = of_find_node_by_type(NULL, "cpu");
 
        if (cpu) {
-               fp = get_property(cpu, name, NULL);
+               fp = of_get_property(cpu, name, NULL);
                if (fp) {
                        found = 1;
                        *val = of_read_ulong(fp, cells);
index 17724fb2067f4a2195f4e30548b62362f2c0bfd4..f7862224fe85e92748a8f1e28a0b7ef71a57b330 100644 (file)
@@ -90,21 +90,11 @@ EXPORT_SYMBOL(unregister_die_notifier);
  * Trap & Exception support
  */
 
-static DEFINE_SPINLOCK(die_lock);
-
-int die(const char *str, struct pt_regs *regs, long err)
-{
-       static int die_counter;
-
-       if (debugger(regs))
-               return 1;
-
-       console_verbose();
-       spin_lock_irq(&die_lock);
-       bust_spinlocks(1);
 #ifdef CONFIG_PMAC_BACKLIGHT
+static void pmac_backlight_unblank(void)
+{
        mutex_lock(&pmac_backlight_mutex);
-       if (machine_is(powermac) && pmac_backlight) {
+       if (pmac_backlight) {
                struct backlight_properties *props;
 
                props = &pmac_backlight->props;
@@ -113,26 +103,67 @@ int die(const char *str, struct pt_regs *regs, long err)
                backlight_update_status(pmac_backlight);
        }
        mutex_unlock(&pmac_backlight_mutex);
+}
+#else
+static inline void pmac_backlight_unblank(void) { }
 #endif
-       printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
+
+int die(const char *str, struct pt_regs *regs, long err)
+{
+       static struct {
+               spinlock_t lock;
+               u32 lock_owner;
+               int lock_owner_depth;
+       } die = {
+               .lock =                 __SPIN_LOCK_UNLOCKED(die.lock),
+               .lock_owner =           -1,
+               .lock_owner_depth =     0
+       };
+       static int die_counter;
+       unsigned long flags;
+
+       if (debugger(regs))
+               return 1;
+
+       oops_enter();
+
+       if (die.lock_owner != raw_smp_processor_id()) {
+               console_verbose();
+               spin_lock_irqsave(&die.lock, flags);
+               die.lock_owner = smp_processor_id();
+               die.lock_owner_depth = 0;
+               bust_spinlocks(1);
+               if (machine_is(powermac))
+                       pmac_backlight_unblank();
+       } else {
+               local_save_flags(flags);
+       }
+
+       if (++die.lock_owner_depth < 3) {
+               printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
 #ifdef CONFIG_PREEMPT
-       printk("PREEMPT ");
+               printk("PREEMPT ");
 #endif
 #ifdef CONFIG_SMP
-       printk("SMP NR_CPUS=%d ", NR_CPUS);
+               printk("SMP NR_CPUS=%d ", NR_CPUS);
 #endif
 #ifdef CONFIG_DEBUG_PAGEALLOC
-       printk("DEBUG_PAGEALLOC ");
+               printk("DEBUG_PAGEALLOC ");
 #endif
 #ifdef CONFIG_NUMA
-       printk("NUMA ");
+               printk("NUMA ");
 #endif
-       printk("%s\n", ppc_md.name ? "" : ppc_md.name);
+               printk("%s\n", ppc_md.name ? ppc_md.name : "");
+
+               print_modules();
+               show_regs(regs);
+       } else {
+               printk("Recursive die() failure, output suppressed\n");
+       }
 
-       print_modules();
-       show_regs(regs);
        bust_spinlocks(0);
-       spin_unlock_irq(&die_lock);
+       die.lock_owner = -1;
+       spin_unlock_irqrestore(&die.lock, flags);
 
        if (kexec_should_crash(current) ||
                kexec_sr_activated(smp_processor_id()))
@@ -145,6 +176,7 @@ int die(const char *str, struct pt_regs *regs, long err)
        if (panic_on_oops)
                panic("Fatal exception");
 
+       oops_exit();
        do_exit(err);
 
        return 0;
index 2968ffeafdb68c06f6d1d7ff96dfa8e4bab4578d..9eaefac5053f395e4b333e580d2aeb20472833aa 100644 (file)
@@ -81,7 +81,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
                struct iommu_table *tbl;
                unsigned long offset, size;
 
-               dma_window = get_property(dev->dev.archdata.of_node,
+               dma_window = of_get_property(dev->dev.archdata.of_node,
                                          "ibm,my-dma-window", NULL);
                if (!dma_window)
                        return NULL;
@@ -226,7 +226,7 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
                return NULL;
        }
 
-       unit_address = get_property(of_node, "reg", NULL);
+       unit_address = of_get_property(of_node, "reg", NULL);
        if (unit_address == NULL) {
                printk(KERN_WARNING "%s: node %s missing 'reg'\n",
                                __FUNCTION__,
@@ -246,7 +246,7 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
        viodev->type = of_node->type;
        viodev->unit_address = *unit_address;
        if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-               unit_address = get_property(of_node,
+               unit_address = of_get_property(of_node,
                                "linux,unit_address", NULL);
                if (unit_address != NULL)
                        viodev->unit_address = *unit_address;
@@ -308,7 +308,7 @@ static int __init vio_bus_init(void)
                return err;
        }
 
-       node_vroot = find_devices("vdevice");
+       node_vroot = of_find_node_by_name(NULL, "vdevice");
        if (node_vroot) {
                struct device_node *of_node;
 
@@ -322,6 +322,7 @@ static int __init vio_bus_init(void)
                                        __FUNCTION__, of_node);
                        vio_register_device_node(of_node);
                }
+               of_node_put(node_vroot);
        }
 
        return 0;
@@ -377,7 +378,7 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp,
        dn = dev->archdata.of_node;
        if (!dn)
                return -ENODEV;
-       cp = get_property(dn, "compatible", &length);
+       cp = of_get_property(dn, "compatible", &length);
        if (!cp)
                return -ENODEV;
 
@@ -406,12 +407,12 @@ struct bus_type vio_bus_type = {
  * @which:     The property/attribute to be extracted.
  * @length:    Pointer to length of returned data size (unused if NULL).
  *
- * Calls prom.c's get_property() to return the value of the
+ * Calls prom.c's of_get_property() to return the value of the
  * attribute specified by @which
 */
 const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length)
 {
-       return get_property(vdev->dev.archdata.of_node, which, length);
+       return of_get_property(vdev->dev.archdata.of_node, which, length);
 }
 EXPORT_SYMBOL(vio_get_attribute);
 
@@ -443,7 +444,7 @@ struct vio_dev *vio_find_node(struct device_node *vnode)
        char kobj_name[BUS_ID_SIZE];
 
        /* construct the kobject name from the device node */
-       unit_address = get_property(vnode, "reg", NULL);
+       unit_address = of_get_property(vnode, "reg", NULL);
        if (!unit_address)
                return NULL;
        snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
index a6b54cb97c4912a60a85bb41f8a7ce05a93becfb..25ec5378afa454232704d48c604e968efdd33cc0 100644 (file)
@@ -24,7 +24,7 @@ _GLOBAL(__copy_tofrom_user)
        dcbt    0,r4
        beq     .Lcopy_page_4K
        andi.   r6,r6,7
-       mtcrf   0x01,r5
+       PPC_MTOCRF      0x01,r5
        blt     cr1,.Lshort_copy
        bne     .Ldst_unaligned
 .Ldst_aligned:
@@ -135,7 +135,7 @@ _GLOBAL(__copy_tofrom_user)
        b       .Ldo_tail
 
 .Ldst_unaligned:
-       mtcrf   0x01,r6         /* put #bytes to 8B bdry into cr7 */
+       PPC_MTOCRF      0x01,r6         /* put #bytes to 8B bdry into cr7 */
        subf    r5,r6,r5
        li      r7,0
        cmpldi  r1,r5,16
@@ -150,7 +150,7 @@ _GLOBAL(__copy_tofrom_user)
 2:     bf      cr7*4+1,3f
 37:    lwzx    r0,r7,r4
 83:    stwx    r0,r7,r3
-3:     mtcrf   0x01,r5
+3:     PPC_MTOCRF      0x01,r5
        add     r4,r6,r4
        add     r3,r6,r3
        b       .Ldst_aligned
index 80b482ca30dfac7e8098e0d1b8cafd3ecc82656c..79d0fa3a470d9eaf4f0811652775e16c7f1634ec 100644 (file)
@@ -43,9 +43,11 @@ void __spin_yield(raw_spinlock_t *lock)
        if (firmware_has_feature(FW_FEATURE_ISERIES))
                HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
                        ((u64)holder_cpu << 32) | yield_count);
+#ifdef CONFIG_PPC_SPLPAR
        else
                plpar_hcall_norets(H_CONFER,
                        get_hard_smp_processor_id(holder_cpu), yield_count);
+#endif
 }
 
 /*
@@ -72,9 +74,11 @@ void __rw_yield(raw_rwlock_t *rw)
        if (firmware_has_feature(FW_FEATURE_ISERIES))
                HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
                        ((u64)holder_cpu << 32) | yield_count);
+#ifdef CONFIG_PPC_SPLPAR
        else
                plpar_hcall_norets(H_CONFER,
                        get_hard_smp_processor_id(holder_cpu), yield_count);
+#endif
 }
 #endif
 
index 68df20283ff508c4ca28305ac7f29b6f56183765..11ce045e21fd1ab43518e6a58f8986d9390cb760 100644 (file)
@@ -19,7 +19,7 @@ _GLOBAL(memset)
        rlwimi  r4,r4,16,0,15
        cmplw   cr1,r5,r0               /* do we get that far? */
        rldimi  r4,r4,32,0
-       mtcrf   1,r0
+       PPC_MTOCRF      1,r0
        mr      r6,r3
        blt     cr1,8f
        beq+    3f                      /* if already 8-byte aligned */
@@ -49,7 +49,7 @@ _GLOBAL(memset)
        bdnz    4b
 5:     srwi.   r0,r5,3
        clrlwi  r5,r5,29
-       mtcrf   1,r0
+       PPC_MTOCRF      1,r0
        beq     8f
        bf      29,6f
        std     r4,0(r6)
@@ -65,7 +65,7 @@ _GLOBAL(memset)
        std     r4,0(r6)
        addi    r6,r6,8
 8:     cmpwi   r5,0
-       mtcrf   1,r5
+       PPC_MTOCRF      1,r5
        beqlr+
        bf      29,9f
        stw     r4,0(r6)
index 7173ba98f427d293fc6f66727a4448be2da40ff2..3f131129d1c1a496607637f39eb1f563596768d0 100644 (file)
@@ -12,7 +12,7 @@
        .align  7
 _GLOBAL(memcpy)
        std     r3,48(r1)       /* save destination pointer for return value */
-       mtcrf   0x01,r5
+       PPC_MTOCRF      0x01,r5
        cmpldi  cr1,r5,16
        neg     r6,r3           # LS 3 bits = # bytes to 8-byte dest bdry
        andi.   r6,r6,7
@@ -128,7 +128,7 @@ _GLOBAL(memcpy)
        b       .Ldo_tail
 
 .Ldst_unaligned:
-       mtcrf   0x01,r6         # put #bytes to 8B bdry into cr7
+       PPC_MTOCRF      0x01,r6         # put #bytes to 8B bdry into cr7
        subf    r5,r6,r5
        li      r7,0
        cmpldi  r1,r5,16
@@ -143,7 +143,7 @@ _GLOBAL(memcpy)
 2:     bf      cr7*4+1,3f
        lwzx    r0,r7,r4
        stwx    r0,r7,r3
-3:     mtcrf   0x01,r5
+3:     PPC_MTOCRF      0x01,r5
        add     r4,r6,r4
        add     r3,r6,r3
        b       .Ldst_aligned
index 7e8ded051b5b3fcc505c2ea8449422c6f42b6e61..4aae0c3876452919d17b95322682ea7486d0beb6 100644 (file)
@@ -54,7 +54,7 @@ static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs)
  */
 int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 {
-       unsigned int opcode, rd;
+       unsigned int opcode, rs, rb, rd, spr;
        unsigned long int imm;
 
        opcode = instr >> 26;
@@ -152,6 +152,49 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                                regs->nip &= 0xffffffffUL;
                        return 1;
 #endif
+               case 0x26:      /* mfcr */
+                       regs->gpr[rd] = regs->ccr;
+                       regs->gpr[rd] &= 0xffffffffUL;
+                       goto mtspr_out;
+               case 0x2a6:     /* mfspr */
+                       spr = (instr >> 11) & 0x3ff;
+                       switch (spr) {
+                       case 0x20:      /* mfxer */
+                               regs->gpr[rd] = regs->xer;
+                               regs->gpr[rd] &= 0xffffffffUL;
+                               goto mtspr_out;
+                       case 0x100:     /* mflr */
+                               regs->gpr[rd] = regs->link;
+                               goto mtspr_out;
+                       case 0x120:     /* mfctr */
+                               regs->gpr[rd] = regs->ctr;
+                               goto mtspr_out;
+                       }
+                       break;
+               case 0x378:     /* orx */
+                       rs = (instr >> 21) & 0x1f;
+                       rb = (instr >> 11) & 0x1f;
+                       if (rs == rb) {         /* mr */
+                               rd = (instr >> 16) & 0x1f;
+                               regs->gpr[rd] = regs->gpr[rs];
+                               goto mtspr_out;
+                       }
+                       break;
+               case 0x3a6:     /* mtspr */
+                       spr = (instr >> 11) & 0x3ff;
+                       switch (spr) {
+                       case 0x20:      /* mtxer */
+                               regs->xer = (regs->gpr[rd] & 0xffffffffUL);
+                               goto mtspr_out;
+                       case 0x100:     /* mtlr */
+                               regs->link = regs->gpr[rd];
+                               goto mtspr_out;
+                       case 0x120:     /* mtctr */
+                               regs->ctr = regs->gpr[rd];
+mtspr_out:
+                               regs->nip += 4;
+                               return 1;
+                       }
                }
        }
        return 0;
index bd68df5fa78ac083bc0479946b1085c44934f5b7..ddceefc06ecc0a5554a650e5dbe690959274943a 100644 (file)
@@ -283,6 +283,7 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
 #define PTEG_SIZE      64
 #define LG_PTEG_SIZE   6
 #define LDPTEu         lwzu
+#define LDPTE          lwz
 #define STPTE          stw
 #define CMPPTE         cmpw
 #define PTE_H          0x40
@@ -389,13 +390,30 @@ _GLOBAL(hash_page_patch_C)
         * and we know there is a definite (although small) speed
         * advantage to putting the PTE in the primary PTEG, we always
         * put the PTE in the primary PTEG.
+        *
+        * In addition, we skip any slot that is mapping kernel text in
+        * order to avoid a deadlock when not using BAT mappings if
+        * trying to hash in the kernel hash code itself after it has
+        * already taken the hash table lock. This works in conjunction
+        * with pre-faulting of the kernel text.
+        *
+        * If the hash table bucket is full of kernel text entries, we'll
+        * lockup here but that shouldn't happen
         */
-       addis   r4,r7,next_slot@ha
+
+1:     addis   r4,r7,next_slot@ha              /* get next evict slot */
        lwz     r6,next_slot@l(r4)
-       addi    r6,r6,PTE_SIZE
+       addi    r6,r6,PTE_SIZE                  /* search for candidate */
        andi.   r6,r6,7*PTE_SIZE
        stw     r6,next_slot@l(r4)
        add     r4,r3,r6
+       LDPTE   r0,PTE_SIZE/2(r4)               /* get PTE second word */
+       clrrwi  r0,r0,12
+       lis     r6,etext@h
+       ori     r6,r6,etext@l                   /* get etext */
+       tophys(r6,r6)
+       cmpl    cr0,r0,r6                       /* compare and try again */
+       blt     1b
 
 #ifndef CONFIG_SMP
        /* Store PTE in PTEG */
index 9bc0a9c2b9bcee59e6ca39fa5b9e7207dc7425b0..e64ce3eec36ed3e025324cb68011bac3c6a1028c 100644 (file)
@@ -445,9 +445,12 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
 
 htab_insert_pte:
        /* real page number in r5, PTE RPN value + index */
-       rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
+       andis.  r0,r31,_PAGE_4K_PFN@h
+       srdi    r5,r31,PTE_RPN_SHIFT
+       bne-    htab_special_pfn
        sldi    r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
        add     r5,r5,r25
+htab_special_pfn:
        sldi    r5,r5,HW_PAGE_SHIFT
 
        /* Calculate primary group hash */
index 6f1016acdbf691a9c4dbed2b65a111cdc1dff4d2..79aedaf36f2bd3cc91a893ce862bf8c00056a488 100644 (file)
@@ -505,7 +505,7 @@ static inline int tlb_batching_enabled(void)
        int enabled = 1;
 
        if (root) {
-               const char *model = get_property(root, "model", NULL);
+               const char *model = of_get_property(root, "model", NULL);
                if (model && !strcmp(model, "IBM,9076-N81"))
                        enabled = 0;
                of_node_put(root);
index 3c7fe2c65b5a85dc54dda993d68c025b845038f3..49618461defbda9a4e2017477c1326530281272e 100644 (file)
@@ -100,6 +100,11 @@ unsigned int HPAGE_SHIFT;
 #ifdef CONFIG_PPC_64K_PAGES
 int mmu_ci_restrictions;
 #endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+static u8 *linear_map_hash_slots;
+static unsigned long linear_map_hash_count;
+static spinlock_t linear_map_hash_lock;
+#endif /* CONFIG_DEBUG_PAGEALLOC */
 
 /* There are definitions of page sizes arrays to be used when none
  * is provided by the firmware.
@@ -152,11 +157,10 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
 
        for (vaddr = vstart, paddr = pstart; vaddr < vend;
             vaddr += step, paddr += step) {
-               unsigned long vpn, hash, hpteg;
+               unsigned long hash, hpteg;
                unsigned long vsid = get_kernel_vsid(vaddr);
                unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff);
 
-               vpn = va >> shift;
                tmp_mode = mode;
                
                /* Make non-kernel text non-executable */
@@ -174,6 +178,10 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
 
                if (ret < 0)
                        break;
+#ifdef CONFIG_DEBUG_PAGEALLOC
+               if ((paddr >> PAGE_SHIFT) < linear_map_hash_count)
+                       linear_map_hash_slots[paddr >> PAGE_SHIFT] = ret | 0x80;
+#endif /* CONFIG_DEBUG_PAGEALLOC */
        }
        return ret < 0 ? ret : 0;
 }
@@ -281,6 +289,7 @@ static void __init htab_init_page_sizes(void)
                memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
                       sizeof(mmu_psize_defaults_gp));
  found:
+#ifndef CONFIG_DEBUG_PAGEALLOC
        /*
         * Pick a size for the linear mapping. Currently, we only support
         * 16M, 1M and 4K which is the default
@@ -289,6 +298,7 @@ static void __init htab_init_page_sizes(void)
                mmu_linear_psize = MMU_PAGE_16M;
        else if (mmu_psize_defs[MMU_PAGE_1M].shift)
                mmu_linear_psize = MMU_PAGE_1M;
+#endif /* CONFIG_DEBUG_PAGEALLOC */
 
 #ifdef CONFIG_PPC_64K_PAGES
        /*
@@ -303,12 +313,14 @@ static void __init htab_init_page_sizes(void)
        if (mmu_psize_defs[MMU_PAGE_64K].shift) {
                mmu_virtual_psize = MMU_PAGE_64K;
                mmu_vmalloc_psize = MMU_PAGE_64K;
+               if (mmu_linear_psize == MMU_PAGE_4K)
+                       mmu_linear_psize = MMU_PAGE_64K;
                if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE))
                        mmu_io_psize = MMU_PAGE_64K;
                else
                        mmu_ci_restrictions = 1;
        }
-#endif
+#endif /* CONFIG_PPC_64K_PAGES */
 
        printk(KERN_DEBUG "Page orders: linear mapping = %d, "
               "virtual = %d, io = %d\n",
@@ -476,6 +488,13 @@ void __init htab_initialize(void)
 
        mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX;
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       linear_map_hash_count = lmb_end_of_DRAM() >> PAGE_SHIFT;
+       linear_map_hash_slots = __va(lmb_alloc_base(linear_map_hash_count,
+                                                   1, lmb.rmo_size));
+       memset(linear_map_hash_slots, 0, linear_map_hash_count);
+#endif /* CONFIG_DEBUG_PAGEALLOC */
+
        /* On U3 based machines, we need to reserve the DART area and
         * _NOT_ map it to avoid cache paradoxes as it's remapped non
         * cacheable later on
@@ -573,6 +592,27 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
        return pp;
 }
 
+/*
+ * Demote a segment to using 4k pages.
+ * For now this makes the whole process use 4k pages.
+ */
+void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
+{
+#ifdef CONFIG_PPC_64K_PAGES
+       if (mm->context.user_psize == MMU_PAGE_4K)
+               return;
+       mm->context.user_psize = MMU_PAGE_4K;
+       mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp;
+       get_paca()->context = mm->context;
+       slb_flush_and_rebolt();
+#ifdef CONFIG_SPE_BASE
+       spu_flush_all_slbs(mm);
+#endif
+#endif
+}
+
+EXPORT_SYMBOL_GPL(demote_segment_4k);
+
 /* Result code is:
  *  0 - handled
  *  1 - normal page fault
@@ -665,15 +705,19 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
 #ifndef CONFIG_PPC_64K_PAGES
        rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
 #else
+       /* If _PAGE_4K_PFN is set, make sure this is a 4k segment */
+       if (pte_val(*ptep) & _PAGE_4K_PFN) {
+               demote_segment_4k(mm, ea);
+               psize = MMU_PAGE_4K;
+       }
+
        if (mmu_ci_restrictions) {
                /* If this PTE is non-cacheable, switch to 4k */
                if (psize == MMU_PAGE_64K &&
                    (pte_val(*ptep) & _PAGE_NO_CACHE)) {
                        if (user_region) {
+                               demote_segment_4k(mm, ea);
                                psize = MMU_PAGE_4K;
-                               mm->context.user_psize = MMU_PAGE_4K;
-                               mm->context.sllp = SLB_VSID_USER |
-                                       mmu_psize_defs[MMU_PAGE_4K].sllp;
                        } else if (ea < VMALLOC_END) {
                                /*
                                 * some driver did a non-cacheable mapping
@@ -756,16 +800,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
        if (mmu_ci_restrictions) {
                /* If this PTE is non-cacheable, switch to 4k */
                if (mm->context.user_psize == MMU_PAGE_64K &&
-                   (pte_val(*ptep) & _PAGE_NO_CACHE)) {
-                       mm->context.user_psize = MMU_PAGE_4K;
-                       mm->context.sllp = SLB_VSID_USER |
-                               mmu_psize_defs[MMU_PAGE_4K].sllp;
-                       get_paca()->context = mm->context;
-                       slb_flush_and_rebolt();
-#ifdef CONFIG_SPE_BASE
-                       spu_flush_all_slbs(mm);
-#endif
-               }
+                   (pte_val(*ptep) & _PAGE_NO_CACHE))
+                       demote_segment_4k(mm, ea);
        }
        if (mm->context.user_psize == MMU_PAGE_64K)
                __hash_page_64K(ea, access, vsid, ptep, trap, local);
@@ -825,3 +861,62 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address)
        }
        bad_page_fault(regs, address, SIGBUS);
 }
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi)
+{
+       unsigned long hash, hpteg, vsid = get_kernel_vsid(vaddr);
+       unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff);
+       unsigned long mode = _PAGE_ACCESSED | _PAGE_DIRTY |
+               _PAGE_COHERENT | PP_RWXX | HPTE_R_N;
+       int ret;
+
+       hash = hpt_hash(va, PAGE_SHIFT);
+       hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
+
+       ret = ppc_md.hpte_insert(hpteg, va, __pa(vaddr),
+                                mode, HPTE_V_BOLTED, mmu_linear_psize);
+       BUG_ON (ret < 0);
+       spin_lock(&linear_map_hash_lock);
+       BUG_ON(linear_map_hash_slots[lmi] & 0x80);
+       linear_map_hash_slots[lmi] = ret | 0x80;
+       spin_unlock(&linear_map_hash_lock);
+}
+
+static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi)
+{
+       unsigned long hash, hidx, slot, vsid = get_kernel_vsid(vaddr);
+       unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff);
+
+       hash = hpt_hash(va, PAGE_SHIFT);
+       spin_lock(&linear_map_hash_lock);
+       BUG_ON(!(linear_map_hash_slots[lmi] & 0x80));
+       hidx = linear_map_hash_slots[lmi] & 0x7f;
+       linear_map_hash_slots[lmi] = 0;
+       spin_unlock(&linear_map_hash_lock);
+       if (hidx & _PTEIDX_SECONDARY)
+               hash = ~hash;
+       slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+       slot += hidx & _PTEIDX_GROUP_IX;
+       ppc_md.hpte_invalidate(slot, va, mmu_linear_psize, 0);
+}
+
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+       unsigned long flags, vaddr, lmi;
+       int i;
+
+       local_irq_save(flags);
+       for (i = 0; i < numpages; i++, page++) {
+               vaddr = (unsigned long)page_address(page);
+               lmi = __pa(vaddr) >> PAGE_SHIFT;
+               if (lmi >= linear_map_hash_count)
+                       continue;
+               if (enable)
+                       kernel_map_linear_page(vaddr, lmi);
+               else
+                       kernel_unmap_linear_page(vaddr, lmi);
+       }
+       local_irq_restore(flags);
+}
+#endif /* CONFIG_DEBUG_PAGEALLOC */
index f6ffaaa7a5bfc85fc7e2a95a2208a08e58addc7e..8508f973d9cc69f87112a197573d8863451ba26f 100644 (file)
@@ -316,12 +316,11 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
 {
        if (pte_present(*ptep)) {
                /* We open-code pte_clear because we need to pass the right
-                * argument to hpte_update (huge / !huge)
+                * argument to hpte_need_flush (huge / !huge). Might not be
+                * necessary anymore if we make hpte_need_flush() get the
+                * page size from the slices
                 */
-               unsigned long old = pte_update(ptep, ~0UL);
-               if (old & _PAGE_HASHPTE)
-                       hpte_update(mm, addr & HPAGE_MASK, ptep, old, 1);
-               flush_tlb_pending();
+               pte_update(mm, addr & HPAGE_MASK, ptep, ~0UL, 1);
        }
        *ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
 }
@@ -329,12 +328,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
 pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep)
 {
-       unsigned long old = pte_update(ptep, ~0UL);
-
-       if (old & _PAGE_HASHPTE)
-               hpte_update(mm, addr & HPAGE_MASK, ptep, old, 1);
-       *ptep = __pte(0);
-
+       unsigned long old = pte_update(mm, addr, ptep, ~0UL, 1);
        return __pte(old);
 }
 
index 0e53ca8f02fb88a4f14de9d40cf97dfc6d6d2722..5fce6ccecb8dee301d98e5ca97c7d9290a5540d9 100644 (file)
@@ -115,6 +115,10 @@ void MMU_setup(void)
        if (strstr(cmd_line, "noltlbs")) {
                __map_without_ltlbs = 1;
        }
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       __map_without_bats = 1;
+       __map_without_ltlbs = 1;
+#endif
 }
 
 /*
index 716a2906a24da373a9e892e1486e24f1316d271e..e3a1e8dc536a5bab3ea4c48f99e530cde5971e0b 100644 (file)
@@ -146,6 +146,10 @@ static long __init lmb_add_region(struct lmb_region *rgn, unsigned long base,
                unsigned long rgnbase = rgn->region[i].base;
                unsigned long rgnsize = rgn->region[i].size;
 
+               if ((rgnbase == base) && (rgnsize == size))
+                       /* Already have this region, so we're done */
+                       return 0;
+
                adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);
                if ( adjacent > 0 ) {
                        rgn->region[i].base -= size;
index 52f397c108a7b3e981800f8ee9f18c64effcef65..c4bcd7546424acff524d64536c6eb2e97854fa91 100644 (file)
@@ -58,9 +58,6 @@ int init_bootmem_done;
 int mem_init_done;
 unsigned long memory_limit;
 
-extern void hash_preload(struct mm_struct *mm, unsigned long ea,
-                        unsigned long access, unsigned long trap);
-
 int page_is_ram(unsigned long pfn)
 {
        unsigned long paddr = (pfn << PAGE_SHIFT);
index bea2d21ac6f789eb642890d2fc086b8ec27e08dd..9c4538bb04b0337f0452ac32516d8689b7c7fa46 100644 (file)
  *  2 of the License, or (at your option) any later version.
  *
  */
+#include <linux/mm.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu.h>
 
+extern void hash_preload(struct mm_struct *mm, unsigned long ea,
+                        unsigned long access, unsigned long trap);
+
+
 #ifdef CONFIG_PPC32
 extern void mapin_ram(void);
 extern int map_page(unsigned long va, phys_addr_t pa, int flags);
index e86c37c82cfda2f3a8d88e1c68ead668c4fc9907..b3a592b25ab3a7a18e31955af180ab6857763444 100644 (file)
@@ -74,7 +74,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu)
 
        while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) {
                /* Try interrupt server first */
-               interrupt_server = get_property(cpu_node,
+               interrupt_server = of_get_property(cpu_node,
                                        "ibm,ppc-interrupt-server#s", &len);
 
                len = len / sizeof(u32);
@@ -85,7 +85,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu)
                                        return cpu_node;
                        }
                } else {
-                       reg = get_property(cpu_node, "reg", &len);
+                       reg = of_get_property(cpu_node, "reg", &len);
                        if (reg && (len > 0) && (reg[0] == hw_cpuid))
                                return cpu_node;
                }
@@ -97,7 +97,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu)
 /* must hold reference to node during call */
 static const int *of_get_associativity(struct device_node *dev)
 {
-       return get_property(dev, "ibm,associativity", NULL);
+       return of_get_property(dev, "ibm,associativity", NULL);
 }
 
 /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
@@ -179,7 +179,7 @@ static int __init find_min_common_depth(void)
         * configuration (should be all 0's) and the second is for a normal
         * NUMA configuration.
         */
-       ref_points = get_property(rtas_root,
+       ref_points = of_get_property(rtas_root,
                        "ibm,associativity-reference-points", &len);
 
        if ((len >= 1) && ref_points) {
@@ -201,8 +201,8 @@ static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
        if (!memory)
                panic("numa.c: No memory nodes found!");
 
-       *n_addr_cells = prom_n_addr_cells(memory);
-       *n_size_cells = prom_n_size_cells(memory);
+       *n_addr_cells = of_n_addr_cells(memory);
+       *n_size_cells = of_n_size_cells(memory);
        of_node_put(memory);
 }
 
@@ -308,9 +308,9 @@ static void __init parse_drconf_memory(struct device_node *memory)
        int nid, default_nid = 0;
        unsigned int start, ai, flags;
 
-       lm = get_property(memory, "ibm,lmb-size", &ls);
-       dm = get_property(memory, "ibm,dynamic-memory", &ld);
-       aa = get_property(memory, "ibm,associativity-lookup-arrays", &la);
+       lm = of_get_property(memory, "ibm,lmb-size", &ls);
+       dm = of_get_property(memory, "ibm,dynamic-memory", &ld);
+       aa = of_get_property(memory, "ibm,associativity-lookup-arrays", &la);
        if (!lm || !dm || !aa ||
            ls < sizeof(unsigned int) || ld < sizeof(unsigned int) ||
            la < 2 * sizeof(unsigned int))
@@ -404,10 +404,10 @@ static int __init parse_numa_properties(void)
                const unsigned int *memcell_buf;
                unsigned int len;
 
-               memcell_buf = get_property(memory,
+               memcell_buf = of_get_property(memory,
                        "linux,usable-memory", &len);
                if (!memcell_buf || len <= 0)
-                       memcell_buf = get_property(memory, "reg", &len);
+                       memcell_buf = of_get_property(memory, "reg", &len);
                if (!memcell_buf || len <= 0)
                        continue;
 
@@ -725,7 +725,7 @@ int hot_add_scn_to_nid(unsigned long scn_addr)
                const unsigned int *memcell_buf;
                unsigned int len;
 
-               memcell_buf = get_property(memory, "reg", &len);
+               memcell_buf = of_get_property(memory, "reg", &len);
                if (!memcell_buf || len <= 0)
                        continue;
 
index c284bdac9947088e57fb66bc120639422eaf8900..bca56037492732f258c8fa6603843b1102f51b0c 100644 (file)
@@ -183,8 +183,8 @@ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
         * mem_init() sets high_memory so only do the check after that.
         */
        if (mem_init_done && (p < virt_to_phys(high_memory))) {
-               printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p,
-                      __builtin_return_address(0));
+               printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n",
+                      (unsigned long long)p, __builtin_return_address(0));
                return NULL;
        }
 
@@ -266,9 +266,12 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
        pg = pte_alloc_kernel(pd, va);
        if (pg != 0) {
                err = 0;
-               set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags)));
-               if (mem_init_done)
-                       flush_HPTE(0, va, pmd_val(*pd));
+               /* The PTE should never be already set nor present in the
+                * hash table
+                */
+               BUG_ON(pte_val(*pg) & (_PAGE_PRESENT | _PAGE_HASHPTE));
+               set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
+                                                    __pgprot(flags)));
        }
        return err;
 }
@@ -279,16 +282,19 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
 void __init mapin_ram(void)
 {
        unsigned long v, p, s, f;
+       int ktext;
 
        s = mmu_mapin_ram();
        v = KERNELBASE + s;
        p = PPC_MEMSTART + s;
        for (; s < total_lowmem; s += PAGE_SIZE) {
-               if ((char *) v >= _stext && (char *) v < etext)
-                       f = _PAGE_RAM_TEXT;
-               else
-                       f = _PAGE_RAM;
+               ktext = ((char *) v >= _stext && (char *) v < etext);
+               f = ktext ?_PAGE_RAM_TEXT : _PAGE_RAM;
                map_page(v, p, f);
+#ifdef CONFIG_PPC_STD_MMU_32
+               if (ktext)
+                       hash_preload(&init_mm, v, 0, 0x300);
+#endif
                v += PAGE_SIZE;
                p += PAGE_SIZE;
        }
@@ -445,3 +451,55 @@ exit:
        return ret;
 }
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+
+static int __change_page_attr(struct page *page, pgprot_t prot)
+{
+       pte_t *kpte;
+       pmd_t *kpmd;
+       unsigned long address;
+
+       BUG_ON(PageHighMem(page));
+       address = (unsigned long)page_address(page);
+
+       if (v_mapped_by_bats(address) || v_mapped_by_tlbcam(address))
+               return 0;
+       if (!get_pteptr(&init_mm, address, &kpte, &kpmd))
+               return -EINVAL;
+       set_pte_at(&init_mm, address, kpte, mk_pte(page, prot));
+       wmb();
+       flush_HPTE(0, address, pmd_val(*kpmd));
+       pte_unmap(kpte);
+
+       return 0;
+}
+
+/*
+ * Change the page attributes of an page in the linear mapping.
+ *
+ * THIS CONFLICTS WITH BAT MAPPINGS, DEBUG USE ONLY
+ */
+static int change_page_attr(struct page *page, int numpages, pgprot_t prot)
+{
+       int i, err = 0;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       for (i = 0; i < numpages; i++, page++) {
+               err = __change_page_attr(page, prot);
+               if (err)
+                       break;
+       }
+       local_irq_restore(flags);
+       return err;
+}
+
+
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+       if (PageHighMem(page))
+               return;
+
+       change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0));
+}
+#endif /* CONFIG_DEBUG_PAGEALLOC */
index 7cceb2c44cb911936c40dc96ea57f0ba0accf9c7..05066674a7a02fa2b07835d3068c15e951013173 100644 (file)
@@ -85,8 +85,10 @@ unsigned long __init mmu_mapin_ram(void)
        unsigned long max_size = (256<<20);
        unsigned long align;
 
-       if (__map_without_bats)
+       if (__map_without_bats) {
+               printk(KERN_DEBUG "RAM mapped without BATs\n");
                return 0;
+       }
 
        /* Set up BAT2 and if necessary BAT3 to cover RAM. */
 
index b58baa65c4a74f11978baf41bee0e04c428d19f6..fd8d08c325ebecca3083759360cbf6e6c30b1e8e 100644 (file)
@@ -120,17 +120,20 @@ void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
 }
 
 /*
- * Update the MMU hash table to correspond with a change to
- * a Linux PTE.  If wrprot is true, it is permissible to
- * change the existing HPTE to read-only rather than removing it
- * (if we remove it we should clear the _PTE_HPTEFLAGS bits).
+ * A linux PTE was changed and the corresponding hash table entry
+ * neesd to be flushed. This function will either perform the flush
+ * immediately or will batch it up if the current CPU has an active
+ * batch on it.
+ *
+ * Must be called from within some kind of spinlock/non-preempt region...
  */
-void hpte_update(struct mm_struct *mm, unsigned long addr,
-                pte_t *ptep, unsigned long pte, int huge)
+void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
+                    pte_t *ptep, unsigned long pte, int huge)
 {
        struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
-       unsigned long vsid;
+       unsigned long vsid, vaddr;
        unsigned int psize;
+       real_pte_t rpte;
        int i;
 
        i = batch->index;
@@ -151,6 +154,26 @@ void hpte_update(struct mm_struct *mm, unsigned long addr,
        } else
                psize = pte_pagesize_index(pte);
 
+       /* Build full vaddr */
+       if (!is_kernel_addr(addr)) {
+               vsid = get_vsid(mm->context.id, addr);
+               WARN_ON(vsid == 0);
+       } else
+               vsid = get_kernel_vsid(addr);
+       vaddr = (vsid << 28 ) | (addr & 0x0fffffff);
+       rpte = __real_pte(__pte(pte), ptep);
+
+       /*
+        * Check if we have an active batch on this CPU. If not, just
+        * flush now and return. For now, we don global invalidates
+        * in that case, might be worth testing the mm cpu mask though
+        * and decide to use local invalidates instead...
+        */
+       if (!batch->active) {
+               flush_hash_page(vaddr, rpte, psize, 0);
+               return;
+       }
+
        /*
         * This can happen when we are in the middle of a TLB batch and
         * we encounter memory pressure (eg copy_page_range when it tries
@@ -162,47 +185,42 @@ void hpte_update(struct mm_struct *mm, unsigned long addr,
         * batch
         */
        if (i != 0 && (mm != batch->mm || batch->psize != psize)) {
-               flush_tlb_pending();
+               __flush_tlb_pending(batch);
                i = 0;
        }
        if (i == 0) {
                batch->mm = mm;
                batch->psize = psize;
        }
-       if (!is_kernel_addr(addr)) {
-               vsid = get_vsid(mm->context.id, addr);
-               WARN_ON(vsid == 0);
-       } else
-               vsid = get_kernel_vsid(addr);
-       batch->vaddr[i] = (vsid << 28 ) | (addr & 0x0fffffff);
-       batch->pte[i] = __real_pte(__pte(pte), ptep);
+       batch->pte[i] = rpte;
+       batch->vaddr[i] = vaddr;
        batch->index = ++i;
        if (i >= PPC64_TLB_BATCH_NR)
-               flush_tlb_pending();
+               __flush_tlb_pending(batch);
 }
 
+/*
+ * This function is called when terminating an mmu batch or when a batch
+ * is full. It will perform the flush of all the entries currently stored
+ * in a batch.
+ *
+ * Must be called from within some kind of spinlock/non-preempt region...
+ */
 void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
 {
-       int i;
-       int cpu;
        cpumask_t tmp;
-       int local = 0;
+       int i, local = 0;
 
-       BUG_ON(in_interrupt());
-
-       cpu = get_cpu();
        i = batch->index;
-       tmp = cpumask_of_cpu(cpu);
+       tmp = cpumask_of_cpu(smp_processor_id());
        if (cpus_equal(batch->mm->cpu_vm_mask, tmp))
                local = 1;
-
        if (i == 1)
                flush_hash_page(batch->vaddr[0], batch->pte[0],
                                batch->psize, local);
        else
                flush_hash_range(i, local);
        batch->index = 0;
-       put_cpu();
 }
 
 void pte_free_finish(void)
index 4ccef2d5530cc476e7a0aed788a9952183bb129d..4b5f9528218ccd14c7af13ac48209b7c7e0add2b 100644 (file)
@@ -12,6 +12,6 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
 
 oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
 oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o
-oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
+oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
 oprofile-$(CONFIG_6xx) += op_model_7450.o
index fbd62eacfdf4264c5620167ce78edc77f157654b..1a7ef7e246d2bb0c069c396ee63ccc23dd2aa92a 100644 (file)
@@ -160,6 +160,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
                case PPC_OPROFILE_POWER4:
                        model = &op_model_power4;
                        break;
+               case PPC_OPROFILE_PA6T:
+                       model = &op_model_pa6t;
+                       break;
 #endif
 #ifdef CONFIG_6xx
                case PPC_OPROFILE_G4:
index e08e1d7b3dc5d21bc525d2f5d88fd89efa34ea9c..626b29f38304e3c8339e61b52ddb619a5c5dd0f5 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/system.h>
 
 #include "../platforms/cell/interrupt.h"
+#include "../platforms/cell/cbe_regs.h"
 
 #define PPU_CYCLES_EVENT_NUM 1 /*  event number for CYCLES */
 #define PPU_CYCLES_GRP_NUM   1  /* special group number for identifying
@@ -130,7 +131,7 @@ static int pm_rtas_token;
 static u32 reset_value[NR_PHYS_CTRS];
 static int num_counters;
 static int oprofile_running;
-static spinlock_t virt_cntr_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(virt_cntr_lock);
 
 static u32 ctr_enabled;
 
diff --git a/arch/powerpc/oprofile/op_model_pa6t.c b/arch/powerpc/oprofile/op_model_pa6t.c
new file mode 100644 (file)
index 0000000..e8a56b0
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Shashi Rao, PA Semi
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on arch/powerpc/oprofile/op_model_power4.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/percpu.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/oprofile_impl.h>
+#include <asm/reg.h>
+
+static unsigned char oprofile_running;
+
+/* mmcr values are set in pa6t_reg_setup, used in pa6t_cpu_setup */
+static u64 mmcr0_val;
+static u64 mmcr1_val;
+
+/* inited in pa6t_reg_setup */
+static u64 reset_value[OP_MAX_COUNTER];
+
+static inline u64 ctr_read(unsigned int i)
+{
+       switch (i) {
+       case 0:
+               return mfspr(SPRN_PA6T_PMC0);
+       case 1:
+               return mfspr(SPRN_PA6T_PMC1);
+       case 2:
+               return mfspr(SPRN_PA6T_PMC2);
+       case 3:
+               return mfspr(SPRN_PA6T_PMC3);
+       case 4:
+               return mfspr(SPRN_PA6T_PMC4);
+       case 5:
+               return mfspr(SPRN_PA6T_PMC5);
+       default:
+               printk(KERN_ERR "ctr_read called with bad arg %u\n", i);
+               return 0;
+       }
+}
+
+static inline void ctr_write(unsigned int i, u64 val)
+{
+       switch (i) {
+       case 0:
+               mtspr(SPRN_PA6T_PMC0, val);
+               break;
+       case 1:
+               mtspr(SPRN_PA6T_PMC1, val);
+               break;
+       case 2:
+               mtspr(SPRN_PA6T_PMC2, val);
+               break;
+       case 3:
+               mtspr(SPRN_PA6T_PMC3, val);
+               break;
+       case 4:
+               mtspr(SPRN_PA6T_PMC4, val);
+               break;
+       case 5:
+               mtspr(SPRN_PA6T_PMC5, val);
+               break;
+       default:
+               printk(KERN_ERR "ctr_write called with bad arg %u\n", i);
+               break;
+       }
+}
+
+
+/* precompute the values to stuff in the hardware registers */
+static void pa6t_reg_setup(struct op_counter_config *ctr,
+                          struct op_system_config *sys,
+                          int num_ctrs)
+{
+       int pmc;
+
+       /*
+        * adjust the mmcr0.en[0-5] and mmcr0.inten[0-5] values obtained from the
+        * event_mappings file by turning off the counters that the user doesn't
+        * care about
+        *
+        * setup user and kernel profiling
+        */
+       for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++)
+               if (!ctr[pmc].enabled) {
+                       sys->mmcr0 &= ~(0x1UL << pmc);
+                       sys->mmcr0 &= ~(0x1UL << (pmc+12));
+                       pr_debug("turned off counter %u\n", pmc);
+               }
+
+       if (sys->enable_kernel)
+               sys->mmcr0 |= PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN;
+       else
+               sys->mmcr0 &= ~(PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN);
+
+       if (sys->enable_user)
+               sys->mmcr0 |= PA6T_MMCR0_PREN;
+       else
+               sys->mmcr0 &= ~PA6T_MMCR0_PREN;
+
+       /*
+        * The performance counter event settings are given in the mmcr0 and
+        * mmcr1 values passed from the user in the op_system_config
+        * structure (sys variable).
+        */
+       mmcr0_val = sys->mmcr0;
+       mmcr1_val = sys->mmcr1;
+       pr_debug("mmcr0_val inited to %016lx\n", sys->mmcr0);
+       pr_debug("mmcr1_val inited to %016lx\n", sys->mmcr1);
+
+       for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++) {
+               /* counters are 40 bit. Move to cputable at some point? */
+               reset_value[pmc] = (0x1UL << 39) - ctr[pmc].count;
+               pr_debug("reset_value for pmc%u inited to 0x%lx\n",
+                                pmc, reset_value[pmc]);
+       }
+}
+
+/* configure registers on this cpu */
+static void pa6t_cpu_setup(struct op_counter_config *ctr)
+{
+       u64 mmcr0 = mmcr0_val;
+       u64 mmcr1 = mmcr1_val;
+
+       /* Default is all PMCs off */
+       mmcr0 &= ~(0x3FUL);
+       mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+       /* program selected programmable events in */
+       mtspr(SPRN_PA6T_MMCR1, mmcr1);
+
+       pr_debug("setup on cpu %d, mmcr0 %016lx\n", smp_processor_id(),
+               mfspr(SPRN_PA6T_MMCR0));
+       pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
+               mfspr(SPRN_PA6T_MMCR1));
+}
+
+static void pa6t_start(struct op_counter_config *ctr)
+{
+       int i;
+
+       /* Hold off event counting until rfid */
+       u64 mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
+
+       for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
+               if (ctr[i].enabled)
+                       ctr_write(i, reset_value[i]);
+               else
+                       ctr_write(i, 0UL);
+
+       mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+       oprofile_running = 1;
+
+       pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+}
+
+static void pa6t_stop(void)
+{
+       u64 mmcr0;
+
+       /* freeze counters */
+       mmcr0 = mfspr(SPRN_PA6T_MMCR0);
+       mmcr0 |= PA6T_MMCR0_FCM0;
+       mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+       oprofile_running = 0;
+
+       pr_debug("stop on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+}
+
+/* handle the perfmon overflow vector */
+static void pa6t_handle_interrupt(struct pt_regs *regs,
+                                 struct op_counter_config *ctr)
+{
+       unsigned long pc = mfspr(SPRN_PA6T_SIAR);
+       int is_kernel = is_kernel_addr(pc);
+       u64 val;
+       int i;
+       u64 mmcr0;
+
+       /* disable perfmon counting until rfid */
+       mmcr0 = mfspr(SPRN_PA6T_MMCR0);
+       mtspr(SPRN_PA6T_MMCR0, mmcr0 | PA6T_MMCR0_HANDDIS);
+
+       /* Record samples. We've got one global bit for whether a sample
+        * was taken, so add it for any counter that triggered overflow.
+        */
+       for (i = 0; i < cur_cpu_spec->num_pmcs; i++) {
+               val = ctr_read(i);
+               if (val & (0x1UL << 39)) { /* Overflow bit set */
+                       if (oprofile_running && ctr[i].enabled) {
+                               if (mmcr0 & PA6T_MMCR0_SIARLOG)
+                                       oprofile_add_ext_sample(pc, regs, i, is_kernel);
+                               ctr_write(i, reset_value[i]);
+                       } else {
+                               ctr_write(i, 0UL);
+                       }
+               }
+       }
+
+       /* Restore mmcr0 to a good known value since the PMI changes it */
+       mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
+       mtspr(SPRN_PA6T_MMCR0, mmcr0);
+}
+
+struct op_powerpc_model op_model_pa6t = {
+       .reg_setup              = pa6t_reg_setup,
+       .cpu_setup              = pa6t_cpu_setup,
+       .start                  = pa6t_start,
+       .stop                   = pa6t_stop,
+       .handle_interrupt       = pa6t_handle_interrupt,
+};
index 2f2a13ed766701275c88cd2ed23cf70335243549..ded357c17414ad16b8643b2e03af6a39992ab511 100644 (file)
@@ -3,278 +3,206 @@ config 4xx
        depends on 40x || 44x
        default y
 
-config WANT_EARLY_SERIAL
+config BOOKE
        bool
-       select SERIAL_8250
-       default n
-
-menu "AMCC 4xx options"
-       depends on 4xx
-
-choice
-       prompt "Machine Type"
-       depends on 40x
-       default WALNUT
-
-config BUBINGA
-       bool "Bubinga"
-       select WANT_EARLY_SERIAL
-       help
-         This option enables support for the IBM 405EP evaluation board.
-
-config CPCI405
-       bool "CPCI405"
-       help
-         This option enables support for the CPCI405 board.
-
-config EP405
-       bool "EP405/EP405PC"
-       help
-         This option enables support for the EP405/EP405PC boards.
-
-config REDWOOD_5
-       bool "Redwood-5"
-       help
-         This option enables support for the IBM STB04 evaluation board.
-
-config REDWOOD_6
-       bool "Redwood-6"
-       help
-         This option enables support for the IBM STBx25xx evaluation board.
-
-config SYCAMORE
-       bool "Sycamore"
-       help
-         This option enables support for the IBM PPC405GPr evaluation board.
-
-config WALNUT
-       bool "Walnut"
-       help
-         This option enables support for the IBM PPC405GP evaluation board.
-
-config XILINX_ML300
-       bool "Xilinx-ML300"
-       help
-         This option enables support for the Xilinx ML300 evaluation board.
-
-endchoice
-
-choice
-       prompt "Machine Type"
        depends on 44x
-       default EBONY
-
-config BAMBOO
-       bool "Bamboo"
-       select WANT_EARLY_SERIAL
-       help
-         This option enables support for the IBM PPC440EP evaluation board.
-
-config EBONY
-       bool "Ebony"
-       select WANT_EARLY_SERIAL
-       help
-         This option enables support for the IBM PPC440GP evaluation board.
-
-config LUAN
-       bool "Luan"
-       select WANT_EARLY_SERIAL
-       help
-         This option enables support for the IBM PPC440SP evaluation board.
-
-config OCOTEA
-       bool "Ocotea"
-       select WANT_EARLY_SERIAL
-       help
-         This option enables support for the IBM PPC440GX evaluation board.
+       default y
 
-endchoice
+menu "AMCC 40x options"
+       depends on 40x
 
-config EP405PC
-       bool "EP405PC Support"
-       depends on EP405
+#config BUBINGA
+#      bool "Bubinga"
+#      depends on 40x
+#      default n
+#      select 405EP
+#      help
+#        This option enables support for the IBM 405EP evaluation board.
+
+#config CPCI405
+#      bool "CPCI405"
+#      depends on 40x
+#      default n
+#      select 405GP
+#      help
+#        This option enables support for the CPCI405 board.
+
+#config EP405
+#      bool "EP405/EP405PC"
+#      depends on 40x
+#      default n
+#      select 405GP
+#      help
+#        This option enables support for the EP405/EP405PC boards.
+
+#config EP405PC
+#      bool "EP405PC Support"
+#      depends on EP405
+#      default y
+#      help
+#        This option enables support for the extra features of the EP405PC board.
+
+#config REDWOOD_5
+#      bool "Redwood-5"
+#      depends on 40x
+#      default n
+#      select STB03xxx
+#      help
+#        This option enables support for the IBM STB04 evaluation board.
+
+#config REDWOOD_6
+#      bool "Redwood-6"
+#      depends on 40x
+#      default n
+#      select STB03xxx
+#      help
+#        This option enables support for the IBM STBx25xx evaluation board.
+
+#config SYCAMORE
+#      bool "Sycamore"
+#      depends on 40x
+#      default n
+#      select 405GPR
+#      help
+#        This option enables support for the IBM PPC405GPr evaluation board.
+
+#config WALNUT
+#      bool "Walnut"
+#      depends on 40x
+#      default y
+#      select 405GP
+#      help
+#        This option enables support for the IBM PPC405GP evaluation board.
+
+#config XILINX_ML300
+#      bool "Xilinx-ML300"
+#      depends on 40x
+#      default y
+#      select VIRTEX_II_PRO
+#      help
+#        This option enables support for the Xilinx ML300 evaluation board.
 
+endmenu
 
-# It's often necessary to know the specific 4xx processor type.
-# Fortunately, it is impled (so far) from the board type, so we
-# don't need to ask more redundant questions.
+# 40x specific CPU modules, selected based on the board above.
 config NP405H
        bool
-       depends on ASH
-       default y
+       #depends on ASH
 
-config 440EP
+# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
+config 403GCX
        bool
-       depends on BAMBOO
-       select PPC_FPU
-       default y
+       #depends on OAK
+       select IBM405_ERR51
 
-config 440GP
+config 405GP
        bool
-       depends on EBONY
-       default y
+       select IBM405_ERR77
+       select IBM405_ERR51
 
-config 440GX
+config 405EP
        bool
-       depends on OCOTEA
-       default y
 
-config 440SP
+config 405GPR
        bool
-       depends on LUAN
-       default y
 
-config 440
+config VIRTEX_II_PRO
        bool
-       depends on 440GP || 440SP || 440EP
-       default y
+       select IBM405_ERR77
+       select IBM405_ERR51
 
-config 440A
+config STB03xxx
        bool
-       depends on 440GX
-       default y
+       select IBM405_ERR77
+       select IBM405_ERR51
 
-config IBM440EP_ERR42
-       bool
-       depends on 440EP
-       default y
+# 40x errata/workaround config symbols, selected by the CPU models above
 
 # All 405-based cores up until the 405GPR and 405EP have this errata.
 config IBM405_ERR77
        bool
-       depends on 40x && !403GCX && !405GPR && !405EP
-       default y
 
 # All 40x-based cores, up until the 405GPR and 405EP have this errata.
 config IBM405_ERR51
        bool
-       depends on 40x && !405GPR && !405EP
-       default y
 
-config BOOKE
-       bool
+menu "AMCC 44x options"
        depends on 44x
-       default y
-
-config IBM_OCP
-       bool
-       depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
-       default y
 
-config XILINX_OCP
-       bool
-       depends on XILINX_ML300
-       default y
+#config BAMBOO
+#      bool "Bamboo"
+#      depends on 44x
+#      default n
+#      select 440EP
+#      help
+#        This option enables support for the IBM PPC440EP evaluation board.
 
-config IBM_EMAC4
-       bool
-       depends on 440GX || 440SP
-       default y
-
-config BIOS_FIXUP
-       bool
-       depends on BUBINGA || EP405 || SYCAMORE || WALNUT
-       default y
-
-# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
-config 403GCX
-       bool
-       depends on OAK
-       default y
-
-config 405EP
-       bool
-       depends on BUBINGA
-       default y
-
-config 405GP
-       bool
-       depends on CPCI405 || EP405 || WALNUT
-       default y
-
-config 405GPR
-       bool
-       depends on SYCAMORE
+config EBONY
+       bool "Ebony"
+       depends on 44x
        default y
+       select 440GP
+       help
+         This option enables support for the IBM PPC440GP evaluation board.
 
-config VIRTEX_II_PRO
-       bool
-       depends on XILINX_ML300
-       default y
+#config LUAN
+#      bool "Luan"
+#      depends on 44x
+#      default n
+#      select 440SP
+#      help
+#        This option enables support for the IBM PPC440SP evaluation board.
+
+#config OCOTEA
+#      bool "Ocotea"
+#      depends on 44x
+#      default n
+#      select 440GX
+#      help
+#        This option enables support for the IBM PPC440GX evaluation board.
 
-config STB03xxx
-       bool
-       depends on REDWOOD_5 || REDWOOD_6
-       default y
+endmenu
 
-config EMBEDDEDBOOT
+# 44x specific CPU modules, selected based on the board above.
+config 440EP
        bool
-       depends on EP405 || XILINX_ML300
-       default y
+       select PPC_FPU
+       select IBM440EP_ERR42
 
-config IBM_OPENBIOS
+config 440GP
        bool
-       depends on ASH || BUBINGA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
-       default y
+       select IBM_NEW_EMAC_ZMII
 
-config PPC4xx_DMA
-       bool "PPC4xx DMA controller support"
-       depends on 4xx
-
-config PPC4xx_EDMA
+config 440GX
        bool
-       depends on !STB03xxx && PPC4xx_DMA
-       default y
 
-config PPC_GEN550
+config 440SP
        bool
-       depends on 4xx
-       default y
-
-choice
-       prompt "TTYS0 device and default console"
-       depends on 40x
-       default UART0_TTYS0
-
-config UART0_TTYS0
-       bool "UART0"
 
-config UART0_TTYS1
-       bool "UART1"
-
-endchoice
-
-config SERIAL_SICC
-       bool "SICC Serial port support"
-       depends on STB03xxx
-
-config UART1_DFLT_CONSOLE
+config 440A
        bool
-       depends on SERIAL_SICC && UART0_TTYS1
+       depends on 440GX
        default y
 
-config SERIAL_SICC_CONSOLE
+# 44x errata/workaround config symbols, selected by the CPU models above
+config IBM440EP_ERR42
        bool
-       depends on SERIAL_SICC && UART0_TTYS1
-       default y
-endmenu
 
+#config XILINX_OCP
+#      bool
+#      depends on XILINX_ML300
+#      default y
 
-menu "IBM 40x options"
-       depends on 40x
-
-config SERIAL_SICC
-       bool "SICC Serial port"
-       depends on STB03xxx
-
-config UART1_DFLT_CONSOLE
-       bool
-       depends on SERIAL_SICC && UART0_TTYS1
-       default y
+#config BIOS_FIXUP
+#      bool
+#      depends on BUBINGA || EP405 || SYCAMORE || WALNUT
+#      default y
 
-config SERIAL_SICC_CONSOLE
-       bool
-       depends on SERIAL_SICC && UART0_TTYS1
-       default y
+#config PPC4xx_DMA
+#      bool "PPC4xx DMA controller support"
+#      depends on 4xx
 
-endmenu
+#config PPC4xx_EDMA
+#      bool
+#      depends on !STB03xxx && PPC4xx_DMA
+#      default y
diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig
new file mode 100644 (file)
index 0000000..bc4aa4a
--- /dev/null
@@ -0,0 +1,35 @@
+config PPC_MPC52xx
+       bool
+       default n
+
+config PPC_MPC5200
+       bool
+       select PPC_MPC52xx
+       default n
+
+config PPC_MPC5200_BUGFIX
+       bool "MPC5200 (L25R) bugfix support"
+       depends on PPC_MPC5200
+       default n
+       help
+         Enable workarounds for original MPC5200 errata.  This is not required
+         for MPC5200B based boards.
+
+         It is safe to say 'Y' here
+
+config PPC_EFIKA
+       bool "bPlan Efika 5k2. MPC5200B based computer"
+       depends on PPC_MULTIPLATFORM && PPC32
+       select PPC_RTAS
+       select RTAS_PROC
+       select PPC_MPC52xx
+       select PPC_NATIVE
+       default n
+
+config PPC_LITE5200
+       bool "Freescale Lite5200 Eval Board"
+       depends on PPC_MULTIPLATFORM && PPC32
+       select PPC_MPC5200
+       default n
+
+
index 8de03411668134c4f42ce94c9c27dc709803fd54..a6bba97314eb45a1248e0446753f86f57edf2369 100644 (file)
@@ -112,7 +112,7 @@ void __init efika_pcisetup(void)
                return;
        }
 
-       bus_range = get_property(pcictrl, "bus-range", &len);
+       bus_range = of_get_property(pcictrl, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                printk(KERN_WARNING EFIKA_PLATFORM_NAME
                       ": Can't get bus-range for %s\n", pcictrl->full_name);
@@ -158,18 +158,17 @@ void __init efika_pcisetup(void)
 static void efika_show_cpuinfo(struct seq_file *m)
 {
        struct device_node *root;
-       const char *revision = NULL;
-       const char *codegendescription = NULL;
-       const char *codegenvendor = NULL;
+       const char *revision;
+       const char *codegendescription;
+       const char *codegenvendor;
 
        root = of_find_node_by_path("/");
        if (!root)
                return;
 
-       revision = get_property(root, "revision", NULL);
-       codegendescription =
-                   get_property(root, "CODEGEN,description", NULL);
-       codegenvendor = get_property(root, "CODEGEN,vendor", NULL);
+       revision = of_get_property(root, "revision", NULL);
+       codegendescription = of_get_property(root, "CODEGEN,description", NULL);
+       codegenvendor = of_get_property(root, "CODEGEN,vendor", NULL);
 
        if (codegendescription)
                seq_printf(m, "machine\t\t: %s\n", codegendescription);
index cc3b40de21ddf8ef3351694d593568be95601b2a..8e2646ac417bf788d5223938decdf17b5c00d0b0 100644 (file)
@@ -94,8 +94,8 @@ static void __init lite5200_setup_arch(void)
 
        np = of_find_node_by_type(NULL, "cpu");
        if (np) {
-               unsigned int *fp =
-                   (int *)get_property(np, "clock-frequency", NULL);
+               const unsigned int *fp =
+                       of_get_property(np, "clock-frequency", NULL);
                if (fp != 0)
                        loops_per_jiffy = *fp / HZ;
                else
@@ -108,9 +108,11 @@ static void __init lite5200_setup_arch(void)
        lite5200_setup_cpu();   /* Platorm specific */
 
 #ifdef CONFIG_PCI
-       np = of_find_node_by_type(np, "pci");
-       if (np)
+       np = of_find_node_by_type(NULL, "pci");
+       if (np) {
                mpc52xx_add_bridge(np);
+               of_node_put(np);
+       }
 #endif
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -132,7 +134,7 @@ void lite5200_show_cpuinfo(struct seq_file *m)
        const char *model = NULL;
 
        if (np)
-               model = get_property(np, "model", NULL);
+               model = of_get_property(np, "model", NULL);
 
        seq_printf(m, "vendor\t\t:      Freescale Semiconductor\n");
        seq_printf(m, "machine\t\t:     %s\n", model ? model : "unknown");
index ed0cb694aea878692e329f941e7ce40aaf0d7a1d..2dd415ff55a93bf90eccbf77a288e98f355b0159 100644 (file)
@@ -60,7 +60,7 @@ mpc52xx_find_ipb_freq(struct device_node *node)
 
        of_node_get(node);
        while (node) {
-               p_ipb_freq = get_property(node, "bus-frequency", NULL);
+               p_ipb_freq = of_get_property(node, "bus-frequency", NULL);
                if (p_ipb_freq)
                        break;
 
index faf161bdbc1c126c6f996c70bfa5b0bc21d9148c..34d34a26d30576faf647160b4334bee6e56d0327 100644 (file)
@@ -370,7 +370,7 @@ mpc52xx_add_bridge(struct device_node *node)
                return -EINVAL;
        }
 
-       bus_range = get_property(node, "bus-range", &len);
+       bus_range = of_get_property(node, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
                       node->full_name);
index 47d841ecf2e28767af53edfe6d4ff7278a8433f8..de7fce9cb6eb8b632e0efb7f2b2c1b1b00409e62 100644 (file)
@@ -1,21 +1,36 @@
-menu "Platform support"
-       depends on PPC_82xx
-
 choice
-       prompt "Machine Type"
-       default MPC82xx_ADS
+       prompt "Machine Type"
+       depends on PPC_82xx
+       default MPC82xx_ADS
 
 config MPC82xx_ADS
-       bool "Freescale MPC82xx ADS"
-       select DEFAULT_UIMAGE
-       select PQ2ADS
-       select 8272
-       select 8260
-       select CPM2
-       select FSL_SOC
-       help
-         This option enables support for the MPC8272 ADS board
+       bool "Freescale MPC82xx ADS"
+       select DEFAULT_UIMAGE
+       select PQ2ADS
+       select 8272
+       select 8260
+       select FSL_SOC
+       help
+       This option enables support for the MPC8272 ADS board
 
 endchoice
 
-endmenu
+config PQ2ADS
+       bool
+       default n
+
+config 8260
+       bool
+       depends on 6xx
+       select CPM2
+       help
+         The MPC8260 is a typical embedded CPU made by Freescale.  Selecting
+         this option means that you wish to build a kernel for a machine with
+         an 8260 class CPU.
+
+config 8272
+       bool
+       select 8260
+       help
+         The MPC8272 CPM has a different internal dpram setup than other CPM2
+         devices
index 74e7892cdfcf9b9526ba0453f8d2742436facb53..cc9900d2e5eeecd364854646257de8d2d73f3047 100644 (file)
 static int __init get_freq(char *name, unsigned long *val)
 {
        struct device_node *cpu;
-       unsigned int *fp;
+       const unsigned int *fp;
        int found = 0;
 
        /* The cpu node should have timebase and clock frequency properties */
        cpu = of_find_node_by_type(NULL, "cpu");
 
        if (cpu) {
-               fp = (unsigned int *)get_property(cpu, name, NULL);
+               fp = of_get_property(cpu, name, NULL);
                if (fp) {
                        found = 1;
-                       *val = *fp++;
+                       *val = *fp;
                }
 
                of_node_put(cpu);
index 7334c1a15b90d549a9896e105fe588932ee572e4..47cb09f08052837cb2c7f5621dfcca30c4a79f0b 100644 (file)
@@ -456,7 +456,7 @@ void m82xx_pci_init_irq(void)
                iounmap(immap);
                return;
        }
-       irq_map = get_property(np, "interrupt-map", &size);
+       irq_map = of_get_property(np, "interrupt-map", &size);
        if ((!irq_map) || (size <= 7)) {
                printk(KERN_INFO "No interrupt-map property of pci node\n");
                iounmap(immap);
@@ -481,7 +481,7 @@ void m82xx_pci_init_irq(void)
        }
        pci_pic_node = of_node_get(np);
        /* PCI interrupt controller registers: status and mask */
-       regs = get_property(np, "reg", &size);
+       regs = of_get_property(np, "reg", &size);
        if ((!regs) || (size <= 2)) {
                printk(KERN_INFO "No reg property in pci pic node\n");
                iounmap(immap);
@@ -521,20 +521,20 @@ void __init add_bridge(struct device_node *np)
        struct pci_controller *hose;
        struct resource r;
        const int *bus_range;
-       const void *ptr;
+       const uint *ptr;
 
        memset(&r, 0, sizeof(r));
        if (of_address_to_resource(np, 0, &r)) {
                printk(KERN_INFO "No PCI reg property in device tree\n");
                return;
        }
-       if (!(ptr = get_property(np, "clock-frequency", NULL))) {
+       if (!(ptr = of_get_property(np, "clock-frequency", NULL))) {
                printk(KERN_INFO "No clock-frequency property in PCI node");
                return;
        }
-       pci_clk_frq = *(uint *) ptr;
+       pci_clk_frq = *ptr;
        of_node_put(np);
-       bus_range = get_property(np, "bus-range", &len);
+       bus_range = of_get_property(np, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                printk(KERN_WARNING "Can't get bus-range for %s, assume"
                       " bus 0\n", np->full_name);
index 713b31a16ce9e252e47ad25b35d8b5aa677d0d9b..19cafdf6df9385bc75befac6a2c771e8d15fa582 100644 (file)
@@ -1,8 +1,6 @@
-menu "Platform support"
-       depends on PPC_83xx
-
 choice
        prompt "Machine Type"
+       depends on PPC_83xx
        default MPC834x_MDS
 
 config MPC8313_RDB
@@ -18,6 +16,13 @@ config MPC832x_MDS
        help
          This option enables support for the MPC832x MDS evaluation board.
 
+config MPC832x_RDB
+       bool "Freescale MPC832x RDB"
+       select DEFAULT_UIMAGE
+       select QUICC_ENGINE
+       help
+         This option enables support for the MPC8323 RDB board.
+
 config MPC834x_MDS
        bool "Freescale MPC834x MDS"
        select DEFAULT_UIMAGE
@@ -57,7 +62,7 @@ config PPC_MPC832x
        bool
        select PPC_UDBG_16550
        select PPC_INDIRECT_PCI
-       default y if MPC832x_MDS
+       default y if MPC832x_MDS || MPC832x_RDB
 
 config MPC834x
        bool
@@ -70,5 +75,3 @@ config PPC_MPC836x
        select PPC_UDBG_16550
        select PPC_INDIRECT_PCI
        default y if MPC836x_MDS
-
-endmenu
index dfc970d0df108250ea4c9624da495862945ce67d..31a91b53f52825fde3fb639f19d4f919370534ae 100644 (file)
@@ -4,6 +4,7 @@
 obj-y                          := misc.o
 obj-$(CONFIG_PCI)              += pci.o
 obj-$(CONFIG_MPC8313_RDB)      += mpc8313_rdb.o
+obj-$(CONFIG_MPC832x_RDB)      += mpc832x_rdb.o
 obj-$(CONFIG_MPC834x_MDS)      += mpc834x_mds.o
 obj-$(CONFIG_MPC834x_ITX)      += mpc834x_itx.o
 obj-$(CONFIG_MPC836x_MDS)      += mpc836x_mds.o
index 17e3a3c6d8b4e45a198c87008d757e69af51da7d..fff09f5d6edfc126c2db322e868efa714fad71e3 100644 (file)
@@ -41,7 +41,6 @@
 #include <asm/qe_ic.h>
 
 #include "mpc83xx.h"
-#include "mpc832x_mds.h"
 
 #undef DEBUG
 #ifdef DEBUG
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.h b/arch/powerpc/platforms/83xx/mpc832x_mds.h
deleted file mode 100644 (file)
index a495889..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Description:
- * MPC832x MDS board specific header.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#ifndef __MACH_MPC832x_MDS_H__
-#define __MACH_MPC832x_MDS_H__
-
-extern u8 *get_bcsr(void);
-
-#endif                         /* __MACH_MPC832x_MDS_H__ */
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
new file mode 100644 (file)
index 0000000..6b71e9f
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * arch/powerpc/platforms/83xx/mpc832x_rdb.c
+ *
+ * Copyright (C) Freescale Semiconductor, Inc. 2007. All rights reserved.
+ *
+ * Description:
+ * MPC832x RDB board specific routines.
+ * This file is based on mpc832x_mds.c and mpc8313_rdb.c
+ * Author: Michael Barkowski <michael.barkowski@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/pci.h>
+
+#include <asm/of_platform.h>
+#include <asm/time.h>
+#include <asm/ipic.h>
+#include <asm/udbg.h>
+#include <asm/qe.h>
+#include <asm/qe_ic.h>
+
+#include "mpc83xx.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init mpc832x_rdb_setup_arch(void)
+{
+       struct device_node *np;
+
+       if (ppc_md.progress)
+               ppc_md.progress("mpc832x_rdb_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+       for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+               add_bridge(np);
+
+       ppc_md.pci_exclude_device = mpc83xx_exclude_device;
+#endif
+
+#ifdef CONFIG_QUICC_ENGINE
+       qe_reset();
+
+       if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
+               par_io_init(np);
+               of_node_put(np);
+
+               for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;)
+                       par_io_of_config(np);
+       }
+#endif                         /* CONFIG_QUICC_ENGINE */
+}
+
+static struct of_device_id mpc832x_ids[] = {
+       { .type = "soc", },
+       { .compatible = "soc", },
+       { .type = "qe", },
+       {},
+};
+
+static int __init mpc832x_declare_of_platform_devices(void)
+{
+       if (!machine_is(mpc832x_rdb))
+               return 0;
+
+       /* Publish the QE devices */
+       of_platform_bus_probe(NULL, mpc832x_ids, NULL);
+
+       return 0;
+}
+device_initcall(mpc832x_declare_of_platform_devices);
+
+void __init mpc832x_rdb_init_IRQ(void)
+{
+
+       struct device_node *np;
+
+       np = of_find_node_by_type(NULL, "ipic");
+       if (!np)
+               return;
+
+       ipic_init(np, 0);
+
+       /* Initialize the default interrupt mapping priorities,
+        * in case the boot rom changed something on us.
+        */
+       ipic_set_default_priority();
+       of_node_put(np);
+
+#ifdef CONFIG_QUICC_ENGINE
+       np = of_find_node_by_type(NULL, "qeic");
+       if (!np)
+               return;
+
+       qe_ic_init(np, 0);
+       of_node_put(np);
+#endif                         /* CONFIG_QUICC_ENGINE */
+}
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc832x_rdb_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "MPC832xRDB");
+}
+
+define_machine(mpc832x_rdb) {
+       .name           = "MPC832x RDB",
+       .probe          = mpc832x_rdb_probe,
+       .setup_arch     = mpc832x_rdb_setup_arch,
+       .init_IRQ       = mpc832x_rdb_init_IRQ,
+       .get_irq        = ipic_get_irq,
+       .restart        = mpc83xx_restart,
+       .time_init      = mpc83xx_time_init,
+       .calibrate_decr = generic_calibrate_decr,
+       .progress       = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.h b/arch/powerpc/platforms/83xx/mpc834x_itx.h
deleted file mode 100644 (file)
index 174ca4e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * arch/powerpc/platforms/83xx/mpc834x_itx.h
- *
- * MPC834X ITX common board definitions
- *
- * Maintainer: Kumar Gala <galak@kernel.crashing.org>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#ifndef __MACH_MPC83XX_ITX_H__
-#define __MACH_MPC83XX_ITX_H__
-
-#define PIRQA  MPC83xx_IRQ_EXT4
-#define PIRQB  MPC83xx_IRQ_EXT5
-#define PIRQC  MPC83xx_IRQ_EXT6
-#define PIRQD  MPC83xx_IRQ_EXT7
-
-#endif                         /* __MACH_MPC83XX_ITX_H__ */
index 9c3650555144d91b8a4d9ebdd8a9a0915ad2263c..774457d09e947af0c43ef8cd9d4f99b780e1bd8d 100644 (file)
@@ -60,7 +60,7 @@ int __init add_bridge(struct device_node *dev)
        has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
 
        /* Get bus range if any */
-       bus_range = get_property(dev, "bus-range", &len);
+       bus_range = of_get_property(dev, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                printk(KERN_WARNING "Can't get bus-range for %s, assume"
                       " bus 0\n", dev->full_name);
index e764c0aced88ae6b3d7a752a6766dc6a6ef362c8..629926e01e90217a9f08b392f656e221a817114b 100644 (file)
@@ -1,8 +1,6 @@
-menu "Platform support"
-       depends on PPC_85xx
-
 choice
        prompt "Machine Type"
+       depends on PPC_85xx
        default MPC8540_ADS
 
 config MPC8540_ADS
@@ -30,6 +28,12 @@ config MPC85xx_MDS
        help
          This option enables support for the MPC85xx MDS board
 
+config MPC8544_DS
+       bool "Freescale MPC8544 DS"
+       select DEFAULT_UIMAGE
+       help
+         This option enables support for the MPC8544 DS board
+
 endchoice
 
 config MPC8540
@@ -40,33 +44,15 @@ config MPC8540
 
 config MPC8560
        bool
-       select PPC_INDIRECT_PCI
+       select CPM2
        default y if MPC8560_ADS
 
 config MPC85xx
        bool
        select PPC_UDBG_16550
        select PPC_INDIRECT_PCI
+       select PPC_INDIRECT_PCI_BE
+       select MPIC
        select SERIAL_8250_SHARE_IRQ if SERIAL_8250
-       default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS || MPC85xx_MDS
-
-config PPC_INDIRECT_PCI_BE
-       bool
-       depends on PPC_85xx
-       default y
-
-config MPIC
-       bool
-       default y
-
-config CPM2
-       bool
-       depends on MPC8560
-       default y
-       help
-         The CPM2 (Communications Processor Module) is a coprocessor on
-         embedded CPUs made by Motorola.  Selecting this option means that
-         you wish to build a kernel for a machine with a CPM2 coprocessor
-         on it.
-
-endmenu
+       default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS \
+               || MPC85xx_MDS || MPC8544_DS
index 4e63917ada9d4651744f0c08dfd4eeec892b8828..4e02cbb14cf7460d65c34a8d4c1b03850b9371de 100644 (file)
@@ -5,4 +5,5 @@ obj-$(CONFIG_PPC_85xx)  += misc.o pci.o
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
+obj-$(CONFIG_MPC8544_DS)  += mpc8544_ds.o
 obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
diff --git a/arch/powerpc/platforms/85xx/mpc8544_ds.c b/arch/powerpc/platforms/85xx/mpc8544_ds.c
new file mode 100644 (file)
index 0000000..2867f85
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * MPC8544 DS Board Setup
+ *
+ * Author Xianghua Xiao (x.xiao@freescale.com)
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/mpc85xx.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+#include <asm/i8259.h>
+
+#include <sysdev/fsl_soc.h>
+#include "mpc85xx.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+
+void __init mpc8544_ds_pic_init(void)
+{
+       struct mpic *mpic;
+       struct resource r;
+       struct device_node *np = NULL;
+#ifdef CONFIG_PPC_I8259
+       struct device_node *cascade_node = NULL;
+       int cascade_irq;
+#endif
+
+       np = of_find_node_by_type(np, "open-pic");
+
+       if (np == NULL) {
+               printk(KERN_ERR "Could not find open-pic node\n");
+               return;
+       }
+
+       if (of_address_to_resource(np, 0, &r)) {
+               printk(KERN_ERR "Failed to map mpic register space\n");
+               of_node_put(np);
+               return;
+       }
+
+       /* Alloc mpic structure and per isu has 16 INT entries. */
+       mpic = mpic_alloc(np, r.start,
+                         MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+                         16, 64, " OPENPIC     ");
+       BUG_ON(mpic == NULL);
+
+       /*
+        * 48 Internal Interrupts
+        */
+       mpic_assign_isu(mpic, 0, r.start + 0x10200);
+       mpic_assign_isu(mpic, 1, r.start + 0x10400);
+       mpic_assign_isu(mpic, 2, r.start + 0x10600);
+
+       /*
+        * 16 External interrupts
+        */
+       mpic_assign_isu(mpic, 3, r.start + 0x10000);
+
+       mpic_init(mpic);
+
+#ifdef CONFIG_PPC_I8259
+       /* Initialize the i8259 controller */
+       for_each_node_by_type(np, "interrupt-controller")
+           if (device_is_compatible(np, "chrp,iic")) {
+               cascade_node = np;
+               break;
+       }
+
+       if (cascade_node == NULL) {
+               printk(KERN_DEBUG "Could not find i8259 PIC\n");
+               return;
+       }
+
+       cascade_irq = irq_of_parse_and_map(cascade_node, 0);
+       if (cascade_irq == NO_IRQ) {
+               printk(KERN_ERR "Failed to map cascade interrupt\n");
+               return;
+       }
+
+       DBG("mpc8544ds: cascade mapped to irq %d\n", cascade_irq);
+
+       i8259_init(cascade_node, 0);
+       of_node_put(cascade_node);
+
+       set_irq_chained_handler(cascade_irq, mpc8544_8259_cascade);
+#endif /* CONFIG_PPC_I8259 */
+}
+
+
+/*
+ * Setup the architecture
+ */
+static void __init mpc8544_ds_setup_arch(void)
+{
+       if (ppc_md.progress)
+               ppc_md.progress("mpc8544_ds_setup_arch()", 0);
+
+       printk("MPC8544 DS board from Freescale Semiconductor\n");
+}
+
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mpc8544_ds_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "MPC8544DS");
+}
+
+define_machine(mpc8544_ds) {
+       .name                   = "MPC8544 DS",
+       .probe                  = mpc8544_ds_probe,
+       .setup_arch             = mpc8544_ds_setup_arch,
+       .init_IRQ               = mpc8544_ds_pic_init,
+       .get_irq                = mpic_get_irq,
+       .restart                = mpc85xx_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
index 8ed034aeca5f139acfac1875e6a3a19058b4c8e6..5d27621f09272af77d520afbdb7c1f29a0ebc303 100644 (file)
@@ -227,7 +227,7 @@ static void __init mpc85xx_ads_setup_arch(void)
        if (cpu != 0) {
                const unsigned int *fp;
 
-               fp = get_property(cpu, "clock-frequency", NULL);
+               fp = of_get_property(cpu, "clock-frequency", NULL);
                if (fp != 0)
                        loops_per_jiffy = *fp / HZ;
                else
index 4232686be441b4e534777c658e2f352223546114..7e71636f90981a1767e8738b25afa014574a865a 100644 (file)
@@ -237,7 +237,7 @@ static void __init mpc85xx_cds_setup_arch(void)
        if (cpu != 0) {
                const unsigned int *fp;
 
-               fp = get_property(cpu, "clock-frequency", NULL);
+               fp = of_get_property(cpu, "clock-frequency", NULL);
                if (fp != 0)
                        loops_per_jiffy = *fp / HZ;
                else
index 81144d2ae455a0f75e31535301467176a094d775..54db41689954c4342733c09d5f19422deaf4fbbb 100644 (file)
@@ -80,7 +80,7 @@ static void __init mpc85xx_mds_setup_arch(void)
        np = of_find_node_by_type(NULL, "cpu");
        if (np != NULL) {
                const unsigned int *fp =
-                   get_property(np, "clock-frequency", NULL);
+                   of_get_property(np, "clock-frequency", NULL);
                if (fp != NULL)
                        loops_per_jiffy = *fp / HZ;
                else
index 05930eeb6e7f8c53886235f16cdbb056611700d9..48f17e23d771ff0492f8dc9cc46efc753f420555 100644 (file)
@@ -51,7 +51,7 @@ int __init add_bridge(struct device_node *dev)
        has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
 
        /* Get bus range if any */
-       bus_range = get_property(dev, "bus-range", &len);
+       bus_range = of_get_property(dev, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                printk(KERN_WARNING "Can't get bus-range for %s, assume"
                       " bus 0\n", dev->full_name);
index 0c70944d0e37464825b19fe2a68d4dafdc1863e1..d1bcff5004645ea33ca237a55c32e9ad8c04d9c4 100644 (file)
@@ -1,8 +1,6 @@
-menu "Platform Support"
-       depends on PPC_86xx
-
 choice
        prompt "Machine Type"
+       depends on PPC_86xx
        default MPC8641_HPCN
 
 config MPC8641_HPCN
@@ -14,20 +12,10 @@ config MPC8641_HPCN
 
 endchoice
 
-
 config MPC8641
        bool
        select PPC_INDIRECT_PCI
+       select PPC_INDIRECT_PCI_BE
        select PPC_UDBG_16550
+       select MPIC
        default y if MPC8641_HPCN
-
-config MPIC
-       bool
-       default y
-
-config PPC_INDIRECT_PCI_BE
-       bool
-       depends on PPC_86xx
-       default y
-
-endmenu
index 476a6eeee710d314eb2ad4eba2a2987b71d5d9aa..418fd8f4d26805b37e05ecd02d70f10eb03d5764 100644 (file)
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_SMP)              += mpc86xx_smp.o
 obj-$(CONFIG_MPC8641_HPCN)     += mpc86xx_hpcn.o
-obj-$(CONFIG_PCI)              += pci.o mpc86xx_pcie.o
+obj-$(CONFIG_PCI)              += pci.o
index f42f801cf84ed6af33e7ed21b3110a8a93d0629f..3d3d98f5bd4acb4e7b4585bb73d36dd62c40615a 100644 (file)
@@ -349,7 +349,7 @@ mpc86xx_hpcn_setup_arch(void)
        if (np != 0) {
                const unsigned int *fp;
 
-               fp = get_property(np, "clock-frequency", NULL);
+               fp = of_get_property(np, "clock-frequency", NULL);
                if (fp != 0)
                        loops_per_jiffy = *fp / HZ;
                else
@@ -384,7 +384,7 @@ mpc86xx_hpcn_show_cpuinfo(struct seq_file *m)
 
        root = of_find_node_by_path("/");
        if (root)
-               model = get_property(root, "model", NULL);
+               model = of_get_property(root, "model", NULL);
        seq_printf(m, "Machine\t\t: %s\n", model);
        of_node_put(root);
 
index 481e18ed5be94ff7ea65abc6b3a9586567d1ec4a..8235c562661fc356794c5d04573fda545afe36f0 100644 (file)
@@ -22,9 +22,9 @@
 #include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/prom.h>
-#include <asm/immap_86xx.h>
 #include <asm/pci-bridge.h>
 #include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pcie.h>
 
 #include "mpc86xx.h"
 
@@ -163,7 +163,7 @@ int __init add_bridge(struct device_node *dev)
        has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
 
        /* Get bus range if any */
-       bus_range = get_property(dev, "bus-range", &len);
+       bus_range = of_get_property(dev, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int))
                printk(KERN_WARNING "Can't get bus-range for %s, assume"
                       " bus 0\n", dev->full_name);
index beea6834bb7e351f4a90913327893f496ef4013e..39bb8c5ebe700c30c057cf5648c3b200dcf9b05b 100644 (file)
@@ -1,6 +1,3 @@
-menu "Platform support"
-        depends on PPC_8xx
-
 config FADS
        bool
 
@@ -9,6 +6,7 @@ config CPM1
 
 choice
        prompt "8xx Machine Type"
+       depends on PPC_8xx
        depends on 8xx
        default MPC885ADS
 
@@ -36,38 +34,36 @@ config MPC885ADS
 endchoice
 
 menu "Freescale Ethernet driver platform-specific options"
-        depends on (FS_ENET && MPC885ADS)
-
-        config MPC8xx_SECOND_ETH
-        bool "Second Ethernet channel"
-        depends on MPC885ADS
-        default y
-        help
-          This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
-          The latter will use SCC1, for 885ADS you can select it below.
-
-        choice
-                prompt "Second Ethernet channel"
-                depends on MPC8xx_SECOND_ETH
-                default MPC8xx_SECOND_ETH_FEC2
-
-                config MPC8xx_SECOND_ETH_FEC2
-                bool "FEC2"
-                depends on MPC885ADS
-                help
-                  Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
-                  (often 2-nd UART) will not work if this is enabled.
-
-                config MPC8xx_SECOND_ETH_SCC3
-                bool "SCC3"
-                depends on MPC885ADS
-                help
-                  Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
-                  (often 1-nd UART) will not work if this is enabled.
-
-        endchoice
+       depends on (FS_ENET && MPC885ADS)
 
-endmenu
+       config MPC8xx_SECOND_ETH
+       bool "Second Ethernet channel"
+       depends on MPC885ADS
+       default y
+       help
+         This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
+         The latter will use SCC1, for 885ADS you can select it below.
+
+       choice
+               prompt "Second Ethernet channel"
+               depends on MPC8xx_SECOND_ETH
+               default MPC8xx_SECOND_ETH_FEC2
+
+               config MPC8xx_SECOND_ETH_FEC2
+               bool "FEC2"
+               depends on MPC885ADS
+               help
+                 Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
+                 (often 2-nd UART) will not work if this is enabled.
+
+               config MPC8xx_SECOND_ETH_SCC3
+               bool "SCC3"
+               depends on MPC885ADS
+               help
+                 Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
+                 (often 1-nd UART) will not work if this is enabled.
+
+       endchoice
 
 endmenu
 
@@ -98,7 +94,7 @@ config 8xx_CPU6
          require workarounds for Linux (and most other OSes to work).  If you
          get a BUG() very early in boot, this might fix the problem.  For
          more details read the document entitled "MPC860 Family Device Errata
-         Reference" on Motorola's website.  This option also incurs a
+         Reference" on Freescale's website.  This option also incurs a
          performance hit.
 
          If in doubt, say N here.
@@ -135,4 +131,3 @@ config UCODE_PATCH
        depends on !NO_UCODE_PATCH
 
 endmenu
-
index 9ed7125f015000f502015932412ec26916b07326..0901dbada3500e085be2ddf26f882e6384c56371 100644 (file)
@@ -85,17 +85,17 @@ init_internal_rtc(void)
 static int __init get_freq(char *name, unsigned long *val)
 {
         struct device_node *cpu;
-        unsigned int *fp;
+        const unsigned int *fp;
         int found = 0;
 
         /* The cpu node should have timebase and clock frequency properties */
         cpu = of_find_node_by_type(NULL, "cpu");
 
         if (cpu) {
-                fp = (unsigned int *)get_property(cpu, name, NULL);
+                fp = of_get_property(cpu, name, NULL);
                 if (fp) {
                         found = 1;
-                        *val = *fp++;
+                        *val = *fp;
                 }
 
                 of_node_put(cpu);
@@ -262,7 +262,7 @@ void mpc8xx_show_cpuinfo(struct seq_file *m)
 
        root = of_find_node_by_path("/");
        if (root)
-               model = get_property(root, "model", NULL);
+               model = of_get_property(root, "model", NULL);
        seq_printf(m, "Machine\t\t: %s\n", model);
        of_node_put(root);
 
index b5d19dd0619c2c0d8f61bca0500d67cc9198ada9..59bad2f9ae51a22861157b8da92ea0f5a2fb0822 100644 (file)
@@ -37,7 +37,7 @@
 #define CPM_MAP_ADDR           (get_immrbase() + MPC8xx_CPM_OFFSET)
 #define CPM_IRQ_OFFSET         16     // for compability with cpm_uart driver
 
-#define PCMCIA_MEM_ADDR                (uint)0xff020000)
+#define PCMCIA_MEM_ADDR                ((uint)0xff020000)
 #define PCMCIA_MEM_SIZE                ((uint)(64 * 1024))
 
 /* Bits of interest in the BCSRs.
index ef52ce701b0e1fc16afa887ac267192ed9494b38..a35315af5c532fa84ed3a6be3580f31c2e2676a8 100644 (file)
@@ -247,7 +247,7 @@ void init_smc_ioports(struct fs_uart_platform_info *data)
        }
 }
 
-int platform_device_skip(char *model, int id)
+int platform_device_skip(const char *model, int id)
 {
        return 0;
 }
@@ -260,7 +260,7 @@ static void __init mpc86xads_setup_arch(void)
        if (cpu != 0) {
                const unsigned int *fp;
 
-               fp = get_property(cpu, "clock-frequency", NULL);
+               fp = of_get_property(cpu, "clock-frequency", NULL);
                if (fp != 0)
                        loops_per_jiffy = *fp / HZ;
                else
index 30cbebfe84c549a0916c01ffd833b426dc08a7fc..7c31aec284c26cb575bc2a455f5007a1e37de7f7 100644 (file)
@@ -37,7 +37,7 @@
 #define CPM_MAP_ADDR           (get_immrbase() + MPC8xx_CPM_OFFSET)
 #define CPM_IRQ_OFFSET         16     // for compability with cpm_uart driver
 
-#define PCMCIA_MEM_ADDR                (uint)0xff020000)
+#define PCMCIA_MEM_ADDR                ((uint)0xff020000)
 #define PCMCIA_MEM_SIZE                ((uint)(64 * 1024))
 
 /* Bits of interest in the BCSRs.
index c5fefdf66c0aa3ac8880b242097a50e35c8ed254..a57b57785acd854c2598251ecf1206a9646d0a6d 100644 (file)
@@ -322,7 +322,7 @@ void init_smc_ioports(struct fs_uart_platform_info *data)
        }
 }
 
-int platform_device_skip(char *model, int id)
+int platform_device_skip(const char *model, int id)
 {
 #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
        const char *dev = "FEC";
@@ -346,7 +346,7 @@ static void __init mpc885ads_setup_arch(void)
        if (cpu != 0) {
                const unsigned int *fp;
 
-               fp = get_property(cpu, "clock-frequency", NULL);
+               fp = of_get_property(cpu, "clock-frequency", NULL);
                if (fp != 0)
                        loops_per_jiffy = *fp / HZ;
                else
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
new file mode 100644 (file)
index 0000000..51e3334
--- /dev/null
@@ -0,0 +1,259 @@
+menu "Platform support"
+
+choice
+       prompt "Machine type"
+       depends on PPC64 || CLASSIC32
+       default PPC_MULTIPLATFORM
+
+config PPC_MULTIPLATFORM
+       bool "Generic desktop/server/laptop"
+       help
+         Select this option if configuring for an IBM pSeries or
+         RS/6000 machine, an Apple machine, or a PReP, CHRP,
+         Maple or Cell-based machine.
+
+config EMBEDDED6xx
+       bool "Embedded 6xx/7xx/7xxx-based board"
+       depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
+
+config APUS
+       bool "Amiga-APUS"
+       depends on PPC32 && BROKEN
+       help
+         Select APUS if configuring for a PowerUP Amiga.
+         More information is available at:
+         <http://linux-apus.sourceforge.net/>.
+endchoice
+
+source "arch/powerpc/platforms/pseries/Kconfig"
+source "arch/powerpc/platforms/iseries/Kconfig"
+source "arch/powerpc/platforms/chrp/Kconfig"
+source "arch/powerpc/platforms/52xx/Kconfig"
+source "arch/powerpc/platforms/powermac/Kconfig"
+source "arch/powerpc/platforms/prep/Kconfig"
+source "arch/powerpc/platforms/maple/Kconfig"
+source "arch/powerpc/platforms/pasemi/Kconfig"
+source "arch/powerpc/platforms/celleb/Kconfig"
+source "arch/powerpc/platforms/ps3/Kconfig"
+source "arch/powerpc/platforms/cell/Kconfig"
+source "arch/powerpc/platforms/8xx/Kconfig"
+source "arch/powerpc/platforms/82xx/Kconfig"
+source "arch/powerpc/platforms/83xx/Kconfig"
+source "arch/powerpc/platforms/85xx/Kconfig"
+source "arch/powerpc/platforms/86xx/Kconfig"
+source "arch/powerpc/platforms/embedded6xx/Kconfig"
+#source "arch/powerpc/platforms/4xx/Kconfig
+
+config PPC_NATIVE
+       bool
+       depends on PPC_MULTIPLATFORM
+       help
+         Support for running natively on the hardware, i.e. without
+         a hypervisor. This option is not user-selectable but should
+         be selected by all platforms that need it.
+
+config UDBG_RTAS_CONSOLE
+       bool "RTAS based debug console"
+       depends on PPC_RTAS
+       default n
+
+config PPC_UDBG_BEAT
+       bool "BEAT based debug console"
+       depends on PPC_CELLEB
+       default n
+
+config XICS
+       depends on PPC_PSERIES
+       bool
+       default y
+
+config MPIC
+       bool
+       default n
+
+config MPIC_WEIRD
+       bool
+       default n
+
+config PPC_I8259
+       bool
+       default n
+
+config U3_DART
+       bool
+       depends on PPC_MULTIPLATFORM && PPC64
+       default n
+
+config PPC_RTAS
+       bool
+       default n
+
+config RTAS_ERROR_LOGGING
+       bool
+       depends on PPC_RTAS
+       default n
+
+config RTAS_PROC
+       bool "Proc interface to RTAS"
+       depends on PPC_RTAS
+       default y
+
+config RTAS_FLASH
+       tristate "Firmware flash interface"
+       depends on PPC64 && RTAS_PROC
+
+config PPC_PMI
+       tristate "Support for PMI"
+       depends PPC_IBM_CELL_BLADE
+       help
+         PMI (Platform Management Interrupt) is a way to
+         communicate with the BMC (Baseboard Mangement Controller).
+         It is used in some IBM Cell blades.
+       default m
+
+config MMIO_NVRAM
+       bool
+       default n
+
+config MPIC_U3_HT_IRQS
+       bool
+       depends on PPC_MAPLE
+       default y
+
+config IBMVIO
+       depends on PPC_PSERIES || PPC_ISERIES
+       bool
+       default y
+
+config IBMEBUS
+       depends on PPC_PSERIES
+       bool "Support for GX bus based adapters"
+       help
+         Bus device driver for GX bus based adapters.
+
+config PPC_MPC106
+       bool
+       default n
+
+config PPC_970_NAP
+       bool
+       default n
+
+config PPC_INDIRECT_IO
+       bool
+       select GENERIC_IOMAP
+       default n
+
+config GENERIC_IOMAP
+       bool
+       default n
+
+source "drivers/cpufreq/Kconfig"
+
+menu "CPU Frequency drivers"
+       depends on CPU_FREQ
+
+config CPU_FREQ_PMAC
+       bool "Support for Apple PowerBooks"
+       depends on ADB_PMU && PPC32
+       select CPU_FREQ_TABLE
+       help
+         This adds support for frequency switching on Apple PowerBooks,
+         this currently includes some models of iBook & Titanium
+         PowerBook.
+
+config CPU_FREQ_PMAC64
+       bool "Support for some Apple G5s"
+       depends on PPC_PMAC && PPC64
+       select CPU_FREQ_TABLE
+       help
+         This adds support for frequency switching on Apple iMac G5,
+         and some of the more recent desktop G5 machines as well.
+
+config PPC_PASEMI_CPUFREQ
+       bool "Support for PA Semi PWRficient"
+       depends on PPC_PASEMI
+       default y
+       select CPU_FREQ_TABLE
+       help
+         This adds the support for frequency switching on PA Semi
+         PWRficient processors.
+
+endmenu
+
+config PPC601_SYNC_FIX
+       bool "Workarounds for PPC601 bugs"
+       depends on 6xx && (PPC_PREP || PPC_PMAC)
+       help
+         Some versions of the PPC601 (the first PowerPC chip) have bugs which
+         mean that extra synchronization instructions are required near
+         certain instructions, typically those that make major changes to the
+         CPU state.  These extra instructions reduce performance slightly.
+         If you say N here, these extra instructions will not be included,
+         resulting in a kernel which will run faster but may not run at all
+         on some systems with the PPC601 chip.
+
+         If in doubt, say Y here.
+
+config TAU
+       bool "On-chip CPU temperature sensor support"
+       depends on CLASSIC32
+       help
+         G3 and G4 processors have an on-chip temperature sensor called the
+         'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
+         temperature within 2-4 degrees Celsius. This option shows the current
+         on-die temperature in /proc/cpuinfo if the cpu supports it.
+
+         Unfortunately, on some chip revisions, this sensor is very inaccurate
+         and in many cases, does not work at all, so don't assume the cpu
+         temp is actually what /proc/cpuinfo says it is.
+
+config TAU_INT
+       bool "Interrupt driven TAU driver (DANGEROUS)"
+       depends on TAU
+       ---help---
+         The TAU supports an interrupt driven mode which causes an interrupt
+         whenever the temperature goes out of range. This is the fastest way
+         to get notified the temp has exceeded a range. With this option off,
+         a timer is used to re-check the temperature periodically.
+
+         However, on some cpus it appears that the TAU interrupt hardware
+         is buggy and can cause a situation which would lead unexplained hard
+         lockups.
+
+         Unless you are extending the TAU driver, or enjoy kernel/hardware
+         debugging, leave this option off.
+
+config TAU_AVERAGE
+       bool "Average high and low temp"
+       depends on TAU
+       ---help---
+         The TAU hardware can compare the temperature to an upper and lower
+         bound.  The default behavior is to show both the upper and lower
+         bound in /proc/cpuinfo. If the range is large, the temperature is
+         either changing a lot, or the TAU hardware is broken (likely on some
+         G4's). If the range is small (around 4 degrees), the temperature is
+         relatively stable.  If you say Y here, a single temperature value,
+         halfway between the upper and lower bounds, will be reported in
+         /proc/cpuinfo.
+
+         If in doubt, say N here.
+
+config QUICC_ENGINE
+       bool
+       help
+         The QUICC Engine (QE) is a new generation of communications
+         coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
+         Selecting this option means that you wish to build a kernel
+         for a machine with a QE coprocessor.
+
+config CPM2
+       bool
+       default n
+       help
+         The CPM2 (Communications Processor Module) is a coprocessor on
+         embedded CPUs made by Freescale.  Selecting this option means that
+         you wish to build a kernel for a machine with a CPM2 coprocessor
+         on it (826x, 827x, 8560).
+
+endmenu
index 06a85b7043315550dadf0c63bdfe38acaa7c8aa2..82551770917c5e7fb66eec807550b18d4b5e029b 100644 (file)
@@ -1,3 +1,26 @@
+config PPC_CELL
+       bool
+       default n
+
+config PPC_CELL_NATIVE
+       bool
+       select PPC_CELL
+       select PPC_DCR_MMIO
+       select PPC_OF_PLATFORM_PCI
+       select PPC_INDIRECT_IO
+       select PPC_NATIVE
+       select MPIC
+       default n
+
+config PPC_IBM_CELL_BLADE
+       bool "IBM Cell Blade"
+       depends on PPC_MULTIPLATFORM && PPC64
+       select PPC_CELL_NATIVE
+       select PPC_RTAS
+       select MMIO_NVRAM
+       select PPC_UDBG_16550
+       select UDBG_RTAS_CONSOLE
+
 menu "Cell Broadband Engine options"
        depends on PPC_CELL
 
@@ -18,6 +41,7 @@ config SPU_BASE
 
 config CBE_RAS
        bool "RAS features for bare metal Cell BE"
+       depends on PPC_CELL_NATIVE
        default y
 
 config CBE_THERM
index a3850fd1e94c854694b8517742c22523beda2a4e..f9ac3fe3be9767fbf04a73296dfc365d3efbbec7 100644 (file)
 
 #include <asm/hw_irq.h>
 #include <asm/io.h>
+#include <asm/machdep.h>
 #include <asm/processor.h>
 #include <asm/prom.h>
 #include <asm/time.h>
+#include <asm/pmi.h>
+#include <asm/of_platform.h>
 
 #include "cbe_regs.h"
 
@@ -68,6 +71,38 @@ static u64 MIC_Slow_Next_Timer_table[] = {
  * hardware specific functions
  */
 
+static struct of_device *pmi_dev;
+
+static int set_pmode_pmi(int cpu, unsigned int pmode)
+{
+       int ret;
+       pmi_message_t pmi_msg;
+#ifdef DEBUG
+       u64 time;
+#endif
+
+       pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
+       pmi_msg.data1 = cbe_cpu_to_node(cpu);
+       pmi_msg.data2 = pmode;
+
+#ifdef DEBUG
+       time = (u64) get_cycles();
+#endif
+
+       pmi_send_message(pmi_dev, pmi_msg);
+       ret = pmi_msg.data2;
+
+       pr_debug("PMI returned slow mode %d\n", ret);
+
+#ifdef DEBUG
+       time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */
+       time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */
+       pr_debug("had to wait %lu ns for a transition\n", time);
+#endif
+       return ret;
+}
+
+
 static int get_pmode(int cpu)
 {
        int ret;
@@ -79,7 +114,7 @@ static int get_pmode(int cpu)
        return ret;
 }
 
-static int set_pmode(int cpu, unsigned int pmode)
+static int set_pmode_reg(int cpu, unsigned int pmode)
 {
        struct cbe_pmd_regs __iomem *pmd_regs;
        struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -120,37 +155,71 @@ static int set_pmode(int cpu, unsigned int pmode)
        return 0;
 }
 
+static int set_pmode(int cpu, unsigned int slow_mode) {
+       if (pmi_dev)
+               return set_pmode_pmi(cpu, slow_mode);
+       else
+               return set_pmode_reg(cpu, slow_mode);
+}
+
+static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg)
+{
+       struct cpufreq_policy policy;
+       u8 cpu;
+       u8 cbe_pmode_new;
+
+       BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+
+       cpu = cbe_node_to_cpu(pmi_msg.data1);
+       cbe_pmode_new = pmi_msg.data2;
+
+       cpufreq_get_policy(&policy, cpu);
+
+       policy.max = min(policy.max, cbe_freqs[cbe_pmode_new].frequency);
+       policy.min = min(policy.min, policy.max);
+
+       pr_debug("cbe_handle_pmi: new policy.min=%d policy.max=%d\n", policy.min, policy.max);
+       cpufreq_set_policy(&policy);
+}
+
+static struct pmi_handler cbe_pmi_handler = {
+       .type                   = PMI_TYPE_FREQ_CHANGE,
+       .handle_pmi_message     = cbe_cpufreq_handle_pmi,
+};
+
+
 /*
  * cpufreq functions
  */
 
-static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy)
+static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       u32 *max_freq;
+       const u32 *max_freqp;
+       u32 max_freq;
        int i, cur_pmode;
        struct device_node *cpu;
 
        cpu = of_get_cpu_node(policy->cpu, NULL);
 
-       if(!cpu)
+       if (!cpu)
                return -ENODEV;
 
        pr_debug("init cpufreq on CPU %d\n", policy->cpu);
 
-       max_freq = (u32*) get_property(cpu, "clock-frequency", NULL);
+       max_freqp = of_get_property(cpu, "clock-frequency", NULL);
 
-       if(!max_freq)
+       if (!max_freqp)
                return -EINVAL;
 
-       // we need the freq in kHz
-       *max_freq /= 1000;
+       /* we need the freq in kHz */
+       max_freq = *max_freqp / 1000;
 
-       pr_debug("max clock-frequency is at %u kHz\n", *max_freq);
+       pr_debug("max clock-frequency is at %u kHz\n", max_freq);
        pr_debug("initializing frequency table\n");
 
-       // initialize frequency table
+       /* initialize frequency table */
        for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
-               cbe_freqs[i].frequency = *max_freq / cbe_freqs[i].index;
+               cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index;
                pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
        }
 
@@ -167,10 +236,10 @@ static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy)
        policy->cpus = cpu_sibling_map[policy->cpu];
 #endif
 
-       cpufreq_frequency_table_get_attr (cbe_freqs, policy->cpu);
+       cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
 
        /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
-       return cpufreq_frequency_table_cpuinfo (policy, cbe_freqs);
+       return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
 }
 
 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
@@ -202,7 +271,7 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target
        freqs.new = cbe_freqs[cbe_pmode_new].frequency;
        freqs.cpu = policy->cpu;
 
-       mutex_lock (&cbe_switch_mutex);
+       mutex_lock(&cbe_switch_mutex);
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
        pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
@@ -233,11 +302,26 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
 
 static int __init cbe_cpufreq_init(void)
 {
+       struct device_node *np;
+
+       if (!machine_is(cell))
+               return -ENODEV;
+
+       np = of_find_node_by_type(NULL, "ibm,pmi");
+
+       pmi_dev = of_find_device_by_node(np);
+
+       if (pmi_dev)
+               pmi_register_handler(pmi_dev, &cbe_pmi_handler);
+
        return cpufreq_register_driver(&cbe_cpufreq_driver);
 }
 
 static void __exit cbe_cpufreq_exit(void)
 {
+       if (pmi_dev)
+               pmi_unregister_handler(pmi_dev, &cbe_pmi_handler);
+
        cpufreq_unregister_driver(&cbe_cpufreq_driver);
 }
 
index 9a0ee62691d529f69a90779e5bbe62cd7e5fbdcd..12c9674b4b1f27d51f20f590613a7f1afb1273be 100644 (file)
@@ -14,6 +14,8 @@
 #include <asm/pgtable.h>
 #include <asm/prom.h>
 #include <asm/ptrace.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
 
 #include "cbe_regs.h"
 
@@ -27,6 +29,7 @@
 static struct cbe_regs_map
 {
        struct device_node *cpu_node;
+       struct device_node *be_node;
        struct cbe_pmd_regs __iomem *pmd_regs;
        struct cbe_iic_regs __iomem *iic_regs;
        struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -37,30 +40,43 @@ static int cbe_regs_map_count;
 static struct cbe_thread_map
 {
        struct device_node *cpu_node;
+       struct device_node *be_node;
        struct cbe_regs_map *regs;
+       unsigned int thread_id;
+       unsigned int cbe_id;
 } cbe_thread_map[NR_CPUS];
 
+static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = CPU_MASK_NONE };
+static cpumask_t cbe_first_online_cpu = CPU_MASK_NONE;
+
 static struct cbe_regs_map *cbe_find_map(struct device_node *np)
 {
        int i;
        struct device_node *tmp_np;
 
-       if (strcasecmp(np->type, "spe") == 0) {
-               if (np->data == NULL) {
-                       /* walk up path until cpu node was found */
-                       tmp_np = np->parent;
-                       while (tmp_np != NULL && strcasecmp(tmp_np->type, "cpu") != 0)
-                               tmp_np = tmp_np->parent;
+       if (strcasecmp(np->type, "spe")) {
+               for (i = 0; i < cbe_regs_map_count; i++)
+                       if (cbe_regs_maps[i].cpu_node == np ||
+                           cbe_regs_maps[i].be_node == np)
+                               return &cbe_regs_maps[i];
+               return NULL;
+       }
 
-                       np->data = cbe_find_map(tmp_np);
-               }
+       if (np->data)
                return np->data;
-       }
 
-       for (i = 0; i < cbe_regs_map_count; i++)
-               if (cbe_regs_maps[i].cpu_node == np)
-                       return &cbe_regs_maps[i];
-       return NULL;
+       /* walk up path until cpu or be node was found */
+       tmp_np = np;
+       do {
+               tmp_np = tmp_np->parent;
+               /* on a correct devicetree we wont get up to root */
+               BUG_ON(!tmp_np);
+       } while (strcasecmp(tmp_np->type, "cpu") &&
+                strcasecmp(tmp_np->type, "be"));
+
+       np->data = cbe_find_map(tmp_np);
+
+       return np->data;
 }
 
 struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np)
@@ -130,38 +146,105 @@ struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu)
 }
 EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs);
 
-/* FIXME
- * This is little more than a stub at the moment.  It should be
- * fleshed out so that it works for both SMT and non-SMT, no
- * matter if the passed cpu is odd or even.
- * For SMT enabled, returns 0 for even-numbered cpu; otherwise 1.
- * For SMT disabled, returns 0 for all cpus.
- */
 u32 cbe_get_hw_thread_id(int cpu)
 {
-       return (cpu & 1);
+       return cbe_thread_map[cpu].thread_id;
 }
 EXPORT_SYMBOL_GPL(cbe_get_hw_thread_id);
 
-void __init cbe_regs_init(void)
+u32 cbe_cpu_to_node(int cpu)
 {
-       int i;
-       struct device_node *cpu;
+       return cbe_thread_map[cpu].cbe_id;
+}
+EXPORT_SYMBOL_GPL(cbe_cpu_to_node);
 
-       /* Build local fast map of CPUs */
-       for_each_possible_cpu(i)
-               cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL);
+u32 cbe_node_to_cpu(int node)
+{
+       return find_first_bit( (unsigned long *) &cbe_local_mask[node], sizeof(cpumask_t));
+}
+EXPORT_SYMBOL_GPL(cbe_node_to_cpu);
 
-       /* Find maps for each device tree CPU */
-       for_each_node_by_type(cpu, "cpu") {
-               struct cbe_regs_map *map = &cbe_regs_maps[cbe_regs_map_count++];
+static struct device_node *cbe_get_be_node(int cpu_id)
+{
+       struct device_node *np;
+
+       for_each_node_by_type (np, "be") {
+               int len,i;
+               const phandle *cpu_handle;
+
+               cpu_handle = of_get_property(np, "cpus", &len);
+
+               for (i=0; i<len; i++)
+                       if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL))
+                               return np;
+       }
+
+       return NULL;
+}
+
+void __init cbe_fill_regs_map(struct cbe_regs_map *map)
+{
+       if(map->be_node) {
+               struct device_node *be, *np;
+
+               be = map->be_node;
+
+               for_each_node_by_type(np, "pervasive")
+                       if (of_get_parent(np) == be)
+                               map->pmd_regs = of_iomap(np, 0);
+
+               for_each_node_by_type(np, "CBEA-Internal-Interrupt-Controller")
+                       if (of_get_parent(np) == be)
+                               map->iic_regs = of_iomap(np, 2);
 
+               for_each_node_by_type(np, "mic-tm")
+                       if (of_get_parent(np) == be)
+                               map->mic_tm_regs = of_iomap(np, 0);
+       } else {
+               struct device_node *cpu;
                /* That hack must die die die ! */
                const struct address_prop {
                        unsigned long address;
                        unsigned int len;
                } __attribute__((packed)) *prop;
 
+               cpu = map->cpu_node;
+
+               prop = of_get_property(cpu, "pervasive", NULL);
+               if (prop != NULL)
+                       map->pmd_regs = ioremap(prop->address, prop->len);
+
+               prop = of_get_property(cpu, "iic", NULL);
+               if (prop != NULL)
+                       map->iic_regs = ioremap(prop->address, prop->len);
+
+               prop = of_get_property(cpu, "mic-tm", NULL);
+               if (prop != NULL)
+                       map->mic_tm_regs = ioremap(prop->address, prop->len);
+       }
+}
+
+
+void __init cbe_regs_init(void)
+{
+       int i;
+       unsigned int thread_id;
+       struct device_node *cpu;
+
+       /* Build local fast map of CPUs */
+       for_each_possible_cpu(i) {
+               cbe_thread_map[i].cpu_node = of_get_cpu_node(i, &thread_id);
+               cbe_thread_map[i].be_node = cbe_get_be_node(i);
+               cbe_thread_map[i].thread_id = thread_id;
+       }
+
+       /* Find maps for each device tree CPU */
+       for_each_node_by_type(cpu, "cpu") {
+               struct cbe_regs_map *map;
+               unsigned int cbe_id;
+
+               cbe_id = cbe_regs_map_count++;
+               map = &cbe_regs_maps[cbe_id];
 
                if (cbe_regs_map_count > MAX_CBE) {
                        printk(KERN_ERR "cbe_regs: More BE chips than supported"
@@ -170,22 +253,21 @@ void __init cbe_regs_init(void)
                        return;
                }
                map->cpu_node = cpu;
-               for_each_possible_cpu(i)
-                       if (cbe_thread_map[i].cpu_node == cpu)
-                               cbe_thread_map[i].regs = map;
 
-               prop = get_property(cpu, "pervasive", NULL);
-               if (prop != NULL)
-                       map->pmd_regs = ioremap(prop->address, prop->len);
+               for_each_possible_cpu(i) {
+                       struct cbe_thread_map *thread = &cbe_thread_map[i];
 
-               prop = get_property(cpu, "iic", NULL);
-               if (prop != NULL)
-                       map->iic_regs = ioremap(prop->address, prop->len);
+                       if (thread->cpu_node == cpu) {
+                               thread->regs = map;
+                               thread->cbe_id = cbe_id;
+                               map->be_node = thread->be_node;
+                               cpu_set(i, cbe_local_mask[cbe_id]);
+                               if(thread->thread_id == 0)
+                                       cpu_set(i, cbe_first_online_cpu);
+                       }
+               }
 
-               prop = (struct address_prop *)get_property(cpu, "mic-tm",
-                                                          NULL);
-               if (prop != NULL)
-                       map->mic_tm_regs = ioremap(prop->address, prop->len);
+               cbe_fill_regs_map(map);
        }
 }
 
index 440a7ecc66eab1c3d2a894579c9dc399c7b9a351..17d5971448770bad9e042b2160f46ffb7c7044b8 100644 (file)
@@ -255,6 +255,11 @@ struct cbe_mic_tm_regs {
 extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np);
 extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu);
 
+/* some utility functions to deal with SMT */
+extern u32 cbe_get_hw_thread_id(int cpu);
+extern u32 cbe_cpu_to_node(int cpu);
+extern u32 cbe_node_to_cpu(int node);
+
 /* Init this module early */
 extern void cbe_regs_init(void);
 
index 70e0d968d30f9e5edd77efdc7ce01451586440e3..f370f0fa6f4c87222cd7f679af15b3fc7f00073e 100644 (file)
@@ -1,6 +1,31 @@
 /*
  * thermal support for the cell processor
  *
+ * This module adds some sysfs attributes to cpu and spu nodes.
+ * Base for measurements are the digital thermal sensors (DTS)
+ * located on the chip.
+ * The accuracy is 2 degrees, starting from 65 up to 125 degrees celsius
+ * The attributes can be found under
+ * /sys/devices/system/cpu/cpuX/thermal
+ * /sys/devices/system/spu/spuX/thermal
+ *
+ * The following attributes are added for each node:
+ * temperature:
+ *     contains the current temperature measured by the DTS
+ * throttle_begin:
+ *     throttling begins when temperature is greater or equal to
+ *     throttle_begin. Setting this value to 125 prevents throttling.
+ * throttle_end:
+ *     throttling is being ceased, if the temperature is lower than
+ *     throttle_end. Due to a delay between applying throttling and
+ *     a reduced temperature this value should be less than throttle_begin.
+ *     A value equal to throttle_begin provides only a very little hysteresis.
+ * throttle_full_stop:
+ *     If the temperatrue is greater or equal to throttle_full_stop,
+ *     full throttling is applied to the cpu or spu. This value should be
+ *     greater than throttle_begin and throttle_end. Setting this value to
+ *     65 prevents the unit from running code at all.
+ *
  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
  *
  * Author: Christian Krafft <krafft@de.ibm.com>
 #include "cbe_regs.h"
 #include "spu_priv1_mmio.h"
 
+#define TEMP_MIN 65
+#define TEMP_MAX 125
+
+#define SYSDEV_PREFIX_ATTR(_prefix,_name,_mode)                        \
+struct sysdev_attribute attr_ ## _prefix ## _ ## _name = {     \
+       .attr = { .name = __stringify(_name), .mode = _mode },  \
+       .show   = _prefix ## _show_ ## _name,                   \
+       .store  = _prefix ## _store_ ## _name,                  \
+};
+
+static inline u8 reg_to_temp(u8 reg_value)
+{
+       return ((reg_value & 0x3f) << 1) + TEMP_MIN;
+}
+
+static inline u8 temp_to_reg(u8 temp)
+{
+       return ((temp - TEMP_MIN) >> 1) & 0x3f;
+}
+
 static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
 {
        struct spu *spu;
@@ -43,14 +88,14 @@ static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
 /* returns the value for a given spu in a given register */
 static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg)
 {
-       unsigned int *id;
+       const unsigned int *id;
        union spe_reg value;
        struct spu *spu;
 
        /* getting the id from the reg attribute will not work on future device-tree layouts
         * in future we should store the id to the spu struct and use it here */
        spu = container_of(sysdev, struct spu, sysdev);
-       id = (unsigned int *)get_property(spu_devnode(spu), "reg", NULL);
+       id = of_get_property(spu_devnode(spu), "reg", NULL);
        value.val = in_be64(&reg->val);
 
        return value.spe[*id];
@@ -58,20 +103,81 @@ static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iom
 
 static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf)
 {
-       int value;
+       u8 value;
        struct cbe_pmd_regs __iomem *pmd_regs;
 
        pmd_regs = get_pmd_regs(sysdev);
 
        value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1);
-       /* clear all other bits */
+
+       return sprintf(buf, "%d\n", reg_to_temp(value));
+}
+
+static ssize_t show_throttle(struct cbe_pmd_regs __iomem *pmd_regs, char *buf, int pos)
+{
+       u64 value;
+
+       value = in_be64(&pmd_regs->tm_tpr.val);
+       /* access the corresponding byte */
+       value >>= pos;
        value &= 0x3F;
-       /* temp is stored in steps of 2 degrees */
-       value *= 2;
-       /* base temp is 65 degrees */
-       value += 65;
 
-       return sprintf(buf, "%d\n", (int) value);
+       return sprintf(buf, "%d\n", reg_to_temp(value));
+}
+
+static ssize_t store_throttle(struct cbe_pmd_regs __iomem *pmd_regs, const char *buf, size_t size, int pos)
+{
+       u64 reg_value;
+       int temp;
+       u64 new_value;
+       int ret;
+
+       ret = sscanf(buf, "%u", &temp);
+
+       if (ret != 1 || temp < TEMP_MIN || temp > TEMP_MAX)
+               return -EINVAL;
+
+       new_value = temp_to_reg(temp);
+
+       reg_value = in_be64(&pmd_regs->tm_tpr.val);
+
+       /* zero out bits for new value */
+       reg_value &= ~(0xffull << pos);
+       /* set bits to new value */
+       reg_value |= new_value << pos;
+
+       out_be64(&pmd_regs->tm_tpr.val, reg_value);
+       return size;
+}
+
+static ssize_t spu_show_throttle_end(struct sys_device *sysdev, char *buf)
+{
+       return show_throttle(get_pmd_regs(sysdev), buf, 0);
+}
+
+static ssize_t spu_show_throttle_begin(struct sys_device *sysdev, char *buf)
+{
+       return show_throttle(get_pmd_regs(sysdev), buf, 8);
+}
+
+static ssize_t spu_show_throttle_full_stop(struct sys_device *sysdev, char *buf)
+{
+       return show_throttle(get_pmd_regs(sysdev), buf, 16);
+}
+
+static ssize_t spu_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size)
+{
+       return store_throttle(get_pmd_regs(sysdev), buf, size, 0);
+}
+
+static ssize_t spu_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size)
+{
+       return store_throttle(get_pmd_regs(sysdev), buf, size, 8);
+}
+
+static ssize_t spu_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size)
+{
+       return store_throttle(get_pmd_regs(sysdev), buf, size, 16);
 }
 
 static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
@@ -82,16 +188,9 @@ static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
        pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
        value = in_be64(&pmd_regs->ts_ctsr2);
 
-       /* access the corresponding byte */
-       value >>= pos;
-       /* clear all other bits */
-       value &= 0x3F;
-       /* temp is stored in steps of 2 degrees */
-       value *= 2;
-       /* base temp is 65 degrees */
-       value += 65;
+       value = (value >> pos) & 0x3f;
 
-       return sprintf(buf, "%d\n", (int) value);
+       return sprintf(buf, "%d\n", reg_to_temp(value));
 }
 
 
@@ -108,13 +207,52 @@ static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf)
        return ppe_show_temp(sysdev, buf, 0);
 }
 
+static ssize_t ppe_show_throttle_end(struct sys_device *sysdev, char *buf)
+{
+       return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 32);
+}
+
+static ssize_t ppe_show_throttle_begin(struct sys_device *sysdev, char *buf)
+{
+       return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 40);
+}
+
+static ssize_t ppe_show_throttle_full_stop(struct sys_device *sysdev, char *buf)
+{
+       return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 48);
+}
+
+static ssize_t ppe_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size)
+{
+       return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 32);
+}
+
+static ssize_t ppe_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size)
+{
+       return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 40);
+}
+
+static ssize_t ppe_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size)
+{
+       return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 48);
+}
+
+
 static struct sysdev_attribute attr_spu_temperature = {
        .attr = {.name = "temperature", .mode = 0400 },
        .show = spu_show_temp,
 };
 
+static SYSDEV_PREFIX_ATTR(spu, throttle_end, 0600);
+static SYSDEV_PREFIX_ATTR(spu, throttle_begin, 0600);
+static SYSDEV_PREFIX_ATTR(spu, throttle_full_stop, 0600);
+
+
 static struct attribute *spu_attributes[] = {
        &attr_spu_temperature.attr,
+       &attr_spu_throttle_end.attr,
+       &attr_spu_throttle_begin.attr,
+       &attr_spu_throttle_full_stop.attr,
        NULL,
 };
 
@@ -133,9 +271,16 @@ static struct sysdev_attribute attr_ppe_temperature1 = {
        .show = ppe_show_temp1,
 };
 
+static SYSDEV_PREFIX_ATTR(ppe, throttle_end, 0600);
+static SYSDEV_PREFIX_ATTR(ppe, throttle_begin, 0600);
+static SYSDEV_PREFIX_ATTR(ppe, throttle_full_stop, 0600);
+
 static struct attribute *ppe_attributes[] = {
        &attr_ppe_temperature0.attr,
        &attr_ppe_temperature1.attr,
+       &attr_ppe_throttle_end.attr,
+       &attr_ppe_throttle_begin.attr,
+       &attr_ppe_throttle_full_stop.attr,
        NULL,
 };
 
index 6666d037eb443c763fc9413f460f2ef5a275c86d..4fc4e92775d0d1735ef1f0c38eec093b1a1e3a4d 100644 (file)
@@ -261,7 +261,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct,
                return -ENODEV;
        if (intsize != 1)
                return -ENODEV;
-       val = get_property(ct, "#interrupt-cells", NULL);
+       val = of_get_property(ct, "#interrupt-cells", NULL);
        if (val == NULL || *val != 1)
                return -ENODEV;
 
@@ -327,7 +327,7 @@ static int __init setup_iic(void)
                if (!device_is_compatible(dn,
                                     "IBM,CBEA-Internal-Interrupt-Controller"))
                        continue;
-               np = get_property(dn, "ibm,interrupt-server-ranges", NULL);
+               np = of_get_property(dn, "ibm,interrupt-server-ranges", NULL);
                if (np == NULL) {
                        printk(KERN_WARNING "IIC: CPU association not found\n");
                        of_node_put(dn);
index 7c73128305ec40754cb87febebec72bbde8a7279..d68d920eb2c4e6bbe8894c3c3dc99caefb8a8fe5 100644 (file)
@@ -318,7 +318,7 @@ static int __init spider_pci_workaround_init(void)
         */
        list_for_each_entry(phb, &hose_list, list_node) {
                struct device_node *np = phb->arch_data;
-               const char *model = get_property(np, "model", NULL);
+               const char *model = of_get_property(np, "model", NULL);
 
                /* If no model property or name isn't exactly "pci", skip */
                if (model == NULL || strcmp(np->name, "pci"))
index 67d617b60a2344ab00a78a9b32e7fb508f1b05fc..760caa76841a025e35969ef58b67002f228e91e7 100644 (file)
@@ -291,9 +291,9 @@ static int cell_iommu_find_ioc(int nid, unsigned long *base)
                const unsigned int *nidp;
                const unsigned long *tmp;
 
-               nidp = get_property(np, "node-id", NULL);
+               nidp = of_get_property(np, "node-id", NULL);
                if (nidp && *nidp == nid) {
-                       tmp = get_property(np, "ioc-translation", NULL);
+                       tmp = of_get_property(np, "ioc-translation", NULL);
                        if (tmp) {
                                *base = *tmp;
                                of_node_put(np);
@@ -430,7 +430,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
        struct iommu_window *window;
        const unsigned int *ioid;
 
-       ioid = get_property(np, "ioid", NULL);
+       ioid = of_get_property(np, "ioid", NULL);
        if (ioid == NULL)
                printk(KERN_WARNING "iommu: missing ioid for %s using 0\n",
                       np->full_name);
@@ -496,7 +496,7 @@ static void cell_dma_dev_setup(struct device *dev)
        struct dev_archdata *archdata = &dev->archdata;
 
        /* If we run without iommu, no need to do anything */
-       if (pci_dma_ops == &dma_direct_ops)
+       if (get_pci_dma_ops() == &dma_direct_ops)
                return;
 
        /* Current implementation uses the first window available in that
@@ -530,7 +530,7 @@ static int cell_of_bus_notify(struct notifier_block *nb, unsigned long action,
                return 0;
 
        /* We use the PCI DMA ops */
-       dev->archdata.dma_ops = pci_dma_ops;
+       dev->archdata.dma_ops = get_pci_dma_ops();
 
        cell_dma_dev_setup(dev);
 
@@ -549,7 +549,7 @@ static int __init cell_iommu_get_window(struct device_node *np,
        unsigned long index;
 
        /* Use ibm,dma-window if available, else, hard code ! */
-       dma_window = get_property(np, "ibm,dma-window", NULL);
+       dma_window = of_get_property(np, "ibm,dma-window", NULL);
        if (dma_window == NULL) {
                *base = 0;
                *size = 0x80000000u;
@@ -646,7 +646,7 @@ static int __init cell_iommu_init_disabled(void)
        unsigned long base = 0, size;
 
        /* When no iommu is present, we use direct DMA ops */
-       pci_dma_ops = &dma_direct_ops;
+       set_pci_dma_ops(&dma_direct_ops);
 
        /* First make sure all IOC translation is turned off */
        cell_disable_iommus();
@@ -734,7 +734,7 @@ static int __init cell_iommu_init(void)
        }
 
        /* Setup default PCI iommu ops */
-       pci_dma_ops = &dma_iommu_ops;
+       set_pci_dma_ops(&dma_iommu_ops);
 
  bail:
        /* Register callbacks on OF platform device addition/removal
index 0984c70716953fd8a5a577cbc3d63efcccb555f3..3961a085b432b4046bd2525c2e850c708da49ae4 100644 (file)
@@ -3,11 +3,13 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
+#include <linux/reboot.h>
 
 #include <asm/reg.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
+#include <asm/rtas.h>
 
 #include "ras.h"
 #include "cbe_regs.h"
@@ -82,6 +84,164 @@ static int cbe_machine_check_handler(struct pt_regs *regs)
        return 0;
 }
 
+struct ptcal_area {
+       struct list_head list;
+       int nid;
+       int order;
+       struct page *pages;
+};
+
+static LIST_HEAD(ptcal_list);
+
+static int ptcal_start_tok, ptcal_stop_tok;
+
+static int __init cbe_ptcal_enable_on_node(int nid, int order)
+{
+       struct ptcal_area *area;
+       int ret = -ENOMEM;
+       unsigned long addr;
+
+#ifdef CONFIG_CRASH_DUMP
+       rtas_call(ptcal_stop_tok, 1, 1, NULL, nid);
+#endif
+
+       area = kmalloc(sizeof(*area), GFP_KERNEL);
+       if (!area)
+               goto out_err;
+
+       area->nid = nid;
+       area->order = order;
+       area->pages = alloc_pages_node(area->nid, GFP_KERNEL, area->order);
+
+       if (!area->pages)
+               goto out_free_area;
+
+       addr = __pa(page_address(area->pages));
+
+       ret = -EIO;
+       if (rtas_call(ptcal_start_tok, 3, 1, NULL, area->nid,
+                               (unsigned int)(addr >> 32),
+                               (unsigned int)(addr & 0xffffffff))) {
+               printk(KERN_ERR "%s: error enabling PTCAL on node %d!\n",
+                               __FUNCTION__, nid);
+               goto out_free_pages;
+       }
+
+       list_add(&area->list, &ptcal_list);
+
+       return 0;
+
+out_free_pages:
+       __free_pages(area->pages, area->order);
+out_free_area:
+       kfree(area);
+out_err:
+       return ret;
+}
+
+static int __init cbe_ptcal_enable(void)
+{
+       const u32 *size;
+       struct device_node *np;
+       int order, found_mic = 0;
+
+       np = of_find_node_by_path("/rtas");
+       if (!np)
+               return -ENODEV;
+
+       size = of_get_property(np, "ibm,cbe-ptcal-size", NULL);
+       if (!size)
+               return -ENODEV;
+
+       pr_debug("%s: enabling PTCAL, size = 0x%x\n", __FUNCTION__, *size);
+       order = get_order(*size);
+       of_node_put(np);
+
+       /* support for malta device trees, with be@/mic@ nodes */
+       for_each_node_by_type(np, "mic-tm") {
+               cbe_ptcal_enable_on_node(of_node_to_nid(np), order);
+               found_mic = 1;
+       }
+
+       if (found_mic)
+               return 0;
+
+       /* support for older device tree - use cpu nodes */
+       for_each_node_by_type(np, "cpu") {
+               const u32 *nid = of_get_property(np, "node-id", NULL);
+               if (!nid) {
+                       printk(KERN_ERR "%s: node %s is missing node-id?\n",
+                                       __FUNCTION__, np->full_name);
+                       continue;
+               }
+               cbe_ptcal_enable_on_node(*nid, order);
+               found_mic = 1;
+       }
+
+       return found_mic ? 0 : -ENODEV;
+}
+
+static int cbe_ptcal_disable(void)
+{
+       struct ptcal_area *area, *tmp;
+       int ret = 0;
+
+       pr_debug("%s: disabling PTCAL\n", __FUNCTION__);
+
+       list_for_each_entry_safe(area, tmp, &ptcal_list, list) {
+               /* disable ptcal on this node */
+               if (rtas_call(ptcal_stop_tok, 1, 1, NULL, area->nid)) {
+                       printk(KERN_ERR "%s: error disabling PTCAL "
+                                       "on node %d!\n", __FUNCTION__,
+                                       area->nid);
+                       ret = -EIO;
+                       continue;
+               }
+
+               /* ensure we can access the PTCAL area */
+               memset(page_address(area->pages), 0,
+                               1 << (area->order + PAGE_SHIFT));
+
+               /* clean up */
+               list_del(&area->list);
+               __free_pages(area->pages, area->order);
+               kfree(area);
+       }
+
+       return ret;
+}
+
+static int cbe_ptcal_notify_reboot(struct notifier_block *nb,
+               unsigned long code, void *data)
+{
+       return cbe_ptcal_disable();
+}
+
+static struct notifier_block cbe_ptcal_reboot_notifier = {
+       .notifier_call = cbe_ptcal_notify_reboot
+};
+
+int __init cbe_ptcal_init(void)
+{
+       int ret;
+       ptcal_start_tok = rtas_token("ibm,cbe-start-ptcal");
+       ptcal_stop_tok = rtas_token("ibm,cbe-stop-ptcal");
+
+       if (ptcal_start_tok == RTAS_UNKNOWN_SERVICE
+                       || ptcal_stop_tok == RTAS_UNKNOWN_SERVICE)
+               return -ENODEV;
+
+       ret = register_reboot_notifier(&cbe_ptcal_reboot_notifier);
+       if (ret) {
+               printk(KERN_ERR "Can't disable PTCAL, so not enabling\n");
+               return ret;
+       }
+
+       return cbe_ptcal_enable();
+}
+
+arch_initcall(cbe_ptcal_init);
+
 void __init cbe_ras_init(void)
 {
        unsigned long hid0;
index 36989c2eee665546d9b0370ec03e7e8331b678d8..54b96183cb64466347cd6ca4a25090de56be6df1 100644 (file)
@@ -71,7 +71,7 @@ static void cell_show_cpuinfo(struct seq_file *m)
 
        root = of_find_node_by_path("/");
        if (root)
-               model = get_property(root, "model", NULL);
+               model = of_get_property(root, "model", NULL);
        seq_printf(m, "machine\t\t: CHRP %s\n", model);
        of_node_put(root);
 }
@@ -190,15 +190,6 @@ static int __init cell_probe(void)
        return 1;
 }
 
-/*
- * Cell has no legacy IO; anything calling this function has to
- * fail or bad things will happen
- */
-static int cell_check_legacy_ioport(unsigned int baseport)
-{
-       return -ENODEV;
-}
-
 define_machine(cell) {
        .name                   = "Cell",
        .probe                  = cell_probe,
@@ -211,7 +202,6 @@ define_machine(cell) {
        .get_rtc_time           = rtas_get_rtc_time,
        .set_rtc_time           = rtas_set_rtc_time,
        .calibrate_decr         = generic_calibrate_decr,
-       .check_legacy_ioport    = cell_check_legacy_ioport,
        .progress               = cell_progress,
        .init_IRQ               = cell_init_irq,
        .pci_setup_phb          = rtas_setup_phb,
index 21a9ebd4978e332cfc9218760877059eb6235766..fb1f15797bbbb837b29b337d90217c4339e7e38c 100644 (file)
@@ -254,25 +254,25 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
        }
 
        /* Now do the horrible hacks */
-       tmp = get_property(pic->of_node, "#interrupt-cells", NULL);
+       tmp = of_get_property(pic->of_node, "#interrupt-cells", NULL);
        if (tmp == NULL)
                return NO_IRQ;
        intsize = *tmp;
-       imap = get_property(pic->of_node, "interrupt-map", &imaplen);
+       imap = of_get_property(pic->of_node, "interrupt-map", &imaplen);
        if (imap == NULL || imaplen < (intsize + 1))
                return NO_IRQ;
        iic = of_find_node_by_phandle(imap[intsize]);
        if (iic == NULL)
                return NO_IRQ;
        imap += intsize + 1;
-       tmp = get_property(iic, "#interrupt-cells", NULL);
+       tmp = of_get_property(iic, "#interrupt-cells", NULL);
        if (tmp == NULL)
                return NO_IRQ;
        intsize = *tmp;
        /* Assume unit is last entry of interrupt specifier */
        unit = imap[intsize - 1];
        /* Ok, we have a unit, now let's try to get the node */
-       tmp = get_property(iic, "ibm,interrupt-server-ranges", NULL);
+       tmp = of_get_property(iic, "ibm,interrupt-server-ranges", NULL);
        if (tmp == NULL) {
                of_node_put(iic);
                return NO_IRQ;
index eba7a2641dcedf0c345e4c6dc7692f9c9deb48c9..fec51525252e2dfba33d8bb0c860bbbc0630d974 100644 (file)
 #include <asm/xmon.h>
 
 const struct spu_management_ops *spu_management_ops;
+EXPORT_SYMBOL_GPL(spu_management_ops);
+
 const struct spu_priv1_ops *spu_priv1_ops;
 
 static struct list_head spu_list[MAX_NUMNODES];
 static LIST_HEAD(spu_full_list);
 static DEFINE_MUTEX(spu_mutex);
-static spinlock_t spu_list_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(spu_list_lock);
 
 EXPORT_SYMBOL_GPL(spu_priv1_ops);
 
@@ -290,7 +292,6 @@ spu_irq_class_1(int irq, void *data)
 
        return stat ? IRQ_HANDLED : IRQ_NONE;
 }
-EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
 
 static irqreturn_t
 spu_irq_class_2(int irq, void *data)
@@ -431,10 +432,11 @@ struct spu *spu_alloc_node(int node)
                spu = list_entry(spu_list[node].next, struct spu, list);
                list_del_init(&spu->list);
                pr_debug("Got SPU %d %d\n", spu->number, spu->node);
-               spu_init_channels(spu);
        }
        mutex_unlock(&spu_mutex);
 
+       if (spu)
+               spu_init_channels(spu);
        return spu;
 }
 EXPORT_SYMBOL_GPL(spu_alloc_node);
@@ -461,108 +463,6 @@ void spu_free(struct spu *spu)
 }
 EXPORT_SYMBOL_GPL(spu_free);
 
-static int spu_handle_mm_fault(struct spu *spu)
-{
-       struct mm_struct *mm = spu->mm;
-       struct vm_area_struct *vma;
-       u64 ea, dsisr, is_write;
-       int ret;
-
-       ea = spu->dar;
-       dsisr = spu->dsisr;
-#if 0
-       if (!IS_VALID_EA(ea)) {
-               return -EFAULT;
-       }
-#endif /* XXX */
-       if (mm == NULL) {
-               return -EFAULT;
-       }
-       if (mm->pgd == NULL) {
-               return -EFAULT;
-       }
-
-       down_read(&mm->mmap_sem);
-       vma = find_vma(mm, ea);
-       if (!vma)
-               goto bad_area;
-       if (vma->vm_start <= ea)
-               goto good_area;
-       if (!(vma->vm_flags & VM_GROWSDOWN))
-               goto bad_area;
-#if 0
-       if (expand_stack(vma, ea))
-               goto bad_area;
-#endif /* XXX */
-good_area:
-       is_write = dsisr & MFC_DSISR_ACCESS_PUT;
-       if (is_write) {
-               if (!(vma->vm_flags & VM_WRITE))
-                       goto bad_area;
-       } else {
-               if (dsisr & MFC_DSISR_ACCESS_DENIED)
-                       goto bad_area;
-               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
-                       goto bad_area;
-       }
-       ret = 0;
-       switch (handle_mm_fault(mm, vma, ea, is_write)) {
-       case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               ret = -EFAULT;
-               goto bad_area;
-       case VM_FAULT_OOM:
-               ret = -ENOMEM;
-               goto bad_area;
-       default:
-               BUG();
-       }
-       up_read(&mm->mmap_sem);
-       return ret;
-
-bad_area:
-       up_read(&mm->mmap_sem);
-       return -EFAULT;
-}
-
-int spu_irq_class_1_bottom(struct spu *spu)
-{
-       u64 ea, dsisr, access, error = 0UL;
-       int ret = 0;
-
-       ea = spu->dar;
-       dsisr = spu->dsisr;
-       if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) {
-               u64 flags;
-
-               access = (_PAGE_PRESENT | _PAGE_USER);
-               access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
-               local_irq_save(flags);
-               if (hash_page(ea, access, 0x300) != 0)
-                       error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
-               local_irq_restore(flags);
-       }
-       if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) {
-               if ((ret = spu_handle_mm_fault(spu)) != 0)
-                       error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
-               else
-                       error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR;
-       }
-       spu->dar = 0UL;
-       spu->dsisr = 0UL;
-       if (!error) {
-               spu_restart_dma(spu);
-       } else {
-               spu->dma_callback(spu, SPE_EVENT_SPE_DATA_STORAGE);
-       }
-       return ret;
-}
-
 struct sysdev_class spu_sysdev_class = {
        set_kset_name("spu")
 };
@@ -636,12 +536,6 @@ static int spu_create_sysdev(struct spu *spu)
        return 0;
 }
 
-static void spu_destroy_sysdev(struct spu *spu)
-{
-       sysfs_remove_device_from_node(&spu->sysdev, spu->node);
-       sysdev_unregister(&spu->sysdev);
-}
-
 static int __init create_spu(void *data)
 {
        struct spu *spu;
@@ -693,58 +587,37 @@ out:
        return ret;
 }
 
-static void destroy_spu(struct spu *spu)
-{
-       list_del_init(&spu->list);
-       list_del_init(&spu->full_list);
-
-       spu_destroy_sysdev(spu);
-       spu_free_irqs(spu);
-       spu_destroy_spu(spu);
-       kfree(spu);
-}
-
-static void cleanup_spu_base(void)
-{
-       struct spu *spu, *tmp;
-       int node;
-
-       mutex_lock(&spu_mutex);
-       for (node = 0; node < MAX_NUMNODES; node++) {
-               list_for_each_entry_safe(spu, tmp, &spu_list[node], list)
-                       destroy_spu(spu);
-       }
-       mutex_unlock(&spu_mutex);
-       sysdev_class_unregister(&spu_sysdev_class);
-}
-module_exit(cleanup_spu_base);
-
 static int __init init_spu_base(void)
 {
-       int i, ret;
+       int i, ret = 0;
+
+       for (i = 0; i < MAX_NUMNODES; i++)
+               INIT_LIST_HEAD(&spu_list[i]);
 
        if (!spu_management_ops)
-               return 0;
+               goto out;
 
        /* create sysdev class for spus */
        ret = sysdev_class_register(&spu_sysdev_class);
        if (ret)
-               return ret;
-
-       for (i = 0; i < MAX_NUMNODES; i++)
-               INIT_LIST_HEAD(&spu_list[i]);
+               goto out;
 
        ret = spu_enumerate_spus(create_spu);
 
        if (ret) {
                printk(KERN_WARNING "%s: Error initializing spus\n",
                        __FUNCTION__);
-               cleanup_spu_base();
-               return ret;
+               goto out_unregister_sysdev_class;
        }
 
        xmon_register_spus(&spu_full_list);
 
+       return 0;
+
+ out_unregister_sysdev_class:
+       sysdev_class_unregister(&spu_sysdev_class);
+ out:
+
        return ret;
 }
 module_init(init_spu_base);
index 6915b418ee73aa00df1c90248529f938529117f7..4fd37ff1e210c29c17eff7c22966d7b05052ac0b 100644 (file)
 
 #include <asm/spu.h>
 
-static struct spu_coredump_calls spu_coredump_calls;
+static struct spu_coredump_calls *spu_coredump_calls;
 static DEFINE_MUTEX(spu_coredump_mutex);
 
 int arch_notes_size(void)
 {
        long ret;
-       struct module *owner = spu_coredump_calls.owner;
 
        ret = -ENOSYS;
        mutex_lock(&spu_coredump_mutex);
-       if (owner && try_module_get(owner)) {
-               ret = spu_coredump_calls.arch_notes_size();
-               module_put(owner);
+       if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) {
+               ret = spu_coredump_calls->arch_notes_size();
+               module_put(spu_coredump_calls->owner);
        }
        mutex_unlock(&spu_coredump_mutex);
        return ret;
@@ -46,36 +45,35 @@ int arch_notes_size(void)
 
 void arch_write_notes(struct file *file)
 {
-       struct module *owner = spu_coredump_calls.owner;
-
        mutex_lock(&spu_coredump_mutex);
-       if (owner && try_module_get(owner)) {
-               spu_coredump_calls.arch_write_notes(file);
-               module_put(owner);
+       if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) {
+               spu_coredump_calls->arch_write_notes(file);
+               module_put(spu_coredump_calls->owner);
        }
        mutex_unlock(&spu_coredump_mutex);
 }
 
 int register_arch_coredump_calls(struct spu_coredump_calls *calls)
 {
-       if (spu_coredump_calls.owner)
-               return -EBUSY;
+       int ret = 0;
+
 
        mutex_lock(&spu_coredump_mutex);
-       spu_coredump_calls.arch_notes_size = calls->arch_notes_size;
-       spu_coredump_calls.arch_write_notes = calls->arch_write_notes;
-       spu_coredump_calls.owner = calls->owner;
+       if (spu_coredump_calls)
+               ret = -EBUSY;
+       else
+               spu_coredump_calls = calls;
        mutex_unlock(&spu_coredump_mutex);
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(register_arch_coredump_calls);
 
 void unregister_arch_coredump_calls(struct spu_coredump_calls *calls)
 {
-       BUG_ON(spu_coredump_calls.owner != calls->owner);
+       BUG_ON(spu_coredump_calls != calls);
 
        mutex_lock(&spu_coredump_mutex);
-       spu_coredump_calls.owner = NULL;
+       spu_coredump_calls = NULL;
        mutex_unlock(&spu_coredump_mutex);
 }
 EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls);
index e34599f53d284250b4174b90f6bbaaa9daab99ba..1d4562ae463dd90ff4e1459cf8514c6fa044008f 100644 (file)
@@ -48,11 +48,11 @@ static u64 __init find_spu_unit_number(struct device_node *spe)
 {
        const unsigned int *prop;
        int proplen;
-       prop = get_property(spe, "unit-id", &proplen);
+       prop = of_get_property(spe, "unit-id", &proplen);
        if (proplen == 4)
                return (u64)*prop;
 
-       prop = get_property(spe, "reg", &proplen);
+       prop = of_get_property(spe, "reg", &proplen);
        if (proplen == 4)
                return (u64)*prop;
 
@@ -76,12 +76,12 @@ static int __init spu_map_interrupts_old(struct spu *spu,
        int nid;
 
        /* Get the interrupt source unit from the device-tree */
-       tmp = get_property(np, "isrc", NULL);
+       tmp = of_get_property(np, "isrc", NULL);
        if (!tmp)
                return -ENODEV;
        isrc = tmp[0];
 
-       tmp = get_property(np->parent->parent, "node-id", NULL);
+       tmp = of_get_property(np->parent->parent, "node-id", NULL);
        if (!tmp) {
                printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__);
                nid = spu->node;
@@ -110,7 +110,7 @@ static void __iomem * __init spu_map_prop_old(struct spu *spu,
        } __attribute__((packed)) *prop;
        int proplen;
 
-       prop = get_property(n, name, &proplen);
+       prop = of_get_property(n, name, &proplen);
        if (prop == NULL || proplen != sizeof (struct address_prop))
                return NULL;
 
@@ -124,11 +124,11 @@ static int __init spu_map_device_old(struct spu *spu)
        int ret;
 
        ret = -ENODEV;
-       spu->name = get_property(node, "name", NULL);
+       spu->name = of_get_property(node, "name", NULL);
        if (!spu->name)
                goto out;
 
-       prop = get_property(node, "local-store", NULL);
+       prop = of_get_property(node, "local-store", NULL);
        if (!prop)
                goto out;
        spu->local_store_phys = *(unsigned long *)prop;
@@ -139,7 +139,7 @@ static int __init spu_map_device_old(struct spu *spu)
        if (!spu->local_store)
                goto out;
 
-       prop = get_property(node, "problem", NULL);
+       prop = of_get_property(node, "problem", NULL);
        if (!prop)
                goto out_unmap;
        spu->problem_phys = *(unsigned long *)prop;
@@ -226,7 +226,7 @@ static int __init spu_map_device(struct spu *spu)
        struct device_node *np = spu->devnode;
        int ret = -ENODEV;
 
-       spu->name = get_property(np, "name", NULL);
+       spu->name = of_get_property(np, "name", NULL);
        if (!spu->name)
                goto out;
 
index 472217d19faf5b7ac0dd7d352cbeb77510d57513..2cd89c11af5ac328209cdbcf7a0b76dcdd7c196c 100644 (file)
@@ -1,4 +1,4 @@
-obj-y += switch.o
+obj-y += switch.o fault.o
 
 obj-$(CONFIG_SPU_FS) += spufs.o
 spufs-y += inode.o file.o context.o syscalls.o coredump.o
index 1898f0d3a8b876aaafe246c845b82189c298986c..3322528fa6eb687c4f25965e9966cb6f7b364a49 100644 (file)
@@ -350,6 +350,11 @@ static int spu_backing_send_mfc_command(struct spu_context *ctx,
        return ret;
 }
 
+static void spu_backing_restart_dma(struct spu_context *ctx)
+{
+       /* nothing to do here */
+}
+
 struct spu_context_ops spu_backing_ops = {
        .mbox_read = spu_backing_mbox_read,
        .mbox_stat_read = spu_backing_mbox_stat_read,
@@ -376,4 +381,5 @@ struct spu_context_ops spu_backing_ops = {
        .read_mfc_tagstatus = spu_backing_read_mfc_tagstatus,
        .get_mfc_free_elements = spu_backing_get_mfc_free_elements,
        .send_mfc_command = spu_backing_send_mfc_command,
+       .restart_dma = spu_backing_restart_dma,
 };
index 04ad2e364e977350643d89087b06e2c5c8163478..a87d9ca3dba26c926822f068e7e8ea0055cb60ba 100644 (file)
@@ -41,9 +41,10 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
                goto out_free;
        }
        spin_lock_init(&ctx->mmio_lock);
+       spin_lock_init(&ctx->mapping_lock);
        kref_init(&ctx->kref);
        mutex_init(&ctx->state_mutex);
-       init_MUTEX(&ctx->run_sema);
+       mutex_init(&ctx->run_mutex);
        init_waitqueue_head(&ctx->ibox_wq);
        init_waitqueue_head(&ctx->wbox_wq);
        init_waitqueue_head(&ctx->stop_wq);
@@ -51,6 +52,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
        ctx->state = SPU_STATE_SAVED;
        ctx->ops = &spu_backing_ops;
        ctx->owner = get_task_mm(current);
+       INIT_LIST_HEAD(&ctx->rq);
        if (gang)
                spu_gang_add_ctx(gang, ctx);
        ctx->rt_priority = current->rt_priority;
@@ -75,6 +77,7 @@ void destroy_spu_context(struct kref *kref)
        spu_fini_csa(&ctx->csa);
        if (ctx->gang)
                spu_gang_remove_ctx(ctx->gang, ctx);
+       BUG_ON(!list_empty(&ctx->rq));
        kfree(ctx);
 }
 
@@ -118,46 +121,6 @@ void spu_unmap_mappings(struct spu_context *ctx)
                unmap_mapping_range(ctx->psmap, 0, 0x20000, 1);
 }
 
-/**
- * spu_acquire_exclusive - lock spu contex and protect against userspace access
- * @ctx:       spu contex to lock
- *
- * Note:
- *     Returns 0 and with the context locked on success
- *     Returns negative error and with the context _unlocked_ on failure.
- */
-int spu_acquire_exclusive(struct spu_context *ctx)
-{
-       int ret = -EINVAL;
-
-       spu_acquire(ctx);
-       /*
-        * Context is about to be freed, so we can't acquire it anymore.
-        */
-       if (!ctx->owner)
-               goto out_unlock;
-
-       if (ctx->state == SPU_STATE_SAVED) {
-               ret = spu_activate(ctx, 0);
-               if (ret)
-                       goto out_unlock;
-       } else {
-               /*
-                * We need to exclude userspace access to the context.
-                *
-                * To protect against memory access we invalidate all ptes
-                * and make sure the pagefault handlers block on the mutex.
-                */
-               spu_unmap_mappings(ctx);
-       }
-
-       return 0;
-
- out_unlock:
-       spu_release(ctx);
-       return ret;
-}
-
 /**
  * spu_acquire_runnable - lock spu contex and make sure it is in runnable state
  * @ctx:       spu contex to lock
index 725e19561159dd60bf492d0d87816f3f76767e51..5d9ad5a0307ba43b6ee47cde43cc25ebcfce907b 100644 (file)
@@ -169,12 +169,12 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
        struct spu_context *ctx;
        loff_t pos = 0;
        int sz, dfd, rc, total = 0;
-       const int bufsz = 4096;
+       const int bufsz = PAGE_SIZE;
        char *name;
        char fullname[80], *buf;
        struct elf_note en;
 
-       buf = kmalloc(bufsz, GFP_KERNEL);
+       buf = (void *)get_zeroed_page(GFP_KERNEL);
        if (!buf)
                return;
 
@@ -187,9 +187,8 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
                sz = spufs_coredump_read[i].size;
 
        ctx = ctx_info->ctx;
-       if (!ctx) {
-               return;
-       }
+       if (!ctx)
+               goto out;
 
        sprintf(fullname, "SPU/%d/%s", dfd, name);
        en.n_namesz = strlen(fullname) + 1;
@@ -197,23 +196,25 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
        en.n_type = NT_SPU;
 
        if (!spufs_dump_write(file, &en, sizeof(en)))
-               return;
+               goto out;
        if (!spufs_dump_write(file, fullname, en.n_namesz))
-               return;
+               goto out;
        if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4)))
-               return;
+               goto out;
 
        do {
                rc = do_coredump_read(i, ctx, buf, bufsz, &pos);
                if (rc > 0) {
                        if (!spufs_dump_write(file, buf, rc))
-                               return;
+                               goto out;
                        total += rc;
                }
        } while (rc == bufsz && total < sz);
 
        spufs_dump_seek(file, roundup((unsigned long)file->f_pos
                                                - total + sz, 4));
+out:
+       free_page((unsigned long)buf);
 }
 
 static void spufs_arch_write_notes(struct file *file)
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
new file mode 100644 (file)
index 0000000..0f75c07
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Low-level SPU handling
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+
+#include "spufs.h"
+
+/*
+ * This ought to be kept in sync with the powerpc specific do_page_fault
+ * function. Currently, there are a few corner cases that we haven't had
+ * to handle fortunately.
+ */
+static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr)
+{
+       struct vm_area_struct *vma;
+       unsigned long is_write;
+       int ret;
+
+#if 0
+       if (!IS_VALID_EA(ea)) {
+               return -EFAULT;
+       }
+#endif /* XXX */
+       if (mm == NULL) {
+               return -EFAULT;
+       }
+       if (mm->pgd == NULL) {
+               return -EFAULT;
+       }
+
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, ea);
+       if (!vma)
+               goto bad_area;
+       if (vma->vm_start <= ea)
+               goto good_area;
+       if (!(vma->vm_flags & VM_GROWSDOWN))
+               goto bad_area;
+       if (expand_stack(vma, ea))
+               goto bad_area;
+good_area:
+       is_write = dsisr & MFC_DSISR_ACCESS_PUT;
+       if (is_write) {
+               if (!(vma->vm_flags & VM_WRITE))
+                       goto bad_area;
+       } else {
+               if (dsisr & MFC_DSISR_ACCESS_DENIED)
+                       goto bad_area;
+               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                       goto bad_area;
+       }
+       ret = 0;
+       switch (handle_mm_fault(mm, vma, ea, is_write)) {
+       case VM_FAULT_MINOR:
+               current->min_flt++;
+               break;
+       case VM_FAULT_MAJOR:
+               current->maj_flt++;
+               break;
+       case VM_FAULT_SIGBUS:
+               ret = -EFAULT;
+               goto bad_area;
+       case VM_FAULT_OOM:
+               ret = -ENOMEM;
+               goto bad_area;
+       default:
+               BUG();
+       }
+       up_read(&mm->mmap_sem);
+       return ret;
+
+bad_area:
+       up_read(&mm->mmap_sem);
+       return -EFAULT;
+}
+
+static void spufs_handle_dma_error(struct spu_context *ctx,
+                               unsigned long ea, int type)
+{
+       if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
+               ctx->event_return |= type;
+               wake_up_all(&ctx->stop_wq);
+       } else {
+               siginfo_t info;
+               memset(&info, 0, sizeof(info));
+
+               switch (type) {
+               case SPE_EVENT_INVALID_DMA:
+                       info.si_signo = SIGBUS;
+                       info.si_code = BUS_OBJERR;
+                       break;
+               case SPE_EVENT_SPE_DATA_STORAGE:
+                       info.si_signo = SIGBUS;
+                       info.si_addr = (void __user *)ea;
+                       info.si_code = BUS_ADRERR;
+                       break;
+               case SPE_EVENT_DMA_ALIGNMENT:
+                       info.si_signo = SIGBUS;
+                       /* DAR isn't set for an alignment fault :( */
+                       info.si_code = BUS_ADRALN;
+                       break;
+               case SPE_EVENT_SPE_ERROR:
+                       info.si_signo = SIGILL;
+                       info.si_addr = (void __user *)(unsigned long)
+                               ctx->ops->npc_read(ctx) - 4;
+                       info.si_code = ILL_ILLOPC;
+                       break;
+               }
+               if (info.si_signo)
+                       force_sig_info(info.si_signo, &info, current);
+       }
+}
+
+void spufs_dma_callback(struct spu *spu, int type)
+{
+       spufs_handle_dma_error(spu->ctx, spu->dar, type);
+}
+EXPORT_SYMBOL_GPL(spufs_dma_callback);
+
+/*
+ * bottom half handler for page faults, we can't do this from
+ * interrupt context, since we might need to sleep.
+ * we also need to give up the mutex so we can get scheduled
+ * out while waiting for the backing store.
+ *
+ * TODO: try calling hash_page from the interrupt handler first
+ *       in order to speed up the easy case.
+ */
+int spufs_handle_class1(struct spu_context *ctx)
+{
+       u64 ea, dsisr, access;
+       unsigned long flags;
+       int ret;
+
+       /*
+        * dar and dsisr get passed from the registers
+        * to the spu_context, to this function, but not
+        * back to the spu if it gets scheduled again.
+        *
+        * if we don't handle the fault for a saved context
+        * in time, we can still expect to get the same fault
+        * the immediately after the context restore.
+        */
+       if (ctx->state == SPU_STATE_RUNNABLE) {
+               ea = ctx->spu->dar;
+               dsisr = ctx->spu->dsisr;
+               ctx->spu->dar= ctx->spu->dsisr = 0;
+       } else {
+               ea = ctx->csa.priv1.mfc_dar_RW;
+               dsisr = ctx->csa.priv1.mfc_dsisr_RW;
+               ctx->csa.priv1.mfc_dar_RW = 0;
+               ctx->csa.priv1.mfc_dsisr_RW = 0;
+       }
+
+       if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
+               return 0;
+
+       pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea,
+               dsisr, ctx->state);
+
+       /* we must not hold the lock when entering spu_handle_mm_fault */
+       spu_release(ctx);
+
+       access = (_PAGE_PRESENT | _PAGE_USER);
+       access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
+       local_irq_save(flags);
+       ret = hash_page(ea, access, 0x300);
+       local_irq_restore(flags);
+
+       /* hashing failed, so try the actual fault handler */
+       if (ret)
+               ret = spu_handle_mm_fault(current->mm, ea, dsisr);
+
+       spu_acquire(ctx);
+       /*
+        * If we handled the fault successfully and are in runnable
+        * state, restart the DMA.
+        * In case of unhandled error report the problem to user space.
+        */
+       if (!ret) {
+               if (ctx->spu)
+                       ctx->ops->restart_dma(ctx);
+       } else
+               spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(spufs_handle_class1);
index 505266a568d4221d9305c9e4ef1b0e99cc3ffc88..d010b2464a98cf3df710a4e5a9dc150c827506e8 100644 (file)
@@ -44,9 +44,25 @@ spufs_mem_open(struct inode *inode, struct file *file)
 {
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
        file->private_data = ctx;
-       ctx->local_store = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->local_store = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
+static int
+spufs_mem_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->local_store = NULL;
+       spin_unlock(&ctx->mapping_lock);
        return 0;
 }
 
@@ -149,6 +165,7 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
 
 static const struct file_operations spufs_mem_fops = {
        .open    = spufs_mem_open,
+       .release = spufs_mem_release,
        .read    = spufs_mem_read,
        .write   = spufs_mem_write,
        .llseek  = generic_file_llseek,
@@ -238,16 +255,33 @@ static int spufs_cntl_open(struct inode *inode, struct file *file)
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
 
+       spin_lock(&ctx->mapping_lock);
        file->private_data = ctx;
-       ctx->cntl = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->cntl = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return simple_attr_open(inode, file, spufs_cntl_get,
                                        spufs_cntl_set, "0x%08lx");
 }
 
+static int
+spufs_cntl_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       simple_attr_close(inode, file);
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->cntl = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 static const struct file_operations spufs_cntl_fops = {
        .open = spufs_cntl_open,
-       .release = simple_attr_close,
+       .release = spufs_cntl_release,
        .read = simple_attr_read,
        .write = simple_attr_write,
        .mmap = spufs_cntl_mmap,
@@ -723,12 +757,28 @@ static int spufs_signal1_open(struct inode *inode, struct file *file)
 {
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
        file->private_data = ctx;
-       ctx->signal1 = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->signal1 = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return nonseekable_open(inode, file);
 }
 
+static int
+spufs_signal1_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->signal1 = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
                        size_t len, loff_t *pos)
 {
@@ -821,6 +871,7 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
 
 static const struct file_operations spufs_signal1_fops = {
        .open = spufs_signal1_open,
+       .release = spufs_signal1_release,
        .read = spufs_signal1_read,
        .write = spufs_signal1_write,
        .mmap = spufs_signal1_mmap,
@@ -830,12 +881,28 @@ static int spufs_signal2_open(struct inode *inode, struct file *file)
 {
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
        file->private_data = ctx;
-       ctx->signal2 = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->signal2 = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return nonseekable_open(inode, file);
 }
 
+static int
+spufs_signal2_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->signal2 = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
                        size_t len, loff_t *pos)
 {
@@ -932,6 +999,7 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
 
 static const struct file_operations spufs_signal2_fops = {
        .open = spufs_signal2_open,
+       .release = spufs_signal2_release,
        .read = spufs_signal2_read,
        .write = spufs_signal2_write,
        .mmap = spufs_signal2_mmap,
@@ -1031,13 +1099,30 @@ static int spufs_mss_open(struct inode *inode, struct file *file)
        struct spu_context *ctx = i->i_ctx;
 
        file->private_data = i->i_ctx;
-       ctx->mss = inode->i_mapping;
-       smp_wmb();
+
+       spin_lock(&ctx->mapping_lock);
+       if (!i->i_openers++)
+               ctx->mss = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return nonseekable_open(inode, file);
 }
 
+static int
+spufs_mss_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->mss = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 static const struct file_operations spufs_mss_fops = {
        .open    = spufs_mss_open,
+       .release = spufs_mss_release,
        .mmap    = spufs_mss_mmap,
 };
 
@@ -1072,14 +1157,30 @@ static int spufs_psmap_open(struct inode *inode, struct file *file)
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
 
+       spin_lock(&ctx->mapping_lock);
        file->private_data = i->i_ctx;
-       ctx->psmap = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->psmap = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return nonseekable_open(inode, file);
 }
 
+static int
+spufs_psmap_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->psmap = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 static const struct file_operations spufs_psmap_fops = {
        .open    = spufs_psmap_open,
+       .release = spufs_psmap_release,
        .mmap    = spufs_psmap_mmap,
 };
 
@@ -1126,12 +1227,27 @@ static int spufs_mfc_open(struct inode *inode, struct file *file)
        if (atomic_read(&inode->i_count) != 1)
                return -EBUSY;
 
+       spin_lock(&ctx->mapping_lock);
        file->private_data = ctx;
-       ctx->mfc = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->mfc = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return nonseekable_open(inode, file);
 }
 
+static int
+spufs_mfc_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->mfc = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 /* interrupt-level mfc callback function. */
 void spufs_mfc_callback(struct spu *spu)
 {
@@ -1313,7 +1429,10 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
        if (ret)
                goto out;
 
-       spu_acquire_runnable(ctx, 0);
+       ret = spu_acquire_runnable(ctx, 0);
+       if (ret)
+               goto out;
+
        if (file->f_flags & O_NONBLOCK) {
                ret = ctx->ops->send_mfc_command(ctx, &cmd);
        } else {
@@ -1399,6 +1518,7 @@ static int spufs_mfc_fasync(int fd, struct file *file, int on)
 
 static const struct file_operations spufs_mfc_fops = {
        .open    = spufs_mfc_open,
+       .release = spufs_mfc_release,
        .read    = spufs_mfc_read,
        .write   = spufs_mfc_write,
        .poll    = spufs_mfc_poll,
index ae42e03b8c8687f1b7ff183bc371f33164280e09..428875c5e4ecec35559316967d37c18cdf01a9d9 100644 (file)
@@ -296,6 +296,14 @@ static int spu_hw_send_mfc_command(struct spu_context *ctx,
        }
 }
 
+static void spu_hw_restart_dma(struct spu_context *ctx)
+{
+       struct spu_priv2 __iomem *priv2 = ctx->spu->priv2;
+
+       if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &ctx->spu->flags))
+               out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
+}
+
 struct spu_context_ops spu_hw_ops = {
        .mbox_read = spu_hw_mbox_read,
        .mbox_stat_read = spu_hw_mbox_stat_read,
@@ -320,4 +328,5 @@ struct spu_context_ops spu_hw_ops = {
        .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
        .get_mfc_free_elements = spu_hw_get_mfc_free_elements,
        .send_mfc_command = spu_hw_send_mfc_command,
+       .restart_dma = spu_hw_restart_dma,
 };
index 8079983ef94fa5486c264cdf85123acbbbcbb161..13e4f70ec8c09d3c98de6204b4494ef0ed18fe4f 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/prom.h>
 #include <asm/semaphore.h>
 #include <asm/spu.h>
+#include <asm/spu_priv1.h>
 #include <asm/uaccess.h>
 
 #include "spufs.h"
@@ -54,6 +55,7 @@ spufs_alloc_inode(struct super_block *sb)
 
        ei->i_gang = NULL;
        ei->i_ctx = NULL;
+       ei->i_openers = 0;
 
        return &ei->vfs_inode;
 }
@@ -520,13 +522,14 @@ out:
 
 /* File system initialization */
 enum {
-       Opt_uid, Opt_gid, Opt_err,
+       Opt_uid, Opt_gid, Opt_mode, Opt_err,
 };
 
 static match_table_t spufs_tokens = {
-       { Opt_uid, "uid=%d" },
-       { Opt_gid, "gid=%d" },
-       { Opt_err, NULL  },
+       { Opt_uid,  "uid=%d" },
+       { Opt_gid,  "gid=%d" },
+       { Opt_mode, "mode=%o" },
+       { Opt_err,   NULL  },
 };
 
 static int
@@ -553,6 +556,11 @@ spufs_parse_options(char *options, struct inode *root)
                                return 0;
                        root->i_gid = option;
                        break;
+               case Opt_mode:
+                       if (match_octal(&args[0], &option))
+                               return 0;
+                       root->i_mode = option | S_IFDIR;
+                       break;
                default:
                        return 0;
                }
@@ -560,6 +568,11 @@ spufs_parse_options(char *options, struct inode *root)
        return 1;
 }
 
+static void spufs_exit_isolated_loader(void)
+{
+       kfree(isolated_loader);
+}
+
 static void
 spufs_init_isolated_loader(void)
 {
@@ -571,7 +584,7 @@ spufs_init_isolated_loader(void)
        if (!dn)
                return;
 
-       loader = get_property(dn, "loader", &size);
+       loader = of_get_property(dn, "loader", &size);
        if (!loader)
                return;
 
@@ -653,6 +666,10 @@ static int __init spufs_init(void)
 {
        int ret;
 
+       ret = -ENODEV;
+       if (!spu_management_ops)
+               goto out;
+
        ret = -ENOMEM;
        spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
                        sizeof(struct spufs_inode_info), 0,
@@ -660,25 +677,29 @@ static int __init spufs_init(void)
 
        if (!spufs_inode_cache)
                goto out;
-       if (spu_sched_init() != 0) {
-               kmem_cache_destroy(spufs_inode_cache);
-               goto out;
-       }
-       ret = register_filesystem(&spufs_type);
+       ret = spu_sched_init();
        if (ret)
                goto out_cache;
+       ret = register_filesystem(&spufs_type);
+       if (ret)
+               goto out_sched;
        ret = register_spu_syscalls(&spufs_calls);
        if (ret)
                goto out_fs;
        ret = register_arch_coredump_calls(&spufs_coredump_calls);
        if (ret)
-               goto out_fs;
+               goto out_syscalls;
 
        spufs_init_isolated_loader();
 
        return 0;
+
+out_syscalls:
+       unregister_spu_syscalls(&spufs_calls);
 out_fs:
        unregister_filesystem(&spufs_type);
+out_sched:
+       spu_sched_exit();
 out_cache:
        kmem_cache_destroy(spufs_inode_cache);
 out:
@@ -689,6 +710,7 @@ module_init(spufs_init);
 static void __exit spufs_exit(void)
 {
        spu_sched_exit();
+       spufs_exit_isolated_loader();
        unregister_arch_coredump_calls(&spufs_coredump_calls);
        unregister_spu_syscalls(&spufs_calls);
        unregister_filesystem(&spufs_type);
index f95a611ca36281fce6c8997f1486209898f8d162..57626600b1a4b5c7cb3d46d17ef214e5b5807d1d 100644 (file)
@@ -18,27 +18,6 @@ void spufs_stop_callback(struct spu *spu)
        wake_up_all(&ctx->stop_wq);
 }
 
-void spufs_dma_callback(struct spu *spu, int type)
-{
-       struct spu_context *ctx = spu->ctx;
-
-       if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
-               ctx->event_return |= type;
-               wake_up_all(&ctx->stop_wq);
-       } else {
-               switch (type) {
-               case SPE_EVENT_DMA_ALIGNMENT:
-               case SPE_EVENT_SPE_DATA_STORAGE:
-               case SPE_EVENT_INVALID_DMA:
-                       force_sig(SIGBUS, /* info, */ current);
-                       break;
-               case SPE_EVENT_SPE_ERROR:
-                       force_sig(SIGILL, /* info */ current);
-                       break;
-               }
-       }
-}
-
 static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
 {
        struct spu *spu;
@@ -63,13 +42,18 @@ static int spu_setup_isolated(struct spu_context *ctx)
        const u32 status_loading = SPU_STATUS_RUNNING
                | SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS;
 
+       ret = -ENODEV;
        if (!isolated_loader)
-               return -ENODEV;
-
-       ret = spu_acquire_exclusive(ctx);
-       if (ret)
                goto out;
 
+       /*
+        * We need to exclude userspace access to the context.
+        *
+        * To protect against memory access we invalidate all ptes
+        * and make sure the pagefault handlers block on the mutex.
+        */
+       spu_unmap_mappings(ctx);
+
        mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
 
        /* purge the MFC DMA queue to ensure no spurious accesses before we
@@ -82,7 +66,7 @@ static int spu_setup_isolated(struct spu_context *ctx)
                        printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n",
                                        __FUNCTION__);
                        ret = -EIO;
-                       goto out_unlock;
+                       goto out;
                }
                cond_resched();
        }
@@ -119,12 +103,15 @@ static int spu_setup_isolated(struct spu_context *ctx)
                pr_debug("%s: isolated LOAD failed\n", __FUNCTION__);
                ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
                ret = -EACCES;
+               goto out_drop_priv;
+       }
 
-       } else if (!(status & SPU_STATUS_ISOLATED_STATE)) {
+       if (!(status & SPU_STATUS_ISOLATED_STATE)) {
                /* This isn't allowed by the CBEA, but check anyway */
                pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__);
                ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP);
                ret = -EINVAL;
+               goto out_drop_priv;
        }
 
 out_drop_priv:
@@ -132,30 +119,19 @@ out_drop_priv:
        sr1 |= MFC_STATE1_PROBLEM_STATE_MASK;
        spu_mfc_sr1_set(ctx->spu, sr1);
 
-out_unlock:
-       spu_release(ctx);
 out:
        return ret;
 }
 
-static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
+static int spu_run_init(struct spu_context *ctx, u32 * npc)
 {
-       int ret;
-       unsigned long runcntl = SPU_RUNCNTL_RUNNABLE;
-
-       ret = spu_acquire_runnable(ctx, 0);
-       if (ret)
-               return ret;
-
        if (ctx->flags & SPU_CREATE_ISOLATE) {
+               unsigned long runcntl;
+
                if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) {
-                       /* Need to release ctx, because spu_setup_isolated will
-                        * acquire it exclusively.
-                        */
-                       spu_release(ctx);
-                       ret = spu_setup_isolated(ctx);
-                       if (!ret)
-                               ret = spu_acquire_runnable(ctx, 0);
+                       int ret = spu_setup_isolated(ctx);
+                       if (ret)
+                               return ret;
                }
 
                /* if userspace has set the runcntrl register (eg, to issue an
@@ -164,16 +140,17 @@ static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
                        (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
                if (runcntl == 0)
                        runcntl = SPU_RUNCNTL_RUNNABLE;
+               ctx->ops->runcntl_write(ctx, runcntl);
        } else {
                spu_start_tick(ctx);
                ctx->ops->npc_write(ctx, *npc);
+               ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
        }
 
-       ctx->ops->runcntl_write(ctx, runcntl);
-       return ret;
+       return 0;
 }
 
-static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
+static int spu_run_fini(struct spu_context *ctx, u32 * npc,
                               u32 * status)
 {
        int ret = 0;
@@ -189,19 +166,27 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
        return ret;
 }
 
-static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
+static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
                                         u32 *status)
 {
        int ret;
 
-       if ((ret = spu_run_fini(ctx, npc, status)) != 0)
+       ret = spu_run_fini(ctx, npc, status);
+       if (ret)
                return ret;
-       if (*status & (SPU_STATUS_STOPPED_BY_STOP |
-                      SPU_STATUS_STOPPED_BY_HALT)) {
+
+       if (*status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT))
                return *status;
-       }
-       if ((ret = spu_run_init(ctx, npc)) != 0)
+
+       ret = spu_acquire_runnable(ctx, 0);
+       if (ret)
+               return ret;
+
+       ret = spu_run_init(ctx, npc);
+       if (ret) {
+               spu_release(ctx);
                return ret;
+       }
        return 0;
 }
 
@@ -253,17 +238,17 @@ int spu_process_callback(struct spu_context *ctx)
 {
        struct spu_syscall_block s;
        u32 ls_pointer, npc;
-       char *ls;
+       void __iomem *ls;
        long spu_ret;
        int ret;
 
        /* get syscall block from local store */
-       npc = ctx->ops->npc_read(ctx);
-       ls = ctx->ops->get_ls(ctx);
-       ls_pointer = *(u32*)(ls + npc);
+       npc = ctx->ops->npc_read(ctx) & ~3;
+       ls = (void __iomem *)ctx->ops->get_ls(ctx);
+       ls_pointer = in_be32(ls + npc);
        if (ls_pointer > (LS_SIZE - sizeof(s)))
                return -EFAULT;
-       memcpy(&s, ls + ls_pointer, sizeof (s));
+       memcpy_fromio(&s, ls + ls_pointer, sizeof(s));
 
        /* do actual syscall without pinning the spu */
        ret = 0;
@@ -283,7 +268,7 @@ int spu_process_callback(struct spu_context *ctx)
        }
 
        /* write result, jump over indirect pointer */
-       memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret));
+       memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret));
        ctx->ops->npc_write(ctx, npc);
        ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
        return ret;
@@ -292,11 +277,8 @@ int spu_process_callback(struct spu_context *ctx)
 static inline int spu_process_events(struct spu_context *ctx)
 {
        struct spu *spu = ctx->spu;
-       u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
        int ret = 0;
 
-       if (spu->dsisr & pte_fault)
-               ret = spu_irq_class_1_bottom(spu);
        if (spu->class_0_pending)
                ret = spu_irq_class_0_bottom(spu);
        if (!ret && signal_pending(current))
@@ -310,14 +292,21 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
        int ret;
        u32 status;
 
-       if (down_interruptible(&ctx->run_sema))
+       if (mutex_lock_interruptible(&ctx->run_mutex))
                return -ERESTARTSYS;
 
        ctx->ops->master_start(ctx);
        ctx->event_return = 0;
-       ret = spu_run_init(ctx, npc);
+
+       ret = spu_acquire_runnable(ctx, 0);
        if (ret)
+               return ret;
+
+       ret = spu_run_init(ctx, npc);
+       if (ret) {
+               spu_release(ctx);
                goto out;
+       }
 
        do {
                ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
@@ -330,6 +319,10 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
                                break;
                        status &= ~SPU_STATUS_STOPPED_BY_STOP;
                }
+               ret = spufs_handle_class1(ctx);
+               if (ret)
+                       break;
+
                if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
                        ret = spu_reacquire_runnable(ctx, npc, &status);
                        if (ret) {
@@ -363,6 +356,6 @@ out2:
 
 out:
        *event = ctx->event_return;
-       up(&ctx->run_sema);
+       mutex_unlock(&ctx->run_mutex);
        return ret;
 }
index 39823cec08444c6244ea8ca149fb4af39630be99..91030b8abdca6fbc62ca05efad87367f102c6885 100644 (file)
@@ -71,14 +71,27 @@ static inline int node_allowed(int node)
 
 void spu_start_tick(struct spu_context *ctx)
 {
-       if (ctx->policy == SCHED_RR)
+       if (ctx->policy == SCHED_RR) {
+               /*
+                * Make sure the exiting bit is cleared.
+                */
+               clear_bit(SPU_SCHED_EXITING, &ctx->sched_flags);
+               mb();
                queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE);
+       }
 }
 
 void spu_stop_tick(struct spu_context *ctx)
 {
-       if (ctx->policy == SCHED_RR)
+       if (ctx->policy == SCHED_RR) {
+               /*
+                * While the work can be rearming normally setting this flag
+                * makes sure it does not rearm itself anymore.
+                */
+               set_bit(SPU_SCHED_EXITING, &ctx->sched_flags);
+               mb();
                cancel_delayed_work(&ctx->sched_work);
+       }
 }
 
 void spu_sched_tick(struct work_struct *work)
@@ -86,7 +99,15 @@ void spu_sched_tick(struct work_struct *work)
        struct spu_context *ctx =
                container_of(work, struct spu_context, sched_work.work);
        struct spu *spu;
-       int rearm = 1;
+       int preempted = 0;
+
+       /*
+        * If this context is being stopped avoid rescheduling from the
+        * scheduler tick because we would block on the state_mutex.
+        * The caller will yield the spu later on anyway.
+        */
+       if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags))
+               return;
 
        mutex_lock(&ctx->state_mutex);
        spu = ctx->spu;
@@ -94,12 +115,19 @@ void spu_sched_tick(struct work_struct *work)
                int best = sched_find_first_bit(spu_prio->bitmap);
                if (best <= ctx->prio) {
                        spu_deactivate(ctx);
-                       rearm = 0;
+                       preempted = 1;
                }
        }
        mutex_unlock(&ctx->state_mutex);
 
-       if (rearm)
+       if (preempted) {
+               /*
+                * We need to break out of the wait loop in spu_run manually
+                * to ensure this context gets put on the runqueue again
+                * ASAP.
+                */
+               wake_up(&ctx->stop_wq);
+       } else
                spu_start_tick(ctx);
 }
 
@@ -208,58 +236,40 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
  * spu_add_to_rq - add a context to the runqueue
  * @ctx:       context to add
  */
-static void spu_add_to_rq(struct spu_context *ctx)
+static void __spu_add_to_rq(struct spu_context *ctx)
 {
-       spin_lock(&spu_prio->runq_lock);
-       list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]);
-       set_bit(ctx->prio, spu_prio->bitmap);
-       spin_unlock(&spu_prio->runq_lock);
-}
+       int prio = ctx->prio;
 
-/**
- * spu_del_from_rq - remove a context from the runqueue
- * @ctx:       context to remove
- */
-static void spu_del_from_rq(struct spu_context *ctx)
-{
-       spin_lock(&spu_prio->runq_lock);
-       list_del_init(&ctx->rq);
-       if (list_empty(&spu_prio->runq[ctx->prio]))
-               clear_bit(ctx->prio, spu_prio->bitmap);
-       spin_unlock(&spu_prio->runq_lock);
+       list_add_tail(&ctx->rq, &spu_prio->runq[prio]);
+       set_bit(prio, spu_prio->bitmap);
 }
 
-/**
- * spu_grab_context - remove one context from the runqueue
- * @prio:      priority of the context to be removed
- *
- * This function removes one context from the runqueue for priority @prio.
- * If there is more than one context with the given priority the first
- * task on the runqueue will be taken.
- *
- * Returns the spu_context it just removed.
- *
- * Must be called with spu_prio->runq_lock held.
- */
-static struct spu_context *spu_grab_context(int prio)
+static void __spu_del_from_rq(struct spu_context *ctx)
 {
-       struct list_head *rq = &spu_prio->runq[prio];
+       int prio = ctx->prio;
 
-       if (list_empty(rq))
-               return NULL;
-       return list_entry(rq->next, struct spu_context, rq);
+       if (!list_empty(&ctx->rq))
+               list_del_init(&ctx->rq);
+       if (list_empty(&spu_prio->runq[prio]))
+               clear_bit(prio, spu_prio->bitmap);
 }
 
 static void spu_prio_wait(struct spu_context *ctx)
 {
        DEFINE_WAIT(wait);
 
+       spin_lock(&spu_prio->runq_lock);
        prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE);
        if (!signal_pending(current)) {
+               __spu_add_to_rq(ctx);
+               spin_unlock(&spu_prio->runq_lock);
                mutex_unlock(&ctx->state_mutex);
                schedule();
                mutex_lock(&ctx->state_mutex);
+               spin_lock(&spu_prio->runq_lock);
+               __spu_del_from_rq(ctx);
        }
+       spin_unlock(&spu_prio->runq_lock);
        __set_current_state(TASK_RUNNING);
        remove_wait_queue(&ctx->stop_wq, &wait);
 }
@@ -280,9 +290,14 @@ static void spu_reschedule(struct spu *spu)
        spin_lock(&spu_prio->runq_lock);
        best = sched_find_first_bit(spu_prio->bitmap);
        if (best < MAX_PRIO) {
-               struct spu_context *ctx = spu_grab_context(best);
-               if (ctx)
-                       wake_up(&ctx->stop_wq);
+               struct list_head *rq = &spu_prio->runq[best];
+               struct spu_context *ctx;
+
+               BUG_ON(list_empty(rq));
+
+               ctx = list_entry(rq->next, struct spu_context, rq);
+               __spu_del_from_rq(ctx);
+               wake_up(&ctx->stop_wq);
        }
        spin_unlock(&spu_prio->runq_lock);
 }
@@ -365,6 +380,12 @@ static struct spu *find_victim(struct spu_context *ctx)
                        }
                        spu_unbind_context(spu, victim);
                        mutex_unlock(&victim->state_mutex);
+                       /*
+                        * We need to break out of the wait loop in spu_run
+                        * manually to ensure this context gets put on the
+                        * runqueue again ASAP.
+                        */
+                       wake_up(&victim->stop_wq);
                        return spu;
                }
        }
@@ -377,7 +398,7 @@ static struct spu *find_victim(struct spu_context *ctx)
  * @ctx:       spu context to schedule
  * @flags:     flags (currently ignored)
  *
- * Tries to find a free spu to run @ctx.  If no free spu is availble
+ * Tries to find a free spu to run @ctx.  If no free spu is available
  * add the context to the runqueue so it gets woken up once an spu
  * is available.
  */
@@ -402,9 +423,7 @@ int spu_activate(struct spu_context *ctx, unsigned long flags)
                        return 0;
                }
 
-               spu_add_to_rq(ctx);
                spu_prio_wait(ctx);
-               spu_del_from_rq(ctx);
        } while (!signal_pending(current));
 
        return -ERESTARTSYS;
@@ -438,7 +457,6 @@ void spu_deactivate(struct spu_context *ctx)
 void spu_yield(struct spu_context *ctx)
 {
        struct spu *spu;
-       int need_yield = 0;
 
        if (mutex_trylock(&ctx->state_mutex)) {
                if ((spu = ctx->spu) != NULL) {
@@ -447,13 +465,10 @@ void spu_yield(struct spu_context *ctx)
                                pr_debug("%s: yielding SPU %d NODE %d\n",
                                         __FUNCTION__, spu->number, spu->node);
                                spu_deactivate(ctx);
-                               need_yield = 1;
                        }
                }
                mutex_unlock(&ctx->state_mutex);
        }
-       if (unlikely(need_yield))
-               yield();
 }
 
 int __init spu_sched_init(void)
index 5c4e47d69d79478a37d7ff62563b5dea8d6fd7b8..0a947fd7de57c3da11e2444b64d5d020637a9323 100644 (file)
@@ -41,7 +41,7 @@ struct spu_gang;
 
 /* ctx->sched_flags */
 enum {
-       SPU_SCHED_WAKE = 0, /* currently unused */
+       SPU_SCHED_EXITING = 0,
 };
 
 struct spu_context {
@@ -50,16 +50,17 @@ struct spu_context {
        spinlock_t mmio_lock;             /* protects mmio access */
        struct address_space *local_store; /* local store mapping.  */
        struct address_space *mfc;         /* 'mfc' area mappings. */
-       struct address_space *cntl;        /* 'control' area mappings. */
-       struct address_space *signal1;     /* 'signal1' area mappings. */
-       struct address_space *signal2;     /* 'signal2' area mappings. */
-       struct address_space *mss;         /* 'mss' area mappings. */
-       struct address_space *psmap;       /* 'psmap' area mappings. */
+       struct address_space *cntl;        /* 'control' area mappings. */
+       struct address_space *signal1;     /* 'signal1' area mappings. */
+       struct address_space *signal2;     /* 'signal2' area mappings. */
+       struct address_space *mss;         /* 'mss' area mappings. */
+       struct address_space *psmap;       /* 'psmap' area mappings. */
+       spinlock_t mapping_lock;
        u64 object_id;             /* user space pointer for oprofile */
 
        enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
        struct mutex state_mutex;
-       struct semaphore run_sema;
+       struct mutex run_mutex;
 
        struct mm_struct *owner;
 
@@ -140,6 +141,7 @@ struct spu_context_ops {
                               struct spu_dma_info * info);
        void (*proxydma_info_read) (struct spu_context * ctx,
                                    struct spu_proxydma_info * info);
+       void (*restart_dma)(struct spu_context *ctx);
 };
 
 extern struct spu_context_ops spu_hw_ops;
@@ -149,6 +151,7 @@ struct spufs_inode_info {
        struct spu_context *i_ctx;
        struct spu_gang *i_gang;
        struct inode vfs_inode;
+       int i_openers;
 };
 #define SPUFS_I(inode) \
        container_of(inode, struct spufs_inode_info, vfs_inode)
@@ -170,6 +173,9 @@ int put_spu_gang(struct spu_gang *gang);
 void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx);
 void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx);
 
+/* fault handling */
+int spufs_handle_class1(struct spu_context *ctx);
+
 /* context management */
 static inline void spu_acquire(struct spu_context *ctx)
 {
@@ -190,7 +196,6 @@ void spu_unmap_mappings(struct spu_context *ctx);
 void spu_forget(struct spu_context *ctx);
 int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags);
 void spu_acquire_saved(struct spu_context *ctx);
-int spu_acquire_exclusive(struct spu_context *ctx);
 
 int spu_activate(struct spu_context *ctx, unsigned long flags);
 void spu_deactivate(struct spu_context *ctx);
@@ -218,14 +223,13 @@ extern char *isolated_loader;
                prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE);    \
                if (condition)                                          \
                        break;                                          \
-               if (!signal_pending(current)) {                         \
-                       spu_release(ctx);                               \
-                       schedule();                                     \
-                       spu_acquire(ctx);                               \
-                       continue;                                       \
+               if (signal_pending(current)) {                          \
+                       __ret = -ERESTARTSYS;                           \
+                       break;                                          \
                }                                                       \
-               __ret = -ERESTARTSYS;                                   \
-               break;                                                  \
+               spu_release(ctx);                                       \
+               schedule();                                             \
+               spu_acquire(ctx);                                       \
        }                                                               \
        finish_wait(&(wq), &__wait);                                    \
        __ret;                                                          \
index fd91c73de34e0b4913b93f93aa3222d089ea898d..8347c4a3f894a4bd647cc64b128a6a9089126dda 100644 (file)
@@ -2084,6 +2084,10 @@ int spu_save(struct spu_state *prev, struct spu *spu)
        int rc;
 
        acquire_spu_lock(spu);          /* Step 1.     */
+       prev->dar = spu->dar;
+       prev->dsisr = spu->dsisr;
+       spu->dar = 0;
+       spu->dsisr = 0;
        rc = __do_spu_save(prev, spu);  /* Steps 2-53. */
        release_spu_lock(spu);
        if (rc != 0 && rc != 2 && rc != 6) {
@@ -2109,9 +2113,9 @@ int spu_restore(struct spu_state *new, struct spu *spu)
 
        acquire_spu_lock(spu);
        harvest(NULL, spu);
-       spu->dar = 0;
-       spu->dsisr = 0;
        spu->slb_replace = 0;
+       new->dar = 0;
+       new->dsisr = 0;
        spu->class_0_pending = 0;
        rc = __do_spu_restore(new, spu);
        release_spu_lock(spu);
diff --git a/arch/powerpc/platforms/celleb/Kconfig b/arch/powerpc/platforms/celleb/Kconfig
new file mode 100644 (file)
index 0000000..2db1e29
--- /dev/null
@@ -0,0 +1,9 @@
+config PPC_CELLEB
+       bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
+       depends on PPC_MULTIPLATFORM && PPC64
+       select PPC_CELL
+       select PPC_OF_PLATFORM_PCI
+       select HAS_TXX9_SERIAL
+       select PPC_UDBG_BEAT
+       select USB_OHCI_BIG_ENDIAN_MMIO
+       select USB_EHCI_BIG_ENDIAN_MMIO
index f63b94c65353218b28a913916818e1e8763fc3a9..755d869d8553c424b978c21a6da7978f438dd03b 100644 (file)
@@ -37,7 +37,7 @@ static int __init find_dma_window(u64 *io_space_id, u64 *ioid,
        const unsigned long *dma_window;
 
        for_each_node_by_type(dn, "ioif") {
-               dma_window = get_property(dn, "toshiba,dma-window", NULL);
+               dma_window = of_get_property(dn, "toshiba,dma-window", NULL);
                if (dma_window) {
                        *io_space_id = (dma_window[0] >> 32) & 0xffffffffUL;
                        *ioid = dma_window[0] & 0x7ffUL;
@@ -80,7 +80,7 @@ static int celleb_of_bus_notify(struct notifier_block *nb,
        if (action != BUS_NOTIFY_ADD_DEVICE)
                return 0;
 
-       dev->archdata.dma_ops = pci_dma_ops;
+       dev->archdata.dma_ops = get_pci_dma_ops();
 
        return 0;
 }
@@ -95,7 +95,7 @@ static int __init celleb_init_iommu(void)
                return -ENODEV;
 
        celleb_init_direct_mapping();
-       pci_dma_ops = &dma_direct_ops;
+       set_pci_dma_ops(&dma_direct_ops);
        bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier);
 
        return 0;
index 98de836dfed3fd4e7219e6a43130ad7bde04a1a3..d1adf34cd5e8dedc2b9a43625704d765da37734e 100644 (file)
@@ -309,13 +309,13 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
                goto error;
        }
 
-       name = get_property(node, "model", &rlen);
+       name = of_get_property(node, "model", &rlen);
        if (!name) {
                printk(KERN_ERR "PCI: model property not found.\n");
                goto error;
        }
 
-       wi4 = get_property(node, "reg", &rlen);
+       wi4 = of_get_property(node, "reg", &rlen);
        if (wi4 == NULL)
                goto error;
 
@@ -352,10 +352,10 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
        }
        pr_debug("PCI: res assigned 0x%016lx\n", (unsigned long)*res);
 
-       wi0 = get_property(node, "device-id", NULL);
-       wi1 = get_property(node, "vendor-id", NULL);
-       wi2 = get_property(node, "class-code", NULL);
-       wi3 = get_property(node, "revision-id", NULL);
+       wi0 = of_get_property(node, "device-id", NULL);
+       wi1 = of_get_property(node, "vendor-id", NULL);
+       wi2 = of_get_property(node, "class-code", NULL);
+       wi3 = of_get_property(node, "revision-id", NULL);
 
        celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff);
        celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff);
@@ -376,7 +376,7 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
 
        celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr);
 
-       li = get_property(node, "interrupts", &rlen);
+       li = of_get_property(node, "interrupts", &rlen);
        val = li[0];
        celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1);
        celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val);
@@ -424,7 +424,7 @@ static int __devinit phb_set_bus_ranges(struct device_node *dev,
        const int *bus_range;
        unsigned int len;
 
-       bus_range = get_property(dev, "bus-range", &len);
+       bus_range = of_get_property(dev, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int))
                return 1;
 
@@ -451,7 +451,7 @@ int __devinit celleb_setup_phb(struct pci_controller *phb)
        struct device_node *node;
        unsigned int rlen;
 
-       name = get_property(dev, "name", &rlen);
+       name = of_get_property(dev, "name", &rlen);
        if (!name)
                return 1;
 
index 5f4d0d9332388e1e9455f5a0a7a6c1c49294a7d4..596ab2a788d4571cd3f51f85a7b15352bbf25794 100644 (file)
@@ -67,7 +67,7 @@ static void celleb_show_cpuinfo(struct seq_file *m)
 
        root = of_find_node_by_path("/");
        if (root)
-               model = get_property(root, "model", NULL);
+               model = of_get_property(root, "model", NULL);
        /* using "CHRP" is to trick anaconda into installing FCx into Celleb */
        seq_printf(m, "machine\t\t: %s %s\n", celleb_machine_type, model);
        of_node_put(root);
@@ -128,15 +128,6 @@ static int __init celleb_probe(void)
        return 1;
 }
 
-/*
- * Cell has no legacy IO; anything calling this function has to
- * fail or bad things will happen
- */
-static int celleb_check_legacy_ioport(unsigned int baseport)
-{
-       return -ENODEV;
-}
-
 #ifdef CONFIG_KEXEC
 static void celleb_kexec_cpu_down(int crash, int secondary)
 {
@@ -173,7 +164,6 @@ define_machine(celleb) {
        .get_rtc_time           = beat_get_rtc_time,
        .set_rtc_time           = beat_set_rtc_time,
        .calibrate_decr         = generic_calibrate_decr,
-       .check_legacy_ioport    = celleb_check_legacy_ioport,
        .progress               = celleb_progress,
        .power_save             = beat_power_save,
        .nvram_size             = beat_nvram_get_size,
diff --git a/arch/powerpc/platforms/chrp/Kconfig b/arch/powerpc/platforms/chrp/Kconfig
new file mode 100644 (file)
index 0000000..d2c6905
--- /dev/null
@@ -0,0 +1,11 @@
+config PPC_CHRP
+       bool "Common Hardware Reference Platform (CHRP) based machines"
+       depends on PPC_MULTIPLATFORM && PPC32
+       select MPIC
+       select PPC_I8259
+       select PPC_INDIRECT_PCI
+       select PPC_RTAS
+       select PPC_MPC106
+       select PPC_UDBG_16550
+       select PPC_NATIVE
+       default y
index 0dd4a64757d92a03d1699046d028a72407c426c8..8efd4244701c2eb1d0a73b07d9e21888ae066e94 100644 (file)
@@ -74,7 +74,7 @@ void __init chrp_nvram_init(void)
        if (nvram == NULL)
                return;
 
-       nbytes_p = get_property(nvram, "#bytes", &proplen);
+       nbytes_p = of_get_property(nvram, "#bytes", &proplen);
        if (nbytes_p == NULL || proplen != sizeof(unsigned int))
                return;
 
index ddb4a116ea89b7d0be044c7531cd87aeb59d7093..1469d6478f67663b504b692416931e3879334353 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -137,9 +136,11 @@ hydra_init(void)
        struct device_node *np;
        struct resource r;
 
-       np = find_devices("mac-io");
-       if (np == NULL || of_address_to_resource(np, 0, &r))
+       np = of_find_node_by_name(NULL, "mac-io");
+       if (np == NULL || of_address_to_resource(np, 0, &r)) {
+               of_node_put(np);
                return 0;
+       }
        Hydra = ioremap(r.start, r.end-r.start);
        printk("Hydra Mac I/O at %llx\n", (unsigned long long)r.start);
        printk("Hydra Feature_Control was %x",
@@ -186,10 +187,9 @@ setup_python(struct pci_controller *hose, struct device_node *dev)
 /* Marvell Discovery II based Pegasos 2 */
 static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev)
 {
-       struct device_node *root = find_path_device("/");
+       struct device_node *root = of_find_node_by_path("/");
        struct device_node *rtas;
 
-       of_node_get(root);
        rtas = of_find_node_by_name (root, "rtas");
        if (rtas) {
                hose->ops = &rtas_pci_ops;
@@ -199,6 +199,7 @@ static void __init setup_peg2(struct pci_controller *hose, struct device_node *d
                        " your firmware\n");
        }
        pci_assign_all_buses = 1;
+       /* keep the reference to the root node */
 }
 
 void __init
@@ -211,14 +212,14 @@ chrp_find_bridges(void)
        const unsigned int *dma;
        const char *model, *machine;
        int is_longtrail = 0, is_mot = 0, is_pegasos = 0;
-       struct device_node *root = find_path_device("/");
+       struct device_node *root = of_find_node_by_path("/");
        struct resource r;
        /*
         * The PCI host bridge nodes on some machines don't have
         * properties to adequately identify them, so we have to
         * look at what sort of machine this is as well.
         */
-       machine = get_property(root, "model", NULL);
+       machine = of_get_property(root, "model", NULL);
        if (machine != NULL) {
                is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
                is_mot = strncmp(machine, "MOT", 3) == 0;
@@ -237,7 +238,7 @@ chrp_find_bridges(void)
                               dev->full_name);
                        continue;
                }
-               bus_range = get_property(dev, "bus-range", &len);
+               bus_range = of_get_property(dev, "bus-range", &len);
                if (bus_range == NULL || len < 2 * sizeof(int)) {
                        printk(KERN_WARNING "Can't get bus-range for %s\n",
                                dev->full_name);
@@ -263,7 +264,7 @@ chrp_find_bridges(void)
                hose->first_busno = bus_range[0];
                hose->last_busno = bus_range[1];
 
-               model = get_property(dev, "model", NULL);
+               model = of_get_property(dev, "model", NULL);
                if (model == NULL)
                        model = "<none>";
                if (device_is_compatible(dev, "IBM,python")) {
@@ -285,7 +286,8 @@ chrp_find_bridges(void)
                                           r.start + 0x000f8000,
                                           r.start + 0x000f8010);
                        if (index == 0) {
-                               dma = get_property(dev, "system-dma-base",&len);
+                               dma = of_get_property(dev, "system-dma-base",
+                                                       &len);
                                if (dma && len >= sizeof(*dma)) {
                                        dma = (unsigned int *)
                                                (((unsigned long)dma) +
@@ -303,12 +305,13 @@ chrp_find_bridges(void)
 
                /* check the first bridge for a property that we can
                   use to set pci_dram_offset */
-               dma = get_property(dev, "ibm,dma-ranges", &len);
+               dma = of_get_property(dev, "ibm,dma-ranges", &len);
                if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) {
                        pci_dram_offset = dma[2] - dma[3];
                        printk("pci_dram_offset = %lx\n", pci_dram_offset);
                }
        }
+       of_node_put(root);
 }
 
 /* SL82C105 IDE Control/Status Register */
index 117c9a0055bd734939b3ac5269c96edeef08f9c7..1870038a8e0a7ea3b47f26578e31559d962db284 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/adb.h>
 #include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/ide.h>
 #include <linux/console.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
@@ -111,9 +110,9 @@ void chrp_show_cpuinfo(struct seq_file *m)
        struct device_node *root;
        const char *model = "";
 
-       root = find_path_device("/");
+       root = of_find_node_by_path("/");
        if (root)
-               model = get_property(root, "model", NULL);
+               model = of_get_property(root, "model", NULL);
        seq_printf(m, "machine\t\t: CHRP %s\n", model);
 
        /* longtrail (goldengate) stuff */
@@ -161,6 +160,7 @@ void chrp_show_cpuinfo(struct seq_file *m)
                           gg2_cachetypes[(t>>2) & 3],
                           gg2_cachemodes[t & 3]);
        }
+       of_node_put(root);
 }
 
 /*
@@ -205,13 +205,15 @@ static void __init sio_init(void)
 {
        struct device_node *root;
 
-       if ((root = find_path_device("/")) &&
-           !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
+       if ((root = of_find_node_by_path("/")) &&
+           !strncmp(of_get_property(root, "model", NULL),
+                       "IBM,LongTrail", 13)) {
                /* logical device 0 (KBC/Keyboard) */
                sio_fixup_irq("keyboard", 0, 1, 2);
                /* select logical device 1 (KBC/Mouse) */
                sio_fixup_irq("mouse", 1, 12, 2);
        }
+       of_node_put(root);
 }
 
 
@@ -224,12 +226,12 @@ static void __init pegasos_set_l2cr(void)
                return;
 
        /* Enable L2 cache if needed */
-       np = find_type_devices("cpu");
+       np = of_find_node_by_type(NULL, "cpu");
        if (np != NULL) {
-               const unsigned int *l2cr = get_property(np, "l2cr", NULL);
+               const unsigned int *l2cr = of_get_property(np, "l2cr", NULL);
                if (l2cr == NULL) {
                        printk ("Pegasos l2cr : no cpu l2cr property found\n");
-                       return;
+                       goto out;
                }
                if (!((*l2cr) & 0x80000000)) {
                        printk ("Pegasos l2cr : L2 cache was not active, "
@@ -238,6 +240,8 @@ static void __init pegasos_set_l2cr(void)
                        _set_L2CR((*l2cr) | 0x80000000);
                }
        }
+out:
+       of_node_put(np);
 }
 
 static void briq_restart(char *cmd)
@@ -250,14 +254,14 @@ static void briq_restart(char *cmd)
 
 void __init chrp_setup_arch(void)
 {
-       struct device_node *root = find_path_device ("/");
+       struct device_node *root = of_find_node_by_path("/");
        const char *machine = NULL;
 
        /* init to some ~sane value until calibrate_delay() runs */
        loops_per_jiffy = 50000000/HZ;
 
        if (root)
-               machine = get_property(root, "model", NULL);
+               machine = of_get_property(root, "model", NULL);
        if (machine && strncmp(machine, "Pegasos", 7) == 0) {
                _chrp_type = _CHRP_Pegasos;
        } else if (machine && strncmp(machine, "IBM", 3) == 0) {
@@ -273,6 +277,7 @@ void __init chrp_setup_arch(void)
                /* Let's assume it is an IBM chrp if all else fails */
                _chrp_type = _CHRP_IBM;
        }
+       of_node_put(root);
        printk("chrp type = %x [%s]\n", _chrp_type, chrp_names[_chrp_type]);
 
        rtas_initialize();
@@ -361,8 +366,8 @@ static void __init chrp_find_openpic(void)
                return;
        root = of_find_node_by_path("/");
        if (root) {
-               opprop = get_property(root, "platform-open-pic", &oplen);
-               na = prom_n_addr_cells(root);
+               opprop = of_get_property(root, "platform-open-pic", &oplen);
+               na = of_n_addr_cells(root);
        }
        if (opprop && oplen >= na * sizeof(unsigned int)) {
                opaddr = opprop[na-1];  /* assume 32-bit */
@@ -378,7 +383,7 @@ static void __init chrp_find_openpic(void)
 
        printk(KERN_INFO "OpenPIC at %lx\n", opaddr);
 
-       iranges = get_property(np, "interrupt-ranges", &len);
+       iranges = of_get_property(np, "interrupt-ranges", &len);
        if (iranges == NULL)
                len = 0;        /* non-distributed mpic */
        else
@@ -427,7 +432,7 @@ static void __init chrp_find_openpic(void)
        of_node_put(np);
 }
 
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
 static struct irqaction xmon_irqaction = {
        .handler = xmon_irq,
        .mask = CPU_MASK_NONE,
@@ -463,15 +468,16 @@ static void __init chrp_find_8259(void)
         * Also, Pegasos-type platforms don't have a proper node to start
         * from anyway
         */
-       for (np = find_devices("pci"); np != NULL; np = np->next) {
-               const unsigned int *addrp = get_property(np,
+       for_each_node_by_name(np, "pci") {
+               const unsigned int *addrp = of_get_property(np,
                                "8259-interrupt-acknowledge", NULL);
 
                if (addrp == NULL)
                        continue;
-               chrp_int_ack = addrp[prom_n_addr_cells(np)-1];
+               chrp_int_ack = addrp[of_n_addr_cells(np)-1];
                break;
        }
+       of_node_put(np);
        if (np == NULL)
                printk(KERN_WARNING "Cannot find PCI interrupt acknowledge"
                       " address, polling\n");
@@ -493,7 +499,7 @@ static void __init chrp_find_8259(void)
 
 void __init chrp_init_IRQ(void)
 {
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
        struct device_node *kbd;
 #endif
        chrp_find_openpic();
@@ -510,13 +516,14 @@ void __init chrp_init_IRQ(void)
        if (_chrp_type == _CHRP_Pegasos)
                ppc_md.get_irq        = i8259_irq;
 
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
        /* see if there is a keyboard in the device tree
           with a parent of type "adb" */
-       for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
+       for_each_node_by_name(kbd, "keyboard")
                if (kbd->parent && kbd->parent->type
                    && strcmp(kbd->parent->type, "adb") == 0)
                        break;
+       of_node_put(kbd);
        if (kbd)
                setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction);
 #endif
@@ -542,9 +549,9 @@ chrp_init2(void)
        /* Get the event scan rate for the rtas so we know how
         * often it expects a heartbeat. -- Cort
         */
-       device = find_devices("rtas");
+       device = of_find_node_by_name(NULL, "rtas");
        if (device)
-               p = get_property(device, "rtas-event-scan-rate", NULL);
+               p = of_get_property(device, "rtas-event-scan-rate", NULL);
        if (p && *p) {
                /*
                 * Arrange to call chrp_event_scan at least *p times
@@ -571,6 +578,7 @@ chrp_init2(void)
                printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
                       *p, interval);
        }
+       of_node_put(device);
 
        if (ppc_md.progress)
                ppc_md.progress("  Have fun!    ", 0x7777);
index 7d7889026936a2eee1366b4ba7e6cc6b9e35923c..96d1e4b3c493f8628049891f8f54d1813e8cadaa 100644 (file)
@@ -39,12 +39,17 @@ long __init chrp_time_init(void)
        struct resource r;
        int base;
 
-       rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
+       rtcs = of_find_compatible_node(NULL, "rtc", "pnpPNP,b00");
        if (rtcs == NULL)
-               rtcs = find_compatible_devices("rtc", "ds1385-rtc");
-       if (rtcs == NULL || of_address_to_resource(rtcs, 0, &r))
+               rtcs = of_find_compatible_node(NULL, "rtc", "ds1385-rtc");
+       if (rtcs == NULL)
+               return 0;
+       if (of_address_to_resource(rtcs, 0, &r)) {
+               of_node_put(rtcs);
                return 0;
-       
+       }
+       of_node_put(rtcs);
+
        base = r.start;
        nvram_as1 = 0;
        nvram_as0 = base;
index 3410bcbc9dbe04030b6952ce537f1306a2186d18..9557908ef54578789322cc4fd75c5da7c4d6443d 100644 (file)
@@ -2,78 +2,6 @@ choice
        prompt "Machine Type"
        depends on EMBEDDED6xx
 
-config KATANA
-       bool "Artesyn-Katana"
-       help
-         Select KATANA if configuring an Artesyn KATANA 750i or 3750
-         cPCI board.
-
-config WILLOW
-       bool "Cogent-Willow"
-
-config CPCI690
-       bool "Force-CPCI690"
-       help
-         Select CPCI690 if configuring a Force CPCI690 cPCI board.
-
-config POWERPMC250
-       bool "Force-PowerPMC250"
-
-config CHESTNUT
-       bool "IBM 750FX Eval board or 750GX Eval board"
-       help
-         Select CHESTNUT if configuring an IBM 750FX Eval Board or a
-         IBM 750GX Eval board.
-
-config SPRUCE
-       bool "IBM-Spruce"
-       select PPC_INDIRECT_PCI
-
-config HDPU
-       bool "Sky-HDPU"
-       help
-         Select HDPU if configuring a Sky Computers Compute Blade.
-
-config HDPU_FEATURES
-       depends on HDPU
-       tristate "HDPU-Features"
-       help
-         Select to enable HDPU enhanced features.
-
-config EV64260
-       bool "Marvell-EV64260BP"
-       help
-         Select EV64260 if configuring a Marvell (formerly Galileo)
-         EV64260BP Evaluation platform.
-
-config LOPEC
-       bool "Motorola-LoPEC"
-       select PPC_I8259
-
-config MVME5100
-       bool "Motorola-MVME5100"
-       select PPC_INDIRECT_PCI
-
-config PPLUS
-       bool "Motorola-PowerPlus"
-       select PPC_I8259
-       select PPC_INDIRECT_PCI
-
-config PRPMC750
-       bool "Motorola-PrPMC750"
-       select PPC_INDIRECT_PCI
-
-config PRPMC800
-       bool "Motorola-PrPMC800"
-       select PPC_INDIRECT_PCI
-
-config SANDPOINT
-       bool "Motorola-Sandpoint"
-       select PPC_I8259
-       help
-         Select SANDPOINT if configuring for a Motorola Sandpoint X3
-         (any flavor).
-
 config LINKSTATION
        bool "Linkstation / Kurobox(HG) from Buffalo"
        select MPIC
@@ -97,212 +25,24 @@ config MPC7448HPC2
        help
          Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga)
          platform
-
-config RADSTONE_PPC7D
-       bool "Radstone Technology PPC7D board"
-       select PPC_I8259
-
-config PAL4
-       bool "SBS-Palomar4"
-
-config EST8260
-       bool "EST8260"
-       ---help---
-         The EST8260 is a single-board computer manufactured by Wind River
-         Systems, Inc. (formerly Embedded Support Tools Corp.) and based on
-         the MPC8260.  Wind River Systems has a website at
-         <http://www.windriver.com/>, but the EST8260 cannot be found on it
-         and has probably been discontinued or rebadged.
-
-config SBC82xx
-       bool "SBC82xx"
-       ---help---
-         SBC PowerQUICC II, single-board computer with MPC82xx CPU
-         Manufacturer: Wind River Systems, Inc.
-         Date of Release: May 2003
-         End of Life: -
-         URL: <http://www.windriver.com/>
-
-config SBS8260
-       bool "SBS8260"
-
-config RPX8260
-       bool "RPXSUPER"
-
-config TQM8260
-       bool "TQM8260"
-       ---help---
-         MPC8260 based module, little larger than credit card,
-         up to 128 MB global + 64 MB local RAM, 32 MB Flash,
-         32 kB EEPROM, 256 kB L@ Cache, 10baseT + 100baseT Ethernet,
-         2 x serial ports, ...
-         Manufacturer: TQ Components, www.tq-group.de
-         Date of Release: June 2001
-         End of Life: not yet :-)
-         URL: <http://www.denx.de/PDF/TQM82xx_SPEC_Rev005.pdf>
-
-config ADS8272
-       bool "ADS8272"
-
-config PQ2FADS
-       bool "Freescale-PQ2FADS"
-       help
-         Select PQ2FADS if you wish to configure for a Freescale
-         PQ2FADS board (-VR or -ZU).
-
-config EV64360
-       bool "Marvell-EV64360BP"
-       help
-         Select EV64360 if configuring a Marvell EV64360BP Evaluation
-         platform.
 endchoice
 
-config PQ2ADS
-       bool
-       depends on ADS8272
-       default y
-
-config TQM8xxL
-       bool
-       depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L)
-       default y
-
-config 8260
-       bool "CPM2 Support" if WILLOW
-       depends on 6xx
-       default y if TQM8260 || RPX8260 || EST8260 || SBS8260 || SBC82xx || PQ2FADS
-       help
-         The MPC8260 is a typical embedded CPU made by Motorola.  Selecting
-         this option means that you wish to build a kernel for a machine with
-         an 8260 class CPU.
-
-config 8272
-       bool
-       depends on 6xx
-       default y if ADS8272
-       select 8260
-       help
-         The MPC8272 CPM has a different internal dpram setup than other CPM2
-         devices
-
-config CPM2
-       bool
-       depends on 8260 || MPC8560 || MPC8555
-       default y
-       help
-         The CPM2 (Communications Processor Module) is a coprocessor on
-         embedded CPUs made by Motorola.  Selecting this option means that
-         you wish to build a kernel for a machine with a CPM2 coprocessor
-         on it (826x, 827x, 8560).
-
-config PPC_GEN550
-       bool
-       depends on SANDPOINT || SPRUCE || PPLUS || \
-               PRPMC750 || PRPMC800 || LOPEC || \
-               (EV64260 && !SERIAL_MPSC) || CHESTNUT || RADSTONE_PPC7D || \
-               83xx || LINKSTATION
-       default y
-
-config FORCE
-       bool
-       depends on 6xx && POWERPMC250
-       default y
-
-config GT64260
-       bool
-       depends on EV64260 || CPCI690
-       default y
-
-config MV64360         # Really MV64360 & MV64460
-       bool
-       depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU || EV64360
-       default y
-
-config MV64X60
-       bool
-       depends on (GT64260 || MV64360)
-       select PPC_INDIRECT_PCI
-       default y
-
 config TSI108_BRIDGE
        bool
        depends on MPC7448HPC2
        default y
 
-menu "Set bridge options"
-       depends on MV64X60
-
-config NOT_COHERENT_CACHE
-       bool "Turn off Cache Coherency"
-       default n
-       help
-         Some 64x60 bridges lock up when trying to enforce cache coherency.
-         When this option is selected, cache coherency will be turned off.
-         Note that this can cause other problems (e.g., stale data being
-         speculatively loaded via a cached mapping).  Use at your own risk.
-
-config MV64X60_BASE
-       hex "Set bridge base used by firmware"
-       default "0xf1000000"
-       help
-         A firmware can leave the base address of the bridge's registers at
-         a non-standard location.  If so, set this value to reflect the
-         address of that non-standard location.
-
-config MV64X60_NEW_BASE
-       hex "Set bridge base used by kernel"
-       default "0xf1000000"
-       help
-         If the current base address of the bridge's registers is not where
-         you want it, set this value to the address that you want it moved to.
-
-endmenu
-
-config NONMONARCH_SUPPORT
-       bool "Enable Non-Monarch Support"
-       depends on PRPMC800
-
-config HARRIER
-       bool
-       depends on PRPMC800
-       default y
-
-config EPIC_SERIAL_MODE
-       bool
-       depends on 6xx && (LOPEC || SANDPOINT)
-       default y
-
 config MPC10X_BRIDGE
        bool
-       depends on POWERPMC250 || LOPEC || SANDPOINT || LINKSTATION
+       depends on LINKSTATION
        select PPC_INDIRECT_PCI
        default y
 
 config MPC10X_OPENPIC
        bool
-       depends on POWERPMC250 || LOPEC || SANDPOINT || LINKSTATION
+       depends on LINKSTATION
        default y
 
 config MPC10X_STORE_GATHERING
        bool "Enable MPC10x store gathering"
        depends on MPC10X_BRIDGE
-
-config SANDPOINT_ENABLE_UART1
-       bool "Enable DUART mode on Sandpoint"
-       depends on SANDPOINT
-       help
-         If this option is enabled then the MPC824x processor will run
-         in DUART mode instead of UART mode.
-
-config HARRIER_STORE_GATHERING
-       bool "Enable Harrier store gathering"
-       depends on HARRIER
-
-config MVME5100_IPMC761_PRESENT
-       bool "MVME5100 configured with an IPMC761"
-       depends on MVME5100
-       select PPC_I8259
-
-config SPRUCE_BAUD_33M
-       bool "Spruce baud clock support"
-       depends on SPRUCE
index 3f6c4114f908c392a27e2b1d92b6691b875782de..b412f006a9c55a8dd0bd60ebd193ab1277872793 100644 (file)
@@ -58,11 +58,11 @@ static int __init add_bridge(struct device_node *dev)
 {
        int len;
        struct pci_controller *hose;
-       int *bus_range;
+       const int *bus_range;
 
        printk("Adding PCI host bridge %s\n", dev->full_name);
 
-       bus_range = (int *) get_property(dev, "bus-range", &len);
+       bus_range = of_get_property(dev, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int))
                printk(KERN_WARNING "Can't get bus-range for %s, assume"
                                " bus 0\n", dev->full_name);
@@ -106,7 +106,7 @@ static void __init linkstation_init_IRQ(void)
 {
        struct mpic *mpic;
        struct device_node *dnp;
-       void *prop;
+       const u32 *prop;
        int size;
        phys_addr_t paddr;
 
@@ -114,7 +114,7 @@ static void __init linkstation_init_IRQ(void)
        if (dnp == NULL)
                return;
 
-       prop = (struct device_node *)get_property(dnp, "reg", &size);
+       prop = of_get_property(dnp, "reg", &size);
        paddr = (phys_addr_t)of_translate_address(dnp, prop);
 
        mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, 4, 32, " EPIC     ");
index 0e837762cc5bf5b60b7a047fe62ac9b2c51d2a05..d0bee9f19e4e8659140c75b0ad215baa50cac2ef 100644 (file)
@@ -110,8 +110,8 @@ static int __init ls_uarts_init(void)
        if (!avr)
                return -EINVAL;
 
-       avr_clock = *(u32*)get_property(avr, "clock-frequency", &len);
-       phys_addr = ((u32*)get_property(avr, "reg", &len))[0];
+       avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len);
+       phys_addr = ((u32*)of_get_property(avr, "reg", &len))[0];
 
        if (!avr_clock || !phys_addr)
                return -EINVAL;
index 3fcc85f60fbf2d78b7ee8ba29c8733026e951fcd..c3f64ddb0be6e2e756a5e915b0276f72c62a9639 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
-#include <linux/ide.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
 #include <linux/serial.h>
@@ -82,7 +81,7 @@ static void __init mpc7448_hpc2_setup_arch(void)
        if (cpu != 0) {
                const unsigned int *fp;
 
-               fp = get_property(cpu, "clock-frequency", NULL);
+               fp = of_get_property(cpu, "clock-frequency", NULL);
                if (fp != 0)
                        loops_per_jiffy = *fp / HZ;
                else
@@ -91,16 +90,6 @@ static void __init mpc7448_hpc2_setup_arch(void)
        }
        tsi108_csr_vir_base = get_vir_csrbase();
 
-#ifdef CONFIG_ROOT_NFS
-       ROOT_DEV = Root_NFS;
-#else
-       ROOT_DEV = Root_HDA1;
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       ROOT_DEV = Root_RAM0;
-#endif
-
        /* setup PCI host bridge */
 #ifdef CONFIG_PCI
        for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
@@ -143,7 +132,7 @@ static void __init mpc7448_hpc2_init_IRQ(void)
        tsi_pic = of_find_node_by_type(NULL, "open-pic");
        if (tsi_pic) {
                unsigned int size;
-               const void *prop = get_property(tsi_pic, "reg", &size);
+               const void *prop = of_get_property(tsi_pic, "reg", &size);
                mpic_paddr = of_translate_address(tsi_pic, prop);
        }
 
index 54e6b3b6f2615445fb2a742f02f67beda095b560..46c3a8e7c3a8a0a5b035991c9a34921423af8eca 100644 (file)
@@ -1,3 +1,7 @@
+config PPC_ISERIES
+       bool "IBM Legacy iSeries"
+       depends on PPC_MULTIPLATFORM && PPC64
+       select PPC_INDIRECT_IO
 
 menu "iSeries device drivers"
        depends on PPC_ISERIES
index d7a756d5135cf4ee0ba6366106f69a2b639658db..3b6a9666c2c07c0407989a5a17d98e2cdcdf4179 100644 (file)
@@ -171,7 +171,7 @@ void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn)
 {
        struct iommu_table *tbl;
        struct pci_dn *pdn = PCI_DN(dn);
-       const u32 *lsn = get_property(dn, "linux,logical-slot-number", NULL);
+       const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL);
 
        BUG_ON(lsn == NULL);
 
@@ -194,5 +194,5 @@ void iommu_init_early_iSeries(void)
        ppc_md.tce_build = tce_build_iSeries;
        ppc_md.tce_free  = tce_free_iSeries;
 
-       pci_dma_ops = &dma_iommu_ops;
+       set_pci_dma_ops(&dma_iommu_ops);
 }
index 5225abfafd9b8f44b1ec7e7aeac3cfe800e233a7..63b33675848b01f77ef713b6224590f2a055a8b3 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/param.h>
 #include <linux/string.h>
 #include <linux/bootmem.h>
-#include <linux/ide.h>
 #include <linux/irq.h>
 #include <linux/spinlock.h>
 
@@ -337,6 +336,8 @@ unsigned int iSeries_get_irq(void)
        return irq;
 }
 
+#ifdef CONFIG_PCI
+
 static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
                                irq_hw_number_t hw)
 {
@@ -384,3 +385,4 @@ void __init iSeries_init_IRQ(void)
                                "failed with rc 0x%x\n", ret);
 }
 
+#endif /* CONFIG_PCI */
index 4a06d9c349869cdcb1fda45c516034b8cf992867..9c974227155e5a957ad98391bde74a97f4f62a4b 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/ide.h>
 #include <linux/pci.h>
 
 #include <asm/io.h>
@@ -177,7 +176,7 @@ void __init iSeries_pci_final_fixup(void)
                        struct pci_dn *pdn = PCI_DN(node);
                        const u32 *agent;
 
-                       agent = get_property(node, "linux,agent-id", NULL);
+                       agent = of_get_property(node, "linux,agent-id", NULL);
                        if ((pdn != NULL) && (agent != NULL)) {
                                u8 irq = iSeries_allocate_IRQ(pdn->busno, 0,
                                                pdn->bussubno);
@@ -755,7 +754,7 @@ void __init iSeries_pcibios_init(void)
                if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
                        continue;
 
-               busp = get_property(node, "bus-range", NULL);
+               busp = of_get_property(node, "bus-range", NULL);
                if (busp == NULL)
                        continue;
                bus = *busp;
index cce7e309340c99f933390dd5cf81f65a0fb0ab39..7f5dcee814d4cde9f4331eb8442920f8136eb10e 100644 (file)
@@ -628,15 +628,6 @@ static void iseries_iounmap(volatile void __iomem *token)
 {
 }
 
-/*
- * iSeries has no legacy IO, anything calling this function has to
- * fail or bad things will happen
- */
-static int iseries_check_legacy_ioport(unsigned int baseport)
-{
-       return -ENODEV;
-}
-
 static int __init iseries_probe(void)
 {
        unsigned long root = of_get_flat_dt_root();
@@ -667,7 +658,6 @@ define_machine(iseries) {
        .calibrate_decr = generic_calibrate_decr,
        .progress       = iSeries_progress,
        .probe          = iseries_probe,
-       .check_legacy_ioport    = iseries_check_legacy_ioport,
        .ioremap        = iseries_ioremap,
        .iounmap        = iseries_iounmap,
        /* XXX Implement enable_pmcs for iSeries */
index e2100ece9c652759162dec6f7b0bee08656a9297..2ca2d8a9de97ac5bcf23148e62141df6978f069b 100644 (file)
@@ -155,7 +155,7 @@ static int proc_viopath_show(struct seq_file *m, void *v)
        node = of_find_node_by_path("/");
        sysid = NULL;
        if (node != NULL)
-               sysid = get_property(node, "system-id", NULL);
+               sysid = of_get_property(node, "system-id", NULL);
 
        if (sysid == NULL)
                seq_printf(m, "SRLNBR=<UNKNOWN>\n");
diff --git a/arch/powerpc/platforms/maple/Kconfig b/arch/powerpc/platforms/maple/Kconfig
new file mode 100644 (file)
index 0000000..f7c95eb
--- /dev/null
@@ -0,0 +1,17 @@
+config PPC_MAPLE
+       depends on PPC_MULTIPLATFORM && PPC64
+       bool "Maple 970FX Evaluation Board"
+       select MPIC
+       select U3_DART
+       select MPIC_U3_HT_IRQS
+       select GENERIC_TBSYNC
+       select PPC_UDBG_16550
+       select PPC_970_NAP
+       select PPC_NATIVE
+       select PPC_RTAS
+       select MMIO_NVRAM
+       select ATA_NONSTANDARD if ATA
+       default n
+       help
+          This option enables support for the Maple 970FX Evaluation Board.
+         For more information, refer to <http://www.970eval.com>
index 73c59904697fa00eb1325aa61daa46950f549628..b1d3b99c3f9d74abf96f5f5fa46b5f5de3b72a88 100644 (file)
@@ -44,11 +44,11 @@ static int __init fixup_one_level_bus_range(struct device_node *node, int higher
                int len;
 
                /* For PCI<->PCI bridges or CardBus bridges, we go down */
-               class_code = get_property(node, "class-code", NULL);
+               class_code = of_get_property(node, "class-code", NULL);
                if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
                        (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
                        continue;
-               bus_range = get_property(node, "bus-range", &len);
+               bus_range = of_get_property(node, "bus-range", &len);
                if (bus_range != NULL && len > 2 * sizeof(int)) {
                        if (bus_range[1] > higher)
                                higher = bus_range[1];
@@ -77,7 +77,7 @@ static void __init fixup_bus_range(struct device_node *bridge)
                               bridge->full_name);
                return;
        }
-       bus_range = (int *)prop->value;
+       bus_range = prop->value;
        bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
 }
 
@@ -454,7 +454,7 @@ static int __init add_bridge(struct device_node *dev)
 
        DBG("Adding PCI host bridge %s\n", dev->full_name);
 
-       bus_range = get_property(dev, "bus-range", &len);
+       bus_range = of_get_property(dev, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
                dev->full_name);
index 82d3f9e28d7ce05a2170e19b730dea92d9662c83..2a30c5b2532e1e2e512d775fee618de75e356f00 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/initrd.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
-#include <linux/ide.h>
 #include <linux/pci.h>
 #include <linux/adb.h>
 #include <linux/cuda.h>
@@ -114,8 +113,8 @@ static void maple_restart(char *cmd)
                printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
                goto fail;
        }
-       maple_nvram_offset = get_property(sp, "restart-addr", NULL);
-       maple_nvram_command = get_property(sp, "restart-value", NULL);
+       maple_nvram_offset = of_get_property(sp, "restart-addr", NULL);
+       maple_nvram_command = of_get_property(sp, "restart-value", NULL);
        of_node_put(sp);
 
        /* send command */
@@ -141,8 +140,8 @@ static void maple_power_off(void)
                printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
                goto fail;
        }
-       maple_nvram_offset = get_property(sp, "power-off-addr", NULL);
-       maple_nvram_command = get_property(sp, "power-off-value", NULL);
+       maple_nvram_offset = of_get_property(sp, "power-off-addr", NULL);
+       maple_nvram_command = of_get_property(sp, "power-off-value", NULL);
        of_node_put(sp);
 
        /* send command */
@@ -249,8 +248,8 @@ static void __init maple_init_IRQ(void)
 
        /* Find address list in /platform-open-pic */
        root = of_find_node_by_path("/");
-       naddr = prom_n_addr_cells(root);
-       opprop = get_property(root, "platform-open-pic", &opplen);
+       naddr = of_n_addr_cells(root);
+       opprop = of_get_property(root, "platform-open-pic", &opplen);
        if (opprop != 0) {
                openpic_addr = of_read_number(opprop, naddr);
                has_isus = (opplen > naddr);
@@ -261,11 +260,11 @@ static void __init maple_init_IRQ(void)
        BUG_ON(openpic_addr == 0);
 
        /* Check for a big endian MPIC */
-       if (get_property(np, "big-endian", NULL) != NULL)
+       if (of_get_property(np, "big-endian", NULL) != NULL)
                flags |= MPIC_BIG_ENDIAN;
 
        /* XXX Maple specific bits */
-       flags |= MPIC_BROKEN_U3 | MPIC_WANTS_RESET;
+       flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET;
        /* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */
        flags |= MPIC_BIG_ENDIAN;
 
index 68dc529dfd2f6453df60a4181eea9b744790bf96..eb4dbc705b0654b771f4de03548084499185d854 100644 (file)
@@ -1,3 +1,15 @@
+config PPC_PASEMI
+       depends on PPC_MULTIPLATFORM && PPC64
+       bool "PA Semi SoC-based platforms"
+       default n
+       select MPIC
+       select PPC_UDBG_16550
+       select GENERIC_TBSYNC
+       select PPC_NATIVE
+       help
+         This option enables support for PA Semi's PWRficient line
+         of SoC processors, including PA6T-1682M
+
 menu "PA Semi PWRficient options"
        depends on PPC_PASEMI
 
@@ -7,4 +19,11 @@ config PPC_PASEMI_IOMMU
        help
          IOMMU support for PA6T-1682M
 
+config PPC_PASEMI_MDIO
+       depends on PHYLIB
+       tristate "MDIO support via GPIO"
+       default y
+       help
+         Driver for MDIO via GPIO on PWRficient platforms
+
 endmenu
index e657ccae90a9245f903b14c4faf78c1e6e65afb9..2cd2a4f26a48cfd29c2ab32f44e23fb28b836902 100644 (file)
@@ -1,2 +1,3 @@
 obj-y  += setup.o pci.o time.o idle.o powersave.o iommu.o
-
+obj-$(CONFIG_PPC_PASEMI_MDIO)  += gpio_mdio.o
+obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c
new file mode 100644 (file)
index 0000000..2a57d60
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2007 PA Semi, Inc
+ *
+ * Authors: Egor Martovetsky <egor@pasemi.com>
+ *         Olof Johansson <olof@lixom.net>
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on arch/powerpc/platforms/cell/cbe_cpufreq.c:
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/timer.h>
+
+#include <asm/hw_irq.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+
+#define SDCASR_REG             0x0100
+#define SDCASR_REG_STRIDE      0x1000
+#define SDCPWR_CFGA0_REG       0x0100
+#define SDCPWR_PWST0_REG       0x0000
+#define SDCPWR_GIZTIME_REG     0x0440
+
+/* SDCPWR_GIZTIME_REG fields */
+#define SDCPWR_GIZTIME_GR      0x80000000
+#define SDCPWR_GIZTIME_LONGLOCK        0x000000ff
+
+/* Offset of ASR registers from SDC base */
+#define SDCASR_OFFSET          0x120000
+
+static void __iomem *sdcpwr_mapbase;
+static void __iomem *sdcasr_mapbase;
+
+static DEFINE_MUTEX(pas_switch_mutex);
+
+/* Current astate, is used when waking up from power savings on
+ * one core, in case the other core has switched states during
+ * the idle time.
+ */
+static int current_astate;
+
+/* We support 5(A0-A4) power states excluding turbo(A5-A6) modes */
+static struct cpufreq_frequency_table pas_freqs[] = {
+       {0,     0},
+       {1,     0},
+       {2,     0},
+       {3,     0},
+       {4,     0},
+       {0,     CPUFREQ_TABLE_END},
+};
+
+static struct freq_attr *pas_cpu_freqs_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+/*
+ * hardware specific functions
+ */
+
+static int get_astate_freq(int astate)
+{
+       u32 ret;
+       ret = in_le32(sdcpwr_mapbase + SDCPWR_CFGA0_REG + (astate * 0x10));
+
+       return ret & 0x3f;
+}
+
+static int get_cur_astate(int cpu)
+{
+       u32 ret;
+
+       ret = in_le32(sdcpwr_mapbase + SDCPWR_PWST0_REG);
+       ret = (ret >> (cpu * 4)) & 0x7;
+
+       return ret;
+}
+
+static int get_gizmo_latency(void)
+{
+       u32 giztime, ret;
+
+       giztime = in_le32(sdcpwr_mapbase + SDCPWR_GIZTIME_REG);
+
+       /* just provide the upper bound */
+       if (giztime & SDCPWR_GIZTIME_GR)
+               ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 128000;
+       else
+               ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 1000;
+
+       return ret;
+}
+
+static void set_astate(int cpu, unsigned int astate)
+{
+       u64 flags;
+
+       /* Return if called before init has run */
+       if (unlikely(!sdcasr_mapbase))
+               return;
+
+       local_irq_save(flags);
+
+       out_le32(sdcasr_mapbase + SDCASR_REG + SDCASR_REG_STRIDE*cpu, astate);
+
+       local_irq_restore(flags);
+}
+
+void restore_astate(int cpu)
+{
+       set_astate(cpu, current_astate);
+}
+
+/*
+ * cpufreq functions
+ */
+
+static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+       const u32 *max_freqp;
+       u32 max_freq;
+       int i, cur_astate;
+       struct resource res;
+       struct device_node *cpu, *dn;
+       int err = -ENODEV;
+
+       cpu = of_get_cpu_node(policy->cpu, NULL);
+
+       if (!cpu)
+               goto out;
+
+       dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc");
+       if (!dn)
+               goto out;
+       err = of_address_to_resource(dn, 0, &res);
+       of_node_put(dn);
+       if (err)
+               goto out;
+       sdcasr_mapbase = ioremap(res.start + SDCASR_OFFSET, 0x2000);
+       if (!sdcasr_mapbase) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo");
+       if (!dn) {
+               err = -ENODEV;
+               goto out_unmap_sdcasr;
+       }
+       err = of_address_to_resource(dn, 0, &res);
+       of_node_put(dn);
+       if (err)
+               goto out_unmap_sdcasr;
+       sdcpwr_mapbase = ioremap(res.start, 0x1000);
+       if (!sdcpwr_mapbase) {
+               err = -EINVAL;
+               goto out_unmap_sdcasr;
+       }
+
+       pr_debug("init cpufreq on CPU %d\n", policy->cpu);
+
+       max_freqp = of_get_property(cpu, "clock-frequency", NULL);
+       if (!max_freqp) {
+               err = -EINVAL;
+               goto out_unmap_sdcpwr;
+       }
+
+       /* we need the freq in kHz */
+       max_freq = *max_freqp / 1000;
+
+       pr_debug("max clock-frequency is at %u kHz\n", max_freq);
+       pr_debug("initializing frequency table\n");
+
+       /* initialize frequency table */
+       for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
+               pas_freqs[i].frequency = get_astate_freq(pas_freqs[i].index) * 100000;
+               pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
+       }
+
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+       policy->cpuinfo.transition_latency = get_gizmo_latency();
+
+       cur_astate = get_cur_astate(policy->cpu);
+       pr_debug("current astate is at %d\n",cur_astate);
+
+       policy->cur = pas_freqs[cur_astate].frequency;
+       policy->cpus = cpu_online_map;
+
+       cpufreq_frequency_table_get_attr(pas_freqs, policy->cpu);
+
+       /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max
+        * are set correctly
+        */
+       return cpufreq_frequency_table_cpuinfo(policy, pas_freqs);
+
+out_unmap_sdcpwr:
+       iounmap(sdcpwr_mapbase);
+
+out_unmap_sdcasr:
+       iounmap(sdcasr_mapbase);
+out:
+       return err;
+}
+
+static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+       if (sdcasr_mapbase)
+               iounmap(sdcasr_mapbase);
+       if (sdcpwr_mapbase)
+               iounmap(sdcpwr_mapbase);
+
+       cpufreq_frequency_table_put_attr(policy->cpu);
+       return 0;
+}
+
+static int pas_cpufreq_verify(struct cpufreq_policy *policy)
+{
+       return cpufreq_frequency_table_verify(policy, pas_freqs);
+}
+
+static int pas_cpufreq_target(struct cpufreq_policy *policy,
+                             unsigned int target_freq,
+                             unsigned int relation)
+{
+       struct cpufreq_freqs freqs;
+       int pas_astate_new;
+       int i;
+
+       cpufreq_frequency_table_target(policy,
+                                      pas_freqs,
+                                      target_freq,
+                                      relation,
+                                      &pas_astate_new);
+
+       freqs.old = policy->cur;
+       freqs.new = pas_freqs[pas_astate_new].frequency;
+       freqs.cpu = policy->cpu;
+
+       mutex_lock(&pas_switch_mutex);
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+       pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
+                policy->cpu,
+                pas_freqs[pas_astate_new].frequency,
+                pas_freqs[pas_astate_new].index);
+
+       current_astate = pas_astate_new;
+
+       for_each_online_cpu(i)
+               set_astate(i, pas_astate_new);
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+       mutex_unlock(&pas_switch_mutex);
+
+       return 0;
+}
+
+static struct cpufreq_driver pas_cpufreq_driver = {
+       .name           = "pas-cpufreq",
+       .owner          = THIS_MODULE,
+       .flags          = CPUFREQ_CONST_LOOPS,
+       .init           = pas_cpufreq_cpu_init,
+       .exit           = pas_cpufreq_cpu_exit,
+       .verify         = pas_cpufreq_verify,
+       .target         = pas_cpufreq_target,
+       .attr           = pas_cpu_freqs_attr,
+};
+
+/*
+ * module init and destoy
+ */
+
+static int __init pas_cpufreq_init(void)
+{
+       if (!machine_is_compatible("PA6T-1682M"))
+               return -ENODEV;
+
+       return cpufreq_register_driver(&pas_cpufreq_driver);
+}
+
+static void __exit pas_cpufreq_exit(void)
+{
+       cpufreq_unregister_driver(&pas_cpufreq_driver);
+}
+
+module_init(pas_cpufreq_init);
+module_exit(pas_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>, Olof Johansson <olof@lixom.net>");
diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c
new file mode 100644 (file)
index 0000000..c91a335
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Olof Johansson, PA Semi
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on drivers/net/fs_enet/mii-bitbang.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <asm/of_platform.h>
+
+#define DELAY 1
+
+static void __iomem *gpio_regs;
+
+struct gpio_priv {
+       int mdc_pin;
+       int mdio_pin;
+};
+
+#define MDC_PIN(bus)   (((struct gpio_priv *)bus->priv)->mdc_pin)
+#define MDIO_PIN(bus)  (((struct gpio_priv *)bus->priv)->mdio_pin)
+
+static inline void mdio_lo(struct mii_bus *bus)
+{
+       out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus));
+}
+
+static inline void mdio_hi(struct mii_bus *bus)
+{
+       out_le32(gpio_regs, 1 << MDIO_PIN(bus));
+}
+
+static inline void mdc_lo(struct mii_bus *bus)
+{
+       out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus));
+}
+
+static inline void mdc_hi(struct mii_bus *bus)
+{
+       out_le32(gpio_regs, 1 << MDC_PIN(bus));
+}
+
+static inline void mdio_active(struct mii_bus *bus)
+{
+       out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus)));
+}
+
+static inline void mdio_tristate(struct mii_bus *bus)
+{
+       out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus)));
+}
+
+static inline int mdio_read(struct mii_bus *bus)
+{
+       return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus)));
+}
+
+static void clock_out(struct mii_bus *bus, int bit)
+{
+       if (bit)
+               mdio_hi(bus);
+       else
+               mdio_lo(bus);
+       udelay(DELAY);
+       mdc_hi(bus);
+       udelay(DELAY);
+       mdc_lo(bus);
+}
+
+/* Utility to send the preamble, address, and register (common to read and write). */
+static void bitbang_pre(struct mii_bus *bus, int read, u8 addr, u8 reg)
+{
+       int i;
+
+       /* CFE uses a really long preamble (40 bits). We'll do the same. */
+       mdio_active(bus);
+       for (i = 0; i < 40; i++) {
+               clock_out(bus, 1);
+       }
+
+       /* send the start bit (01) and the read opcode (10) or write (10) */
+       clock_out(bus, 0);
+       clock_out(bus, 1);
+
+       clock_out(bus, read);
+       clock_out(bus, !read);
+
+       /* send the PHY address */
+       for (i = 0; i < 5; i++) {
+               clock_out(bus, (addr & 0x10) != 0);
+               addr <<= 1;
+       }
+
+       /* send the register address */
+       for (i = 0; i < 5; i++) {
+               clock_out(bus, (reg & 0x10) != 0);
+               reg <<= 1;
+       }
+}
+
+static int gpio_mdio_read(struct mii_bus *bus, int phy_id, int location)
+{
+       u16 rdreg;
+       int ret, i;
+       u8 addr = phy_id & 0xff;
+       u8 reg = location & 0xff;
+
+       bitbang_pre(bus, 1, addr, reg);
+
+       /* tri-state our MDIO I/O pin so we can read */
+       mdio_tristate(bus);
+       udelay(DELAY);
+       mdc_hi(bus);
+       udelay(DELAY);
+       mdc_lo(bus);
+
+       /* read 16 bits of register data, MSB first */
+       rdreg = 0;
+       for (i = 0; i < 16; i++) {
+               mdc_lo(bus);
+               udelay(DELAY);
+               mdc_hi(bus);
+               udelay(DELAY);
+               mdc_lo(bus);
+               udelay(DELAY);
+               rdreg <<= 1;
+               rdreg |= mdio_read(bus);
+       }
+
+       mdc_hi(bus);
+       udelay(DELAY);
+       mdc_lo(bus);
+       udelay(DELAY);
+
+       ret = rdreg;
+
+       return ret;
+}
+
+static int gpio_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+{
+       int i;
+
+       u8 addr = phy_id & 0xff;
+       u8 reg = location & 0xff;
+       u16 value = val & 0xffff;
+
+       bitbang_pre(bus, 0, addr, reg);
+
+       /* send the turnaround (10) */
+       mdc_lo(bus);
+       mdio_hi(bus);
+       udelay(DELAY);
+       mdc_hi(bus);
+       udelay(DELAY);
+       mdc_lo(bus);
+       mdio_lo(bus);
+       udelay(DELAY);
+       mdc_hi(bus);
+       udelay(DELAY);
+
+       /* write 16 bits of register data, MSB first */
+       for (i = 0; i < 16; i++) {
+               mdc_lo(bus);
+               if (value & 0x8000)
+                       mdio_hi(bus);
+               else
+                       mdio_lo(bus);
+               udelay(DELAY);
+               mdc_hi(bus);
+               udelay(DELAY);
+               value <<= 1;
+       }
+
+       /*
+        * Tri-state the MDIO line.
+        */
+       mdio_tristate(bus);
+       mdc_lo(bus);
+       udelay(DELAY);
+       mdc_hi(bus);
+       udelay(DELAY);
+       return 0;
+}
+
+static int gpio_mdio_reset(struct mii_bus *bus)
+{
+       /*nothing here - dunno how to reset it*/
+       return 0;
+}
+
+
+static int __devinit gpio_mdio_probe(struct of_device *ofdev,
+                                    const struct of_device_id *match)
+{
+       struct device *dev = &ofdev->dev;
+       struct device_node *np = ofdev->node;
+       struct device_node *gpio_np;
+       struct mii_bus *new_bus;
+       struct resource res;
+       struct gpio_priv *priv;
+       const unsigned int *prop;
+       int err = 0;
+       int i;
+
+       gpio_np = of_find_compatible_node(NULL, "gpio", "1682m-gpio");
+
+       if (!gpio_np)
+               return -ENODEV;
+
+       err = of_address_to_resource(gpio_np, 0, &res);
+       of_node_put(gpio_np);
+
+       if (err)
+               return -EINVAL;
+
+       if (!gpio_regs)
+               gpio_regs = ioremap(res.start, 0x100);
+
+       if (!gpio_regs)
+               return -EPERM;
+
+       priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+       if (new_bus == NULL)
+               return -ENOMEM;
+
+       new_bus->name = "pasemi gpio mdio bus",
+       new_bus->read = &gpio_mdio_read,
+       new_bus->write = &gpio_mdio_write,
+       new_bus->reset = &gpio_mdio_reset,
+
+       prop = of_get_property(np, "reg", NULL);
+       new_bus->id = *prop;
+       new_bus->priv = priv;
+
+       new_bus->phy_mask = 0;
+
+       new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+       for(i = 0; i < PHY_MAX_ADDR; ++i)
+               new_bus->irq[i] = irq_create_mapping(NULL, 10);
+
+
+       prop = of_get_property(np, "mdc-pin", NULL);
+       priv->mdc_pin = *prop;
+
+       prop = of_get_property(np, "mdio-pin", NULL);
+       priv->mdio_pin = *prop;
+
+       new_bus->dev = dev;
+       dev_set_drvdata(dev, new_bus);
+
+       err = mdiobus_register(new_bus);
+
+       if (0 != err) {
+               printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n",
+                               new_bus->name, err);
+               goto bus_register_fail;
+       }
+
+       return 0;
+
+bus_register_fail:
+       kfree(new_bus);
+
+       return err;
+}
+
+
+static int gpio_mdio_remove(struct of_device *dev)
+{
+       struct mii_bus *bus = dev_get_drvdata(&dev->dev);
+
+       mdiobus_unregister(bus);
+
+       dev_set_drvdata(&dev->dev, NULL);
+
+       kfree(bus->priv);
+       bus->priv = NULL;
+       kfree(bus);
+
+       return 0;
+}
+
+static struct of_device_id gpio_mdio_match[] =
+{
+       {
+               .compatible      = "gpio-mdio",
+       },
+       {},
+};
+
+static struct of_platform_driver gpio_mdio_driver =
+{
+       .name           = "gpio-mdio-bitbang",
+       .match_table    = gpio_mdio_match,
+       .probe          = gpio_mdio_probe,
+       .remove         = gpio_mdio_remove,
+};
+
+int gpio_mdio_init(void)
+{
+       return of_register_platform_driver(&gpio_mdio_driver);
+}
+
+void gpio_mdio_exit(void)
+{
+       of_unregister_platform_driver(&gpio_mdio_driver);
+}
+device_initcall(gpio_mdio_init);
+
index 1ca3ff3815913a400b48a9e9cc19c8298a2f4313..5985ce0c5c489612288d62c722d1b088979489df 100644 (file)
@@ -61,6 +61,10 @@ static int pasemi_system_reset_exception(struct pt_regs *regs)
                /* do system reset */
                return 0;
        }
+
+       /* Set higher astate since we come out of power savings at 0 */
+       restore_astate(hard_smp_processor_id());
+
        /* everything handled */
        regs->msr |= MSR_RI;
        return 1;
@@ -68,6 +72,11 @@ static int pasemi_system_reset_exception(struct pt_regs *regs)
 
 void __init pasemi_idle_init(void)
 {
+#ifndef CONFIG_PPC_PASEMI_CPUFREQ
+       printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n");
+       current_mode = 0;
+#endif
+
        ppc_md.system_reset_exception = pasemi_system_reset_exception;
        ppc_md.power_save = modes[current_mode].entry;
        printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name);
index 71dbf1a56e13dc568c3e91cb4d015507151fcbe4..95fa6a7d15ee4d11aab9e8543d8ac59d11f4c1f7 100644 (file)
@@ -249,13 +249,13 @@ void iommu_init_early_pasemi(void)
        iommu_off = 1;
 #else
        iommu_off = of_chosen &&
-                       get_property(of_chosen, "linux,iommu-off", NULL);
+                       of_get_property(of_chosen, "linux,iommu-off", NULL);
 #endif
        if (iommu_off) {
                /* Direct I/O, IOMMU off */
                ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_null;
                ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_null;
-               pci_dma_ops = &dma_direct_ops;
+               set_pci_dma_ops(&dma_direct_ops);
 
                return;
        }
@@ -266,7 +266,7 @@ void iommu_init_early_pasemi(void)
        ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi;
        ppc_md.tce_build = iobmap_build;
        ppc_md.tce_free  = iobmap_free;
-       pci_dma_ops = &dma_iommu_ops;
+       set_pci_dma_ops(&dma_iommu_ops);
 }
 
 void __init alloc_iobmap_l2(void)
index 2d3927e6edb04c89fcb0c564bfa7078132c440c5..be84954976116e6000bcdf44eb2d4461edee693c 100644 (file)
@@ -14,6 +14,14 @@ extern void __init pasemi_idle_init(void);
 extern void idle_spin(void);
 extern void idle_doze(void);
 
+/* Restore astate to last set */
+#ifdef CONFIG_PPC_PASEMI_CPUFREQ
+extern void restore_astate(int cpu);
+#else
+static inline void restore_astate(int cpu)
+{
+}
+#endif
 
 
 #endif /* _PASEMI_PASEMI_H */
index 7ecb2ba24db9cd26c0b0c80fe13c61a57caa5641..056243da360b6dbce76218cd334bebfd37aa8214 100644 (file)
 
 #define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))
 
-#define CONFIG_OFFSET_VALID(off) ((off) < 4096)
+static inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset)
+{
+       /* Device 0 Function 0 is special: It's config space spans function 1 as
+        * well, so allow larger offset. It's really a two-function device but the
+        * second function does not probe.
+        */
+       if (bus == 0 && devfn == 0)
+               return offset < 8192;
+       else
+               return offset < 4096;
+}
 
 static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose,
                                       u8 bus, u8 devfn, int offset)
@@ -51,7 +61,7 @@ static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn,
        if (!hose)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       if (!CONFIG_OFFSET_VALID(offset))
+       if (!pa_pxp_offset_valid(bus->number, devfn, offset))
                return PCIBIOS_BAD_REGISTER_NUMBER;
 
        addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
@@ -85,7 +95,7 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn,
        if (!hose)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       if (!CONFIG_OFFSET_VALID(offset))
+       if (!pa_pxp_offset_valid(bus->number, devfn, offset))
                return PCIBIOS_BAD_REGISTER_NUMBER;
 
        addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
index 449cf1a08291b76f6dcce289e755bd99c34ad02f..f88f0ec4c8cb2d6ec042021e67a8d3e07c8064a3 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/mpic.h>
 #include <asm/smp.h>
 #include <asm/time.h>
+#include <asm/of_platform.h>
 
 #include "pasemi.h"
 
@@ -101,12 +102,6 @@ void __init pas_setup_arch(void)
        pasemi_idle_init();
 }
 
-/* No legacy IO on our parts */
-static int pas_check_legacy_ioport(unsigned int baseport)
-{
-       return -ENODEV;
-}
-
 static __init void pas_init_IRQ(void)
 {
        struct device_node *np;
@@ -136,8 +131,8 @@ static __init void pas_init_IRQ(void)
 
        /* Find address list in /platform-open-pic */
        root = of_find_node_by_path("/");
-       naddr = prom_n_addr_cells(root);
-       opprop = get_property(root, "platform-open-pic", &opplen);
+       naddr = of_n_addr_cells(root);
+       opprop = of_get_property(root, "platform-open-pic", &opplen);
        if (!opprop) {
                printk(KERN_ERR "No platform-open-pic property.\n");
                of_node_put(root);
@@ -147,7 +142,7 @@ static __init void pas_init_IRQ(void)
        printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
 
        mpic = mpic_alloc(mpic_node, openpic_addr,
-                         MPIC_PRIMARY|MPIC_LARGE_VECTORS,
+                         MPIC_PRIMARY|MPIC_LARGE_VECTORS|MPIC_WANTS_RESET,
                          0, 0, " PAS-OPIC  ");
        BUG_ON(!mpic);
 
@@ -209,6 +204,20 @@ static void __init pas_init_early(void)
        iommu_init_early_pasemi();
 }
 
+static struct of_device_id pasemi_bus_ids[] = {
+       { .type = "sdc", },
+       {},
+};
+
+static int __init pasemi_publish_devices(void)
+{
+       /* Publish OF platform devices for southbridge IOs */
+       of_platform_bus_probe(NULL, pasemi_bus_ids, NULL);
+
+       return 0;
+}
+device_initcall(pasemi_publish_devices);
+
 
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
@@ -237,7 +246,6 @@ define_machine(pas) {
        .restart                = pas_restart,
        .get_boot_time          = pas_get_boot_time,
        .calibrate_decr         = generic_calibrate_decr,
-       .check_legacy_ioport    = pas_check_legacy_ioport,
        .progress               = pas_progress,
        .machine_check_exception = pas_machine_check_handler,
        .pci_irq_fixup          = pas_pci_irq_fixup,
diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig
new file mode 100644 (file)
index 0000000..5b7afe5
--- /dev/null
@@ -0,0 +1,20 @@
+config PPC_PMAC
+       bool "Apple PowerMac based machines"
+       depends on PPC_MULTIPLATFORM
+       select MPIC
+       select PPC_INDIRECT_PCI if PPC32
+       select PPC_MPC106 if PPC32
+       select PPC_NATIVE
+       default y
+
+config PPC_PMAC64
+       bool
+       depends on PPC_PMAC && POWER4
+       select MPIC
+       select U3_DART
+       select MPIC_U3_HT_IRQS
+       select GENERIC_TBSYNC
+       select PPC_970_NAP
+       default y
+
+
index de7440e62cc4fb05f0bc7b58e0d5b0ad3e81ff95..d679964ae2ab28321589c9194de481a7ba0d2bea 100644 (file)
@@ -56,13 +56,16 @@ struct backlight_device *pmac_backlight;
 
 int pmac_has_backlight_type(const char *type)
 {
-       struct device_node* bk_node = find_devices("backlight");
+       struct device_node* bk_node = of_find_node_by_name(NULL, "backlight");
 
        if (bk_node) {
-               const char *prop = get_property(bk_node,
+               const char *prop = of_get_property(bk_node,
                                "backlight-control", NULL);
-               if (prop && strncmp(prop, type, strlen(type)) == 0)
+               if (prop && strncmp(prop, type, strlen(type)) == 0) {
+                       of_node_put(bk_node);
                        return 1;
+               }
+               of_node_put(bk_node);
        }
 
        return 0;
index c2b6b4134f6849c28e8871edde719269fa0ab8a0..8943a9456bb7088b64a94c07ce0f8519b85233a8 100644 (file)
@@ -421,7 +421,7 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
 static u32 read_gpio(struct device_node *np)
 {
-       const u32 *reg = get_property(np, "reg", NULL);
+       const u32 *reg = of_get_property(np, "reg", NULL);
        u32 offset;
 
        if (reg == NULL)
@@ -521,13 +521,14 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
                int lenp, rc;
                const u32 *freqs, *ratio;
 
-               freqs = get_property(cpunode, "bus-frequencies", &lenp);
+               freqs = of_get_property(cpunode, "bus-frequencies", &lenp);
                lenp /= sizeof(u32);
                if (freqs == NULL || lenp != 2) {
                        printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n");
                        return 1;
                }
-               ratio = get_property(cpunode, "processor-to-bus-ratio*2", NULL);
+               ratio = of_get_property(cpunode, "processor-to-bus-ratio*2",
+                                               NULL);
                if (ratio == NULL) {
                        printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n");
                        return 1;
@@ -562,7 +563,7 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
        /* If we use the PMU, look for the min & max frequencies in the
         * device-tree
         */
-       value = get_property(cpunode, "min-clock-frequency", NULL);
+       value = of_get_property(cpunode, "min-clock-frequency", NULL);
        if (!value)
                return 1;
        low_freq = (*value) / 1000;
@@ -571,7 +572,7 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
        if (low_freq < 100000)
                low_freq *= 10;
 
-       value = get_property(cpunode, "max-clock-frequency", NULL);
+       value = of_get_property(cpunode, "max-clock-frequency", NULL);
        if (!value)
                return 1;
        hi_freq = (*value) / 1000;
@@ -585,7 +586,7 @@ static int pmac_cpufreq_init_7447A(struct device_node *cpunode)
 {
        struct device_node *volt_gpio_np;
 
-       if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+       if (of_get_property(cpunode, "dynamic-power-step", NULL) == NULL)
                return 1;
 
        volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
@@ -614,11 +615,11 @@ static int pmac_cpufreq_init_750FX(struct device_node *cpunode)
        u32 pvr;
        const u32 *value;
 
-       if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+       if (of_get_property(cpunode, "dynamic-power-step", NULL) == NULL)
                return 1;
 
        hi_freq = cur_freq;
-       value = get_property(cpunode, "reduced-clock-frequency", NULL);
+       value = of_get_property(cpunode, "reduced-clock-frequency", NULL);
        if (!value)
                return 1;
        low_freq = (*value) / 1000;
@@ -657,19 +658,19 @@ static int __init pmac_cpufreq_setup(void)
                return 0;
 
        /* Assume only one CPU */
-       cpunode = find_type_devices("cpu");
+       cpunode = of_find_node_by_type(NULL, "cpu");
        if (!cpunode)
                goto out;
 
        /* Get current cpu clock freq */
-       value = get_property(cpunode, "clock-frequency", NULL);
+       value = of_get_property(cpunode, "clock-frequency", NULL);
        if (!value)
                goto out;
        cur_freq = (*value) / 1000;
 
        /*  Check for 7447A based MacRISC3 */
        if (machine_is_compatible("MacRISC3") &&
-           get_property(cpunode, "dynamic-power-step", NULL) &&
+           of_get_property(cpunode, "dynamic-power-step", NULL) &&
            PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
                pmac_cpufreq_init_7447A(cpunode);
        /* Check for other MacRISC3 machines */
@@ -707,6 +708,7 @@ static int __init pmac_cpufreq_setup(void)
        else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000)
                pmac_cpufreq_init_750FX(cpunode);
 out:
+       of_node_put(cpunode);
        if (set_speed_proc == NULL)
                return -ENODEV;
 
index 9d22361a26d6012a93393bfb664803aa6f73785a..567d5523b6909e294f4fd204890848e940265a2e 100644 (file)
@@ -410,7 +410,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
        /* Get first CPU node */
        for (cpunode = NULL;
             (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
-               const u32 *reg = get_property(cpunode, "reg", NULL);
+               const u32 *reg = of_get_property(cpunode, "reg", NULL);
                if (reg == NULL || (*reg) != 0)
                        continue;
                if (!strcmp(cpunode->type, "cpu"))
@@ -422,7 +422,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
        }
 
        /* Check 970FX for now */
-       valp = get_property(cpunode, "cpu-version", NULL);
+       valp = of_get_property(cpunode, "cpu-version", NULL);
        if (!valp) {
                DBG("No cpu-version property !\n");
                goto bail_noprops;
@@ -434,7 +434,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
        }
 
        /* Look for the powertune data in the device-tree */
-       g5_pmode_data = get_property(cpunode, "power-mode-data",&psize);
+       g5_pmode_data = of_get_property(cpunode, "power-mode-data",&psize);
        if (!g5_pmode_data) {
                DBG("No power-mode-data !\n");
                goto bail_noprops;
@@ -493,7 +493,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
         * half freq in this version. So far, I haven't yet seen a machine
         * supporting anything else.
         */
-       valp = get_property(cpunode, "clock-frequency", NULL);
+       valp = of_get_property(cpunode, "clock-frequency", NULL);
        if (!valp)
                return -ENODEV;
        max_freq = (*valp)/1000;
@@ -563,7 +563,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
        /* Lookup the cpuid eeprom node */
         cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
        if (cpuid != NULL)
-               eeprom = get_property(cpuid, "cpuid", NULL);
+               eeprom = of_get_property(cpuid, "cpuid", NULL);
        if (eeprom == NULL) {
                printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n");
                rc = -ENODEV;
@@ -573,13 +573,13 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
        /* Lookup the i2c hwclock */
        for (hwclock = NULL;
             (hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){
-               const char *loc = get_property(hwclock,
+               const char *loc = of_get_property(hwclock,
                                "hwctrl-location", NULL);
                if (loc == NULL)
                        continue;
                if (strcmp(loc, "CPU CLOCK"))
                        continue;
-               if (!get_property(hwclock, "platform-get-frequency", NULL))
+               if (!of_get_property(hwclock, "platform-get-frequency", NULL))
                        continue;
                break;
        }
@@ -638,7 +638,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
         */
 
        /* Get max frequency from device-tree */
-       valp = get_property(cpunode, "clock-frequency", NULL);
+       valp = of_get_property(cpunode, "clock-frequency", NULL);
        if (!valp) {
                printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n");
                rc = -ENODEV;
index 24cc50c1774ad5131429ed27caef9e7add3ed906..52cfdd86c92847767538793721199989060c00f5 100644 (file)
@@ -1044,6 +1044,7 @@ core99_reset_cpu(struct device_node *node, long param, long value)
        unsigned long flags;
        struct macio_chip *macio;
        struct device_node *np;
+       struct device_node *cpus;
        const int dflt_reset_lines[] = {        KL_GPIO_RESET_CPU0,
                                                KL_GPIO_RESET_CPU1,
                                                KL_GPIO_RESET_CPU2,
@@ -1053,12 +1054,12 @@ core99_reset_cpu(struct device_node *node, long param, long value)
        if (macio->type != macio_keylargo)
                return -ENODEV;
 
-       np = find_path_device("/cpus");
-       if (np == NULL)
+       cpus = of_find_node_by_path("/cpus");
+       if (cpus == NULL)
                return -ENODEV;
-       for (np = np->child; np != NULL; np = np->sibling) {
-               const u32 *num = get_property(np, "reg", NULL);
-               const u32 *rst = get_property(np, "soft-reset", NULL);
+       for (np = cpus->child; np != NULL; np = np->sibling) {
+               const u32 *num = of_get_property(np, "reg", NULL);
+               const u32 *rst = of_get_property(np, "soft-reset", NULL);
                if (num == NULL || rst == NULL)
                        continue;
                if (param == *num) {
@@ -1066,6 +1067,7 @@ core99_reset_cpu(struct device_node *node, long param, long value)
                        break;
                }
        }
+       of_node_put(cpus);
        if (np == NULL || reset_io == 0)
                reset_io = dflt_reset_lines[param];
 
@@ -1095,7 +1097,7 @@ core99_usb_enable(struct device_node *node, long param, long value)
            macio->type != macio_intrepid)
                return -ENODEV;
 
-       prop = get_property(node, "AAPL,clock-id", NULL);
+       prop = of_get_property(node, "AAPL,clock-id", NULL);
        if (!prop)
                return -ENODEV;
        if (strncmp(prop, "usb0u048", 8) == 0)
@@ -1497,17 +1499,18 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
        unsigned long flags;
        struct macio_chip *macio;
        struct device_node *np;
+       struct device_node *cpus;
 
        macio = &macio_chips[0];
        if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
                return -ENODEV;
 
-       np = find_path_device("/cpus");
-       if (np == NULL)
+       cpus = of_find_node_by_path("/cpus");
+       if (cpus == NULL)
                return -ENODEV;
-       for (np = np->child; np != NULL; np = np->sibling) {
-               const u32 *num = get_property(np, "reg", NULL);
-               const u32 *rst = get_property(np, "soft-reset", NULL);
+       for (np = cpus->child; np != NULL; np = np->sibling) {
+               const u32 *num = of_get_property(np, "reg", NULL);
+               const u32 *rst = of_get_property(np, "soft-reset", NULL);
                if (num == NULL || rst == NULL)
                        continue;
                if (param == *num) {
@@ -1515,6 +1518,7 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
                        break;
                }
        }
+       of_node_put(cpus);
        if (np == NULL || reset_io == 0)
                return -ENODEV;
 
@@ -2404,14 +2408,15 @@ static int __init probe_motherboard(void)
        struct macio_chip *macio = &macio_chips[0];
        const char *model = NULL;
        struct device_node *dt;
+       int ret = 0;
 
        /* Lookup known motherboard type in device-tree. First try an
         * exact match on the "model" property, then try a "compatible"
         * match is none is found.
         */
-       dt = find_devices("device-tree");
+       dt = of_find_node_by_name(NULL, "device-tree");
        if (dt != NULL)
-               model = get_property(dt, "model", NULL);
+               model = of_get_property(dt, "model", NULL);
        for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
            if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
                pmac_mb = pmac_mb_defs[i];
@@ -2474,15 +2479,18 @@ static int __init probe_motherboard(void)
                break;
 #endif /* CONFIG_POWER4 */
        default:
-               return -ENODEV;
+               ret = -ENODEV;
+               goto done;
        }
 found:
 #ifndef CONFIG_POWER4
        /* Fixup Hooper vs. Comet */
        if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
                u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4);
-               if (!mach_id_ptr)
-                       return -ENODEV;
+               if (!mach_id_ptr) {
+                       ret = -ENODEV;
+                       goto done;
+               }
                /* Here, I used to disable the media-bay on comet. It
                 * appears this is wrong, the floppy connector is actually
                 * a kind of media-bay and works with the current driver.
@@ -2499,18 +2507,26 @@ found:
         * that all Apple OF revs did it properly, I do it the paranoid way.
         */
        while (uninorth_base && uninorth_rev > 3) {
-               struct device_node *np = find_path_device("/cpus");
-               if (!np || !np->child) {
+               struct device_node *cpus = of_find_node_by_path("/cpus");
+               struct device_node *np;
+
+               if (!cpus || !cpus->child) {
                        printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
+                       of_node_put(cpus);
                        break;
                }
-               np = np->child;
+               np = cpus->child;
                /* Nap mode not supported on SMP */
-               if (np->sibling)
+               if (np->sibling) {
+                       of_node_put(cpus);
                        break;
+               }
                /* Nap mode not supported if flush-on-lock property is present */
-               if (get_property(np, "flush-on-lock", NULL))
+               if (of_get_property(np, "flush-on-lock", NULL)) {
+                       of_node_put(cpus);
                        break;
+               }
+               of_node_put(cpus);
                powersave_nap = 1;
                printk(KERN_DEBUG "Processor NAP mode on idle enabled.\n");
                break;
@@ -2532,7 +2548,9 @@ found:
 
 
        printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
-       return 0;
+done:
+       of_node_put(dt);
+       return ret;
 }
 
 /* Initialize the Core99 UniNorth host bridge and memory controller
@@ -2558,7 +2576,7 @@ static void __init probe_uninorth(void)
        if (uninorth_node == NULL)
                return;
 
-       addrp = get_property(uninorth_node, "reg", NULL);
+       addrp = of_get_property(uninorth_node, "reg", NULL);
        if (addrp == NULL)
                return;
        address = of_translate_address(uninorth_node, addrp);
@@ -2642,7 +2660,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
                return;
        }
        if (type == macio_keylargo || type == macio_keylargo2) {
-               const u32 *did = get_property(node, "device-id", NULL);
+               const u32 *did = of_get_property(node, "device-id", NULL);
                if (*did == 0x00000025)
                        type = macio_pangea;
                if (*did == 0x0000003e)
@@ -2655,7 +2673,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
        macio_chips[i].base     = base;
        macio_chips[i].flags    = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
        macio_chips[i].name     = macio_names[type];
-       revp = get_property(node, "revision-id", NULL);
+       revp = of_get_property(node, "revision-id", NULL);
        if (revp)
                macio_chips[i].rev = *revp;
        printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
@@ -2706,8 +2724,8 @@ initial_serial_shutdown(struct device_node *np)
        int port_type = PMAC_SCC_ASYNC;
        int modem = 0;
 
-       slots = get_property(np, "slot-names", &len);
-       conn = get_property(np, "AAPL,connector", &len);
+       slots = of_get_property(np, "slot-names", &len);
+       conn = of_get_property(np, "AAPL,connector", &len);
        if (conn && (strcmp(conn, "infrared") == 0))
                port_type = PMAC_SCC_IRDA;
        else if (device_is_compatible(np, "cobalt"))
@@ -2735,12 +2753,14 @@ set_initial_features(void)
         * differenciate them all and since that hack was there for a long
         * time, I'll keep it around
         */
-       if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
+       if (macio_chips[0].type == macio_ohare) {
                struct macio_chip *macio = &macio_chips[0];
-               MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
-       } else if (macio_chips[0].type == macio_ohare) {
-               struct macio_chip *macio = &macio_chips[0];
-               MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+               np = of_find_node_by_name(NULL, "via-pmu");
+               if (np)
+                       MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+               else
+                       MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
+               of_node_put(np);
        } else if (macio_chips[1].type == macio_ohare) {
                struct macio_chip *macio = &macio_chips[1];
                MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
@@ -2833,14 +2853,13 @@ set_initial_features(void)
                }
 
                /* Switch airport off */
-               np = find_devices("radio");
-               while(np) {
+               for_each_node_by_name(np, "radio") {
                        if (np && np->parent == macio_chips[0].of_node) {
                                macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
                                core99_airport_enable(np, 0, 0);
                        }
-                       np = np->next;
                }
+               of_node_put(np);
        }
 
        /* On all machines that support sound PM, switch sound off */
@@ -2860,16 +2879,12 @@ set_initial_features(void)
 #endif /* CONFIG_POWER4 */
 
        /* On all machines, switch modem & serial ports off */
-       np = find_devices("ch-a");
-       while(np) {
+       for_each_node_by_name(np, "ch-a")
                initial_serial_shutdown(np);
-               np = np->next;
-       }
-       np = find_devices("ch-b");
-       while(np) {
+       of_node_put(np);
+       for_each_node_by_name(np, "ch-b")
                initial_serial_shutdown(np);
-               np = np->next;
-       }
+       of_node_put(np);
 }
 
 void __init
index bfc4829162f1f2aba47aeca9b93df92ae3df01d0..5430e146b3e91c5aa603ac258935b485f8599b63 100644 (file)
@@ -491,7 +491,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
         * on all i2c keywest nodes so far ... we would have to fallback
         * to macio parsing if that wasn't the case
         */
-       addrp = get_property(np, "AAPL,address", NULL);
+       addrp = of_get_property(np, "AAPL,address", NULL);
        if (addrp == NULL) {
                printk(KERN_ERR "low_i2c: Can't find address for %s\n",
                       np->full_name);
@@ -505,13 +505,13 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
        host->timeout_timer.function = kw_i2c_timeout;
        host->timeout_timer.data = (unsigned long)host;
 
-       psteps = get_property(np, "AAPL,address-step", NULL);
+       psteps = of_get_property(np, "AAPL,address-step", NULL);
        steps = psteps ? (*psteps) : 0x10;
        for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
                steps >>= 1;
        /* Select interface rate */
        host->speed = KW_I2C_MODE_25KHZ;
-       prate = get_property(np, "AAPL,i2c-rate", NULL);
+       prate = of_get_property(np, "AAPL,i2c-rate", NULL);
        if (prate) switch(*prate) {
        case 100:
                host->speed = KW_I2C_MODE_100KHZ;
@@ -619,7 +619,7 @@ static void __init kw_i2c_probe(void)
                } else {
                        for (child = NULL;
                             (child = of_get_next_child(np, child)) != NULL;) {
-                               const u32 *reg = get_property(child,
+                               const u32 *reg = of_get_property(child,
                                                "reg", NULL);
                                if (reg == NULL)
                                        continue;
@@ -905,7 +905,7 @@ static void __init smu_i2c_probe(void)
                if (strcmp(busnode->type, "i2c") &&
                    strcmp(busnode->type, "i2c-bus"))
                        continue;
-               reg = get_property(busnode, "reg", NULL);
+               reg = of_get_property(busnode, "reg", NULL);
                if (reg == NULL)
                        continue;
 
@@ -950,7 +950,8 @@ struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node)
                        if (p == bus->busnode) {
                                if (prev && bus->flags & pmac_i2c_multibus) {
                                        const u32 *reg;
-                                       reg = get_property(prev, "reg", NULL);
+                                       reg = of_get_property(prev, "reg",
+                                                               NULL);
                                        if (!reg)
                                                continue;
                                        if (((*reg) >> 8) != bus->channel)
@@ -971,7 +972,7 @@ EXPORT_SYMBOL_GPL(pmac_i2c_find_bus);
 
 u8 pmac_i2c_get_dev_addr(struct device_node *device)
 {
-       const u32 *reg = get_property(device, "reg", NULL);
+       const u32 *reg = of_get_property(device, "reg", NULL);
 
        if (reg == NULL)
                return 0;
index 6fbac308ded649ffcee13fbdacfe2ea04e55959e..22c4ae4c69348350b0d155418b4fe678515ef0ea 100644 (file)
@@ -70,11 +70,11 @@ static int __init fixup_one_level_bus_range(struct device_node *node, int higher
                int len;
 
                /* For PCI<->PCI bridges or CardBus bridges, we go down */
-               class_code = get_property(node, "class-code", NULL);
+               class_code = of_get_property(node, "class-code", NULL);
                if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
                        (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
                        continue;
-               bus_range = get_property(node, "bus-range", &len);
+               bus_range = of_get_property(node, "bus-range", &len);
                if (bus_range != NULL && len > 2 * sizeof(int)) {
                        if (bus_range[1] > higher)
                                higher = bus_range[1];
@@ -100,7 +100,7 @@ static void __init fixup_bus_range(struct device_node *bridge)
        if (prop == NULL || prop->length < 2 * sizeof(int))
                return;
 
-       bus_range = (int *)prop->value;
+       bus_range = prop->value;
        bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
 }
 
@@ -246,8 +246,8 @@ static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
        if (np == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       vendor = get_property(np, "vendor-id", NULL);
-       device = get_property(np, "device-id", NULL);
+       vendor = of_get_property(np, "vendor-id", NULL);
+       device = of_get_property(np, "device-id", NULL);
        if (vendor == NULL || device == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -622,13 +622,14 @@ static void __init init_p2pbridge(void)
 
        /* XXX it would be better here to identify the specific
           PCI-PCI bridge chip we have. */
-       if ((p2pbridge = find_devices("pci-bridge")) == 0
+       p2pbridge = of_find_node_by_name(NULL, "pci-bridge");
+       if (p2pbridge == NULL
            || p2pbridge->parent == NULL
            || strcmp(p2pbridge->parent->name, "pci") != 0)
-               return;
+               goto done;
        if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
                DBG("Can't find PCI infos for PCI<->PCI bridge\n");
-               return;
+               goto done;
        }
        /* Warning: At this point, we have not yet renumbered all busses.
         * So we must use OF walking to find out hose
@@ -636,16 +637,18 @@ static void __init init_p2pbridge(void)
        hose = pci_find_hose_for_OF_device(p2pbridge);
        if (!hose) {
                DBG("Can't find hose for PCI<->PCI bridge\n");
-               return;
+               goto done;
        }
        if (early_read_config_word(hose, bus, devfn,
                                   PCI_BRIDGE_CONTROL, &val) < 0) {
                printk(KERN_ERR "init_p2pbridge: couldn't read bridge"
                       " control\n");
-               return;
+               goto done;
        }
        val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
        early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
+done:
+       of_node_put(p2pbridge);
 }
 
 static void __init init_second_ohare(void)
@@ -691,17 +694,17 @@ static void __init fixup_nec_usb2(void)
                const u32 *prop;
                u8 bus, devfn;
 
-               prop = get_property(nec, "vendor-id", NULL);
+               prop = of_get_property(nec, "vendor-id", NULL);
                if (prop == NULL)
                        continue;
                if (0x1033 != *prop)
                        continue;
-               prop = get_property(nec, "device-id", NULL);
+               prop = of_get_property(nec, "device-id", NULL);
                if (prop == NULL)
                        continue;
                if (0x0035 != *prop)
                        continue;
-               prop = get_property(nec, "reg", NULL);
+               prop = of_get_property(nec, "reg", NULL);
                if (prop == NULL)
                        continue;
                devfn = (prop[0] >> 8) & 0xff;
@@ -909,7 +912,7 @@ static int __init add_bridge(struct device_node *dev)
        has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
 
        /* Get bus range if any */
-       bus_range = get_property(dev, "bus-range", &len);
+       bus_range = of_get_property(dev, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                printk(KERN_WARNING "Can't get bus-range for %s, assume"
                       " bus 0\n", dev->full_name);
@@ -1199,8 +1202,7 @@ void __init pmac_pcibios_after_init(void)
        }
 #endif /* CONFIG_BLK_DEV_IDE */
 
-       nd = find_devices("firewire");
-       while (nd) {
+       for_each_node_by_name(nd, "firewire") {
                if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
                                   device_is_compatible(nd, "pci106b,30") ||
                                   device_is_compatible(nd, "pci11c1,5811"))
@@ -1208,15 +1210,14 @@ void __init pmac_pcibios_after_init(void)
                        pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
                        pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
                }
-               nd = nd->next;
        }
-       nd = find_devices("ethernet");
-       while (nd) {
+       of_node_put(nd);
+       for_each_node_by_name(nd, "ethernet") {
                if (nd->parent && device_is_compatible(nd, "gmac")
                    && device_is_compatible(nd->parent, "uni-north"))
                        pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
-               nd = nd->next;
        }
+       of_node_put(nd);
 }
 
 #ifdef CONFIG_PPC32
index 5c6c15c5f9a382fc529b636e270986b7825c88f8..45d54b9ad9e04b0941bb94699a6373fe0dec53d0 100644 (file)
@@ -114,7 +114,7 @@ static void macio_gpio_init_one(struct macio_chip *macio)
         * we just create them all
         */
        for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) {
-               const u32 *reg = get_property(gp, "reg", NULL);
+               const u32 *reg = of_get_property(gp, "reg", NULL);
                unsigned long offset;
                if (reg == NULL)
                        continue;
index 7651f278615a307dd701fe900a6bcc6b5fbf67bc..85434231ae14d5658be4d6c122d8ab78d8f27ed1 100644 (file)
@@ -692,8 +692,7 @@ static int pmf_add_functions(struct pmf_device *dev, void *driverdata)
                name = pp->name + plen;
                if (strlen(name) && pp->length >= 12)
                        count += pmf_add_function_prop(dev, driverdata, name,
-                                                      (u32 *)pp->value,
-                                                      pp->length);
+                                                      pp->value, pp->length);
        }
        return count;
 }
@@ -821,7 +820,7 @@ struct pmf_function *__pmf_find_function(struct device_node *target,
         * one, then we fallback to a direct call attempt
         */
        snprintf(fname, 63, "platform-%s", name);
-       prop = get_property(target, fname, NULL);
+       prop = of_get_property(target, fname, NULL);
        if (prop == NULL)
                goto find_it;
        ph = *prop;
index 5e5c0e4add91dc09cf465d0e3bd9eb0f4dfdabb8..ae5097ac0378118855d2267caa3655acba306d40 100644 (file)
@@ -482,14 +482,14 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,
        pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
 
        flags |= MPIC_WANTS_RESET;
-       if (get_property(np, "big-endian", NULL))
+       if (of_get_property(np, "big-endian", NULL))
                flags |= MPIC_BIG_ENDIAN;
 
        /* Primary Big Endian means HT interrupts. This is quite dodgy
         * but works until I find a better way
         */
        if (master && (flags & MPIC_BIG_ENDIAN))
-               flags |= MPIC_BROKEN_U3;
+               flags |= MPIC_U3_HT_IRQS;
 
        mpic = mpic_alloc(np, r.start, flags, 0, 0, name);
        if (mpic == NULL)
@@ -510,7 +510,7 @@ static int __init pmac_pic_probe_mpic(void)
        for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
                     != NULL;) {
                if (master == NULL &&
-                   get_property(np, "interrupts", NULL) == NULL)
+                   of_get_property(np, "interrupts", NULL) == NULL)
                        master = of_node_get(np);
                else if (slave == NULL)
                        slave = of_node_get(np);
@@ -575,7 +575,7 @@ void __init pmac_pic_init(void)
 #ifdef CONFIG_PPC32
        if (!pmac_newworld)
                flags |= OF_IMAP_OLDWORLD_MAC;
-       if (get_property(of_chosen, "linux,bootx", NULL) != NULL)
+       if (of_get_property(of_chosen, "linux,bootx", NULL) != NULL)
                flags |= OF_IMAP_NO_PHANDLE;
 #endif /* CONFIG_PPC_32 */
 
index 651fa424ea06c5ef10be103ac3c888856f6aacaa..b820cabac697ceef08d9a786ded2e37ccbe1df3e 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/initrd.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
-#include <linux/ide.h>
 #include <linux/pci.h>
 #include <linux/adb.h>
 #include <linux/cuda.h>
@@ -135,12 +134,12 @@ static void pmac_show_cpuinfo(struct seq_file *m)
        seq_printf(m, "machine\t\t: ");
        np = of_find_node_by_path("/");
        if (np != NULL) {
-               pp = get_property(np, "model", NULL);
+               pp = of_get_property(np, "model", NULL);
                if (pp != NULL)
                        seq_printf(m, "%s\n", pp);
                else
                        seq_printf(m, "PowerMac\n");
-               pp = get_property(np, "compatible", &plen);
+               pp = of_get_property(np, "compatible", &plen);
                if (pp != NULL) {
                        seq_printf(m, "motherboard\t:");
                        while (plen > 0) {
@@ -164,11 +163,13 @@ static void pmac_show_cpuinfo(struct seq_file *m)
        if (np == NULL)
                np = of_find_node_by_type(NULL, "cache");
        if (np != NULL) {
-               const unsigned int *ic = get_property(np, "i-cache-size", NULL);
-               const unsigned int *dc = get_property(np, "d-cache-size", NULL);
+               const unsigned int *ic =
+                       of_get_property(np, "i-cache-size", NULL);
+               const unsigned int *dc =
+                       of_get_property(np, "d-cache-size", NULL);
                seq_printf(m, "L2 cache\t:");
                has_l2cache = 1;
-               if (get_property(np, "cache-unified", NULL) != 0 && dc) {
+               if (of_get_property(np, "cache-unified", NULL) != 0 && dc) {
                        seq_printf(m, " %dK unified", *dc / 1024);
                } else {
                        if (ic)
@@ -177,7 +178,7 @@ static void pmac_show_cpuinfo(struct seq_file *m)
                                seq_printf(m, "%s %dK data",
                                           (ic? " +": ""), *dc / 1024);
                }
-               pp = get_property(np, "ram-type", NULL);
+               pp = of_get_property(np, "ram-type", NULL);
                if (pp)
                        seq_printf(m, " %s", pp);
                seq_printf(m, "\n");
@@ -192,8 +193,11 @@ static void pmac_show_cpuinfo(struct seq_file *m)
 #ifndef CONFIG_ADB_CUDA
 int find_via_cuda(void)
 {
-       if (!find_devices("via-cuda"))
+       struct device_node *dn = of_find_node_by_name(NULL, "via-cuda");
+
+       if (!dn)
                return 0;
+       of_node_put(dn);
        printk("WARNING ! Your machine is CUDA-based but your kernel\n");
        printk("          wasn't compiled with CONFIG_ADB_CUDA option !\n");
        return 0;
@@ -203,8 +207,11 @@ int find_via_cuda(void)
 #ifndef CONFIG_ADB_PMU
 int find_via_pmu(void)
 {
-       if (!find_devices("via-pmu"))
+       struct device_node *dn = of_find_node_by_name(NULL, "via-pmu");
+
+       if (!dn)
                return 0;
+       of_node_put(dn);
        printk("WARNING ! Your machine is PMU-based but your kernel\n");
        printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
        return 0;
@@ -224,6 +231,8 @@ static volatile u32 *sysctrl_regs;
 
 static void __init ohare_init(void)
 {
+       struct device_node *dn;
+
        /* this area has the CPU identification register
           and some registers used by smp boards */
        sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
@@ -233,7 +242,9 @@ static void __init ohare_init(void)
         * We assume that we have a PSX memory controller iff
         * we have an ohare I/O controller.
         */
-       if (find_devices("ohare") != NULL) {
+       dn = of_find_node_by_name(NULL, "ohare");
+       if (dn) {
+               of_node_put(dn);
                if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
                        if (sysctrl_regs[4] & 0x10)
                                sysctrl_regs[4] |= 0x04000020;
@@ -249,18 +260,19 @@ static void __init l2cr_init(void)
 {
        /* Checks "l2cr-value" property in the registry */
        if (cpu_has_feature(CPU_FTR_L2CR)) {
-               struct device_node *np = find_devices("cpus");
+               struct device_node *np = of_find_node_by_name(NULL, "cpus");
                if (np == 0)
-                       np = find_type_devices("cpu");
+                       np = of_find_node_by_type(NULL, "cpu");
                if (np != 0) {
                        const unsigned int *l2cr =
-                               get_property(np, "l2cr-value", NULL);
+                               of_get_property(np, "l2cr-value", NULL);
                        if (l2cr != 0) {
                                ppc_override_l2cr = 1;
                                ppc_override_l2cr_value = *l2cr;
                                _set_L2CR(0);
                                _set_L2CR(ppc_override_l2cr_value);
                        }
+                       of_node_put(np);
                }
        }
 
@@ -286,7 +298,7 @@ static void __init pmac_setup_arch(void)
        loops_per_jiffy = 50000000 / HZ;
        cpu = of_find_node_by_type(NULL, "cpu");
        if (cpu != NULL) {
-               fp = get_property(cpu, "clock-frequency", NULL);
+               fp = of_get_property(cpu, "clock-frequency", NULL);
                if (fp != NULL) {
                        if (pvr >= 0x30 && pvr < 0x80)
                                /* PPC970 etc. */
@@ -303,7 +315,7 @@ static void __init pmac_setup_arch(void)
 
        /* See if newworld or oldworld */
        for (ic = NULL; (ic = of_find_all_nodes(ic)) != NULL; )
-               if (get_property(ic, "interrupt-controller", NULL))
+               if (of_get_property(ic, "interrupt-controller", NULL))
                        break;
        if (ic) {
                pmac_newworld = 1;
@@ -341,8 +353,15 @@ static void __init pmac_setup_arch(void)
 
 #ifdef CONFIG_SMP
        /* Check for Core99 */
-       if (find_devices("uni-n") || find_devices("u3") || find_devices("u4"))
+       ic = of_find_node_by_name(NULL, "uni-n");
+       if (!ic)
+               ic = of_find_node_by_name(NULL, "u3");
+       if (!ic)
+               ic = of_find_node_by_name(NULL, "u4");
+       if (ic) {
+               of_node_put(ic);
                smp_ops = &core99_smp_ops;
+       }
 #ifdef CONFIG_PPC32
        else
                smp_ops = &psurge_smp_ops;
@@ -616,15 +635,6 @@ static void __init pmac_init_early(void)
 #endif
 }
 
-/*
- * pmac has no legacy IO, anything calling this function has to
- * fail or bad things will happen
- */
-static int pmac_check_legacy_ioport(unsigned int baseport)
-{
-       return -ENODEV;
-}
-
 static int __init pmac_declare_of_platform_devices(void)
 {
        struct device_node *np;
@@ -736,7 +746,6 @@ define_machine(powermac) {
        .get_rtc_time           = pmac_get_rtc_time,
        .calibrate_decr         = pmac_calibrate_decr,
        .feature_call           = pmac_do_feature_call,
-       .check_legacy_ioport    = pmac_check_legacy_ioport,
        .progress               = udbg_progress,
 #ifdef CONFIG_PPC64
        .pci_probe_mode         = pmac_pci_probe_mode,
index d73fb73802bbef98e36ad0e29a9d06607ba441ad..6f32c4eca6e5f48c78eda6f00fd3c98087290537 100644 (file)
@@ -264,6 +264,7 @@ static void __init psurge_quad_init(void)
 static int __init smp_psurge_probe(void)
 {
        int i, ncpus;
+       struct device_node *dn;
 
        /* We don't do SMP on the PPC601 -- paulus */
        if (PVR_VER(mfspr(SPRN_PVR)) == 1)
@@ -279,8 +280,10 @@ static int __init smp_psurge_probe(void)
         * in the hammerhead memory controller in the case of the
         * dual-cpu powersurge board.  -- paulus.
         */
-       if (find_devices("hammerhead") == NULL)
+       dn = of_find_node_by_name(NULL, "hammerhead");
+       if (dn == NULL)
                return 1;
+       of_node_put(dn);
 
        hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
        quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
@@ -567,7 +570,7 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus)
                pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);
                if (pmac_tb_clock_chip_host == NULL)
                        continue;
-               reg = get_property(cc, "reg", NULL);
+               reg = of_get_property(cc, "reg", NULL);
                if (reg == NULL)
                        continue;
                switch (*reg) {
@@ -695,7 +698,7 @@ static void __init smp_core99_setup(int ncpus)
                struct device_node *cpus =
                        of_find_node_by_path("/cpus");
                if (cpus &&
-                   get_property(cpus, "platform-cpu-timebase", NULL)) {
+                   of_get_property(cpus, "platform-cpu-timebase", NULL)) {
                        pmac_tb_freeze = smp_core99_pfunc_tb_freeze;
                        printk(KERN_INFO "Processor timebase sync using"
                               " platform function\n");
@@ -712,7 +715,7 @@ static void __init smp_core99_setup(int ncpus)
                core99_tb_gpio = KL_GPIO_TB_ENABLE;     /* default value */
                cpu = of_find_node_by_type(NULL, "cpu");
                if (cpu != NULL) {
-                       tbprop = get_property(cpu, "timebase-enable", NULL);
+                       tbprop = of_get_property(cpu, "timebase-enable", NULL);
                        if (tbprop)
                                core99_tb_gpio = *tbprop;
                        of_node_put(cpu);
index a4173906e94525a56184ece0d3d1db89e4d66bf3..bf9da56942e8df6bbfdaeea285d7584961970000 100644 (file)
@@ -297,49 +297,11 @@ int __init via_calibrate_decr(void)
 }
 #endif
 
-#ifdef CONFIG_PM
-/*
- * Reset the time after a sleep.
- */
-static int
-time_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-       static unsigned long time_diff;
-       unsigned long flags;
-       unsigned long seq;
-       struct timespec tv;
-
-       switch (when) {
-       case PBOOK_SLEEP_NOW:
-               do {
-                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
-                       time_diff = xtime.tv_sec - pmac_get_boot_time();
-               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-               break;
-       case PBOOK_WAKE:
-               tv.tv_sec = pmac_get_boot_time() + time_diff;
-               tv.tv_nsec = 0;
-               do_settimeofday(&tv);
-               break;
-       }
-       return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier time_sleep_notifier = {
-       time_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PM */
-
 /*
  * Query the OF and get the decr frequency.
  */
 void __init pmac_calibrate_decr(void)
 {
-#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
-       /* XXX why here? */
-       pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif
-
        generic_calibrate_decr();
 
 #ifdef CONFIG_PPC32
index 379db05b0082418ee7232389e1d05b44cad4bc60..47de4d3fc1674008f90dbf380e0971c6cb2417ac 100644 (file)
@@ -81,7 +81,7 @@ void udbg_scc_init(int force_scc)
        macio = of_get_parent(escc);
        if (macio == NULL)
                goto bail;
-       path = get_property(of_chosen, "linux,stdout-path", NULL);
+       path = of_get_property(of_chosen, "linux,stdout-path", NULL);
        if (path != NULL)
                stdout = of_find_node_by_path(path);
        for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) {
@@ -96,13 +96,13 @@ void udbg_scc_init(int force_scc)
        ch = ch_def ? ch_def : ch_a;
 
        /* Get address within mac-io ASIC */
-       reg = get_property(escc, "reg", NULL);
+       reg = of_get_property(escc, "reg", NULL);
        if (reg == NULL)
                goto bail;
        addr = reg[0];
 
        /* Get address of mac-io PCI itself */
-       reg = get_property(macio, "assigned-addresses", NULL);
+       reg = of_get_property(macio, "assigned-addresses", NULL);
        if (reg == NULL)
                goto bail;
        addr += reg[2];
index 673ac47a1626aa0a2e45c7da6cb556d35b71acb2..29d411279b0cbbde12e7c93cd6524b6b27fd8365 100644 (file)
@@ -1,3 +1,12 @@
+config PPC_PREP
+       bool "PowerPC Reference Platform (PReP) based machines"
+       depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
+       select MPIC
+       select PPC_I8259
+       select PPC_INDIRECT_PCI
+       select PPC_UDBG_16550
+       select PPC_NATIVE
+       default n
 
 config PREP_RESIDUAL
        bool "Support for PReP Residual Data"
index 1a481a60a883db69f33e96a1a35c0b0de09bf19f..40f0008af4d1a9af93c7f85bffe2e640594f9581 100644 (file)
@@ -1,3 +1,19 @@
+config PPC_PS3
+       bool "Sony PS3 (incomplete)"
+       depends on PPC_MULTIPLATFORM && PPC64
+       select PPC_CELL
+       select USB_ARCH_HAS_OHCI
+       select USB_OHCI_LITTLE_ENDIAN
+       select USB_OHCI_BIG_ENDIAN_MMIO
+       select USB_ARCH_HAS_EHCI
+       select USB_EHCI_BIG_ENDIAN_MMIO
+       help
+         This option enables support for the Sony PS3 game console
+         and other platforms using the PS3 hypervisor.
+         Support for this platform is not yet complete, so
+         enabling this will not result in a bootable kernel on a
+         PS3 system.
+
 menu "PS3 Platform Options"
        depends on PPC_PS3
 
index e12e59fea13a5a8a94517f580c3c1d5e5041d37d..ea60c451cf87f65e02c04284f9682f2642071bf0 100644 (file)
@@ -39,7 +39,7 @@ static unsigned long htab_addr;
 static unsigned char *bolttab;
 static unsigned char *inusetab;
 
-static spinlock_t ps3_bolttab_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ps3_bolttab_lock);
 
 #define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \
        _debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__)
index a57032cf6f1b2da4c573c6742119416293ea68f2..16e4e401b8203f1668dd83c0c0ee0d1bfb8b54d5 100644 (file)
@@ -1,3 +1,13 @@
+config PPC_PSERIES
+       depends on PPC_MULTIPLATFORM && PPC64
+       bool "IBM pSeries & new (POWER5-based) iSeries"
+       select MPIC
+       select PPC_I8259
+       select PPC_RTAS
+       select RTAS_ERROR_LOGGING
+       select PPC_UDBG_16550
+       select PPC_NATIVE
+       default y
 
 config PPC_SPLPAR
        depends on PPC_PSERIES
index 2dfd05095a25fac98734f871a9188bba1fbaa1bc..90235d598751ab442221f104a9962574bcc8a0e9 100644 (file)
@@ -2,14 +2,15 @@ ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS           += -mno-minimal-toc
 endif
 
-obj-y                  := pci.o lpar.o hvCall.o nvram.o reconfig.o \
-                          setup.o iommu.o ras.o rtasd.o pci_dlpar.o \
+obj-y                  := lpar.o hvCall.o nvram.o reconfig.o \
+                          setup.o iommu.o ras.o rtasd.o \
                           firmware.o power.o
 obj-$(CONFIG_SMP)      += smp.o
 obj-$(CONFIG_XICS)     += xics.o
 obj-$(CONFIG_SCANLOG)  += scanlog.o
 obj-$(CONFIG_EEH)      += eeh.o eeh_cache.o eeh_driver.o eeh_event.o
 obj-$(CONFIG_KEXEC)    += kexec.o
+obj-$(CONFIG_PCI)      += pci.o pci_dlpar.o
 
 obj-$(CONFIG_HOTPLUG_CPU)      += hotplug-cpu.o
 
index 6cedbc002e0ffb3a2f4449b73d1388336cb2a327..48fbd442e9dfbef36bcd26fcaac748fc42b0eb05 100644 (file)
  * is broken and panic.  This sets the threshold for how many read
  * attempts we allow before panicking.
  */
-#define EEH_MAX_FAILS  100000
+#define EEH_MAX_FAILS  2100000
+
+/* Time to wait for a PCI slot to retport status, in milliseconds */
+#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
 
 /* RTAS tokens */
 static int ibm_set_eeh_option;
@@ -83,6 +86,7 @@ static int ibm_read_slot_reset_state;
 static int ibm_read_slot_reset_state2;
 static int ibm_slot_error_detail;
 static int ibm_get_config_addr_info;
+static int ibm_get_config_addr_info2;
 static int ibm_configure_bridge;
 
 int eeh_subsystem_enabled;
@@ -167,6 +171,55 @@ static int read_slot_reset_state(struct pci_dn *pdn, int rets[])
                         BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid));
 }
 
+/**
+ * eeh_wait_for_slot_status - returns error status of slot
+ * @pdn pci device node
+ * @max_wait_msecs maximum number to millisecs to wait
+ *
+ * Return negative value if a permanent error, else return
+ * Partition Endpoint (PE) status value.
+ *
+ * If @max_wait_msecs is positive, then this routine will
+ * sleep until a valid status can be obtained, or until
+ * the max allowed wait time is exceeded, in which case
+ * a -2 is returned.
+ */
+int
+eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs)
+{
+       int rc;
+       int rets[3];
+       int mwait;
+
+       while (1) {
+               rc = read_slot_reset_state(pdn, rets);
+               if (rc) return rc;
+               if (rets[1] == 0) return -1;  /* EEH is not supported */
+
+               if (rets[0] != 5) return rets[0]; /* return actual status */
+
+               if (rets[2] == 0) return -1; /* permanently unavailable */
+
+               if (max_wait_msecs <= 0) return -1;
+
+               mwait = rets[2];
+               if (mwait <= 0) {
+                       printk (KERN_WARNING
+                               "EEH: Firmware returned bad wait value=%d\n", mwait);
+                       mwait = 1000;
+               } else if (mwait > 300*1000) {
+                       printk (KERN_WARNING
+                               "EEH: Firmware is taking too long, time=%d\n", mwait);
+                       mwait = 300*1000;
+               }
+               max_wait_msecs -= mwait;
+               msleep (mwait);
+       }
+
+       printk(KERN_WARNING "EEH: Timed out waiting for slot status\n");
+       return -2;
+}
+
 /**
  * eeh_token_to_phys - convert EEH address token to phys address
  * @token i/o token, should be address in the form 0xA....
@@ -229,7 +282,7 @@ void eeh_mark_slot (struct device_node *dn, int mode_flag)
        dn = find_device_pe (dn);
 
        /* Back up one, since config addrs might be shared */
-       if (PCI_DN(dn) && PCI_DN(dn)->eeh_pe_config_addr)
+       if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
                dn = dn->parent;
 
        PCI_DN(dn)->eeh_mode |= mode_flag;
@@ -263,7 +316,7 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag)
        dn = find_device_pe (dn);
        
        /* Back up one, since config addrs might be shared */
-       if (PCI_DN(dn) && PCI_DN(dn)->eeh_pe_config_addr)
+       if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
                dn = dn->parent;
 
        PCI_DN(dn)->eeh_mode &= ~mode_flag;
@@ -293,7 +346,6 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
        int rets[3];
        unsigned long flags;
        struct pci_dn *pdn;
-       enum pci_channel_state state;
        int rc = 0;
 
        total_mmio_ffs++;
@@ -367,25 +419,25 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
                goto dn_unlock;
        }
 
-       /* If EEH is not supported on this device, punt. */
-       if (rets[1] != 1) {
-               printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n",
-                      ret, dn->full_name);
+       /* Note that config-io to empty slots may fail;
+        * they are empty when they don't have children. */
+       if ((rets[0] == 5) && (dn->child == NULL)) {
                false_positives++;
                rc = 0;
                goto dn_unlock;
        }
 
-       /* If not the kind of error we know about, punt. */
-       if (rets[0] != 2 && rets[0] != 4 && rets[0] != 5) {
+       /* If EEH is not supported on this device, punt. */
+       if (rets[1] != 1) {
+               printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n",
+                      ret, dn->full_name);
                false_positives++;
                rc = 0;
                goto dn_unlock;
        }
 
-       /* Note that config-io to empty slots may fail;
-        * we recognize empty because they don't have children. */
-       if ((rets[0] == 5) && (dn->child == NULL)) {
+       /* If not the kind of error we know about, punt. */
+       if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) {
                false_positives++;
                rc = 0;
                goto dn_unlock;
@@ -399,17 +451,12 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
        eeh_mark_slot (dn, EEH_MODE_ISOLATED);
        spin_unlock_irqrestore(&confirm_error_lock, flags);
 
-       state = pci_channel_io_normal;
-       if ((rets[0] == 2) || (rets[0] == 4))
-               state = pci_channel_io_frozen;
-       if (rets[0] == 5)
-               state = pci_channel_io_perm_failure;
-       eeh_send_failure_event (dn, dev, state, rets[2]);
+       eeh_send_failure_event (dn, dev);
 
        /* Most EEH events are due to device driver bugs.  Having
         * a stack trace will help the device-driver authors figure
         * out what happened.  So print that out. */
-       if (rets[0] != 5) dump_stack();
+       dump_stack();
        return 1;
 
 dn_unlock:
@@ -457,38 +504,6 @@ EXPORT_SYMBOL(eeh_check_failure);
 /* ------------------------------------------------------------- */
 /* The code below deals with error recovery */
 
-/**
- * eeh_slot_availability - returns error status of slot
- * @pdn pci device node
- *
- * Return negative value if a permanent error, else return
- * a number of milliseconds to wait until the PCI slot is
- * ready to be used.
- */
-static int
-eeh_slot_availability(struct pci_dn *pdn)
-{
-       int rc;
-       int rets[3];
-
-       rc = read_slot_reset_state(pdn, rets);
-
-       if (rc) return rc;
-
-       if (rets[1] == 0) return -1;  /* EEH is not supported */
-       if (rets[0] == 0) return 0;   /* Oll Korrect */
-       if (rets[0] == 5) {
-               if (rets[2] == 0) return -1; /* permanently unavailable */
-               return rets[2]; /* number of millisecs to wait */
-       }
-       if (rets[0] == 1)
-               return 250;
-
-       printk (KERN_ERR "EEH: Slot unavailable: rc=%d, rets=%d %d %d\n",
-               rc, rets[0], rets[1], rets[2]);
-       return -2;
-}
-
 /**
  * rtas_pci_enable - enable MMIO or DMA transfers for this slot
  * @pdn pci device node
@@ -512,9 +527,13 @@ rtas_pci_enable(struct pci_dn *pdn, int function)
                            function);
 
        if (rc)
-               printk(KERN_WARNING "EEH: Cannot enable function %d, err=%d dn=%s\n",
+               printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n",
                        function, rc, pdn->node->full_name);
 
+       rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC);
+       if ((rc == 4) && (function == EEH_THAW_MMIO))
+               return 0;
+
        return rc;
 }
 
@@ -595,36 +614,24 @@ int rtas_set_slot_reset(struct pci_dn *pdn)
 {
        int i, rc;
 
-       __rtas_set_slot_reset(pdn);
+       /* Take three shots at resetting the bus */
+       for (i=0; i<3; i++) {
+               __rtas_set_slot_reset(pdn);
 
-       /* Now double check with the firmware to make sure the device is
-        * ready to be used; if not, wait for recovery. */
-       for (i=0; i<10; i++) {
-               rc = eeh_slot_availability (pdn);
+               rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC);
                if (rc == 0)
                        return 0;
 
-               if (rc == -2) {
-                       printk (KERN_ERR "EEH: failed (%d) to reset slot %s\n",
-                               i, pdn->node->full_name);
-                       __rtas_set_slot_reset(pdn);
-                       continue;
-               }
-
                if (rc < 0) {
                        printk (KERN_ERR "EEH: unrecoverable slot failure %s\n",
                                pdn->node->full_name);
                        return -1;
                }
-
-               msleep (rc+100);
+               printk (KERN_ERR "EEH: bus reset %d failed on slot %s\n",
+                       i+1, pdn->node->full_name);
        }
 
-       rc = eeh_slot_availability (pdn);
-       if (rc)
-               printk (KERN_ERR "EEH: timeout resetting slot %s\n", pdn->node->full_name);
-
-       return rc;
+       return -1;
 }
 
 /* ------------------------------------------------------- */
@@ -744,16 +751,48 @@ struct eeh_early_enable_info {
        unsigned int buid_lo;
 };
 
+static int get_pe_addr (int config_addr,
+                        struct eeh_early_enable_info *info)
+{
+       unsigned int rets[3];
+       int ret;
+
+       /* Use latest config-addr token on power6 */
+       if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) {
+               /* Make sure we have a PE in hand */
+               ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,
+                       config_addr, info->buid_hi, info->buid_lo, 1);
+               if (ret || (rets[0]==0))
+                       return 0;
+
+               ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,
+                       config_addr, info->buid_hi, info->buid_lo, 0);
+               if (ret)
+                       return 0;
+               return rets[0];
+       }
+
+       /* Use older config-addr token on power5 */
+       if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
+               ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets,
+                       config_addr, info->buid_hi, info->buid_lo, 0);
+               if (ret)
+                       return 0;
+               return rets[0];
+       }
+       return 0;
+}
+
 /* Enable eeh for the given device node. */
 static void *early_enable_eeh(struct device_node *dn, void *data)
 {
        unsigned int rets[3];
        struct eeh_early_enable_info *info = data;
        int ret;
-       const char *status = get_property(dn, "status", NULL);
-       const u32 *class_code = get_property(dn, "class-code", NULL);
-       const u32 *vendor_id = get_property(dn, "vendor-id", NULL);
-       const u32 *device_id = get_property(dn, "device-id", NULL);
+       const char *status = of_get_property(dn, "status", NULL);
+       const u32 *class_code = of_get_property(dn, "class-code", NULL);
+       const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL);
+       const u32 *device_id = of_get_property(dn, "device-id", NULL);
        const u32 *regs;
        int enable;
        struct pci_dn *pdn = PCI_DN(dn);
@@ -796,7 +835,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
 
        /* Ok... see if this device supports EEH.  Some do, some don't,
         * and the only way to find out is to check each and every one. */
-       regs = get_property(dn, "reg", NULL);
+       regs = of_get_property(dn, "reg", NULL);
        if (regs) {
                /* First register entry is addr (00BBSS00)  */
                /* Try to enable eeh */
@@ -810,15 +849,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
 
                        /* If the newer, better, ibm,get-config-addr-info is supported, 
                         * then use that instead. */
-                       pdn->eeh_pe_config_addr = 0;
-                       if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
-                               ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, 
-                                       pdn->eeh_config_addr, 
-                                       info->buid_hi, info->buid_lo,
-                                       0);
-                               if (ret == 0)
-                                       pdn->eeh_pe_config_addr = rets[0];
-                       }
+                       pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info);
 
                        /* Some older systems (Power4) allow the
                         * ibm,set-eeh-option call to succeed even on nodes
@@ -889,6 +920,7 @@ void __init eeh_init(void)
        ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
        ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");
        ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info");
+       ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2");
        ibm_configure_bridge = rtas_token ("ibm,configure-bridge");
 
        if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
index a4c0bf84ef2e96644f40f6cbe4eaa69c40a8fb53..3170e003f76ada0a313888fe30d51e06c3917c4c 100644 (file)
@@ -158,7 +158,8 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
                return;
 
        rc = driver->err_handler->slot_reset(dev);
-       if (*res == PCI_ERS_RESULT_NONE) *res = rc;
+       if ((*res == PCI_ERS_RESULT_NONE) ||
+           (*res == PCI_ERS_RESULT_RECOVERED)) *res = rc;
        if (*res == PCI_ERS_RESULT_DISCONNECT &&
             rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
 }
@@ -248,6 +249,7 @@ static void eeh_report_failure(struct pci_dev *dev, void *userdata)
 
 static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
 {
+       struct device_node *dn;
        int cnt, rc;
 
        /* pcibios will clear the counter; save the value */
@@ -263,23 +265,20 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
        if (rc)
                return rc;
 
-       /* New-style config addrs might be shared across multiple devices,
-        * Walk over all functions on this device */
-       if (pe_dn->eeh_pe_config_addr) {
-               struct device_node *pe = pe_dn->node;
-               pe = pe->parent->child;
-               while (pe) {
-                       struct pci_dn *ppe = PCI_DN(pe);
-                       if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
-                               rtas_configure_bridge(ppe);
-                               eeh_restore_bars(ppe);
-                       }
-                       pe = pe->sibling;
+       /* Walk over all functions on this device.  */
+       dn = pe_dn->node;
+       if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+               dn = dn->parent->child;
+
+       while (dn) {
+               struct pci_dn *ppe = PCI_DN(dn);
+               /* On Power4, always true because eeh_pe_config_addr=0 */
+               if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
+                       rtas_configure_bridge(ppe);
+                       eeh_restore_bars(ppe);
                }
-       } else {
-               rtas_configure_bridge(pe_dn);
-               eeh_restore_bars(pe_dn);
-       }
+               dn = dn->sibling;
+       }
 
        /* Give the system 5 seconds to finish running the user-space
         * hotplug shutdown scripts, e.g. ifdown for ethernet.  Yes, 
@@ -299,7 +298,7 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
 /* The longest amount of time to wait for a pci device
  * to come back on line, in seconds.
  */
-#define MAX_WAIT_FOR_RECOVERY 15
+#define MAX_WAIT_FOR_RECOVERY 150
 
 struct pci_dn * handle_eeh_events (struct eeh_event *event)
 {
@@ -315,14 +314,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
 
        if (!frozen_dn) {
 
-               location = get_property(event->dn, "ibm,loc-code", NULL);
+               location = of_get_property(event->dn, "ibm,loc-code", NULL);
                location = location ? location : "unknown";
                printk(KERN_ERR "EEH: Error: Cannot find partition endpoint "
                                "for location=%s pci addr=%s\n",
                        location, pci_name(event->dev));
                return NULL;
        }
-       location = get_property(frozen_dn, "ibm,loc-code", NULL);
+       location = of_get_property(frozen_dn, "ibm,loc-code", NULL);
        location = location ? location : "unknown";
 
        /* There are two different styles for coming up with the PE.
@@ -341,13 +340,6 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
                return NULL;
        }
 
-#if 0
-       /* We may get "permanent failure" messages on empty slots.
-        * These are false alarms. Empty slots have no child dn. */
-       if ((event->state == pci_channel_io_perm_failure) && (frozen_device == NULL))
-               return;
-#endif
-
        frozen_pdn = PCI_DN(frozen_dn);
        frozen_pdn->eeh_freeze_count++;
 
@@ -362,13 +354,12 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
        if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
                goto excess_failures;
 
-       /* If the reset state is a '5' and the time to reset is 0 (infinity)
-        * or is more then 15 seconds, then mark this as a permanent failure.
-        */
-       if ((event->state == pci_channel_io_perm_failure) &&
-           ((event->time_unavail <= 0) ||
-            (event->time_unavail > MAX_WAIT_FOR_RECOVERY*1000)))
+       /* Get the current PCI slot state. */
+       rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000);
+       if (rc < 0) {
+               printk(KERN_WARNING "EEH: Permanent failure\n");
                goto hard_fail;
+       }
 
        eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
        printk(KERN_WARNING
@@ -390,14 +381,18 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
         */
        if (result == PCI_ERS_RESULT_NONE) {
                rc = eeh_reset_device(frozen_pdn, frozen_bus);
-               if (rc)
+               if (rc) {
+                       printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc);
                        goto hard_fail;
+               }
        }
 
        /* If all devices reported they can proceed, then re-enable MMIO */
        if (result == PCI_ERS_RESULT_CAN_RECOVER) {
                rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO);
 
+               if (rc < 0)
+                       goto hard_fail;
                if (rc) {
                        result = PCI_ERS_RESULT_NEED_RESET;
                } else {
@@ -410,6 +405,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
        if (result == PCI_ERS_RESULT_CAN_RECOVER) {
                rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA);
 
+               if (rc < 0)
+                       goto hard_fail;
                if (rc)
                        result = PCI_ERS_RESULT_NEED_RESET;
                else
@@ -417,21 +414,28 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
        }
 
        /* If any device has a hard failure, then shut off everything. */
-       if (result == PCI_ERS_RESULT_DISCONNECT)
+       if (result == PCI_ERS_RESULT_DISCONNECT) {
+               printk(KERN_WARNING "EEH: Device driver gave up\n");
                goto hard_fail;
+       }
 
        /* If any device called out for a reset, then reset the slot */
        if (result == PCI_ERS_RESULT_NEED_RESET) {
                rc = eeh_reset_device(frozen_pdn, NULL);
-               if (rc)
+               if (rc) {
+                       printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc);
                        goto hard_fail;
+               }
                result = PCI_ERS_RESULT_NONE;
                pci_walk_bus(frozen_bus, eeh_report_reset, &result);
        }
 
        /* All devices should claim they have recovered by now. */
-       if (result != PCI_ERS_RESULT_RECOVERED)
+       if ((result != PCI_ERS_RESULT_RECOVERED) &&
+           (result != PCI_ERS_RESULT_NONE)) {
+               printk(KERN_WARNING "EEH: Not recovered\n");
                goto hard_fail;
+       }
 
        /* Tell all device drivers that they can resume operations */
        pci_walk_bus(frozen_bus, eeh_report_resume, NULL);
index 49037edf7d3999545c9190d2d7fd0e0594330f49..ddb80f5d850b77231783b7f05c1d7adadd6f9aed 100644 (file)
@@ -118,9 +118,7 @@ static void eeh_thread_launcher(struct work_struct *dummy)
  * (from a workqueue).
  */
 int eeh_send_failure_event (struct device_node *dn,
-                            struct pci_dev *dev,
-                            enum pci_channel_state state,
-                            int time_unavail)
+                            struct pci_dev *dev)
 {
        unsigned long flags;
        struct eeh_event *event;
@@ -128,7 +126,7 @@ int eeh_send_failure_event (struct device_node *dn,
 
        if (!mem_init_done) {
                printk(KERN_ERR "EEH: event during early boot not handled\n");
-               location = get_property(dn, "ibm,loc-code", NULL);
+               location = of_get_property(dn, "ibm,loc-code", NULL);
                printk(KERN_ERR "EEH: device node = %s\n", dn->full_name);
                printk(KERN_ERR "EEH: PCI location = %s\n", location);
                return 1;
@@ -144,8 +142,6 @@ int eeh_send_failure_event (struct device_node *dn,
 
        event->dn = dn;
        event->dev = dev;
-       event->state = state;
-       event->time_unavail = time_unavail;
 
        /* We may or may not be called in an interrupt context */
        spin_lock_irqsave(&eeh_eventlist_lock, flags);
index 90522e3c9d46b1979eb86d738fe7c0b7c62718a9..29bf83bfb1f086b98f6657357606229b0332c266 100644 (file)
@@ -80,7 +80,7 @@ void __init fw_feature_init(void)
                goto out;
        }
 
-       hypertas = get_property(dn, "ibm,hypertas-functions", &len);
+       hypertas = of_get_property(dn, "ibm,hypertas-functions", &len);
        if (hypertas == NULL)
                goto out;
 
index f460b9cbfd465c5ba97527395b435dc93cba45a7..9711eb0d549645fee11f198fcb1cdf4ddc9f8860 100644 (file)
@@ -143,7 +143,7 @@ static int pseries_add_processor(struct device_node *np)
        int err = -ENOSPC, len, nthreads, i;
        const u32 *intserv;
 
-       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+       intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
        if (!intserv)
                return 0;
 
@@ -203,7 +203,7 @@ static void pseries_remove_processor(struct device_node *np)
        int len, nthreads, i;
        const u32 *intserv;
 
-       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+       intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
        if (!intserv)
                return;
 
index e6653a868b91c6177c79d60a97a542bd6e79a7fe..66665c82415cc7810a0e42787bd8d93a198e31bb 100644 (file)
@@ -242,6 +242,7 @@ static unsigned long tce_get_pSeriesLP(struct iommu_table *tbl, long tcenum)
        return tce_ret;
 }
 
+#ifdef CONFIG_PCI
 static void iommu_table_setparms(struct pci_controller *phb,
                                 struct device_node *dn,
                                 struct iommu_table *tbl)
@@ -252,8 +253,8 @@ static void iommu_table_setparms(struct pci_controller *phb,
 
        node = (struct device_node *)phb->arch_data;
 
-       basep = get_property(node, "linux,tce-base", NULL);
-       sizep = get_property(node, "linux,tce-size", NULL);
+       basep = of_get_property(node, "linux,tce-base", NULL);
+       sizep = of_get_property(node, "linux,tce-size", NULL);
        if (basep == NULL || sizep == NULL) {
                printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has "
                                "missing tce entries !\n", dn->full_name);
@@ -403,7 +404,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
 
        /* Find nearest ibm,dma-window, walking up the device tree */
        for (pdn = dn; pdn != NULL; pdn = pdn->parent) {
-               dma_window = get_property(pdn, "ibm,dma-window", NULL);
+               dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
                if (dma_window != NULL)
                        break;
        }
@@ -478,29 +479,6 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
                       pci_name(dev));
 }
 
-static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
-{
-       int err = NOTIFY_OK;
-       struct device_node *np = node;
-       struct pci_dn *pci = PCI_DN(np);
-
-       switch (action) {
-       case PSERIES_RECONFIG_REMOVE:
-               if (pci && pci->iommu_table &&
-                   get_property(np, "ibm,dma-window", NULL))
-                       iommu_free_table(np);
-               break;
-       default:
-               err = NOTIFY_DONE;
-               break;
-       }
-       return err;
-}
-
-static struct notifier_block iommu_reconfig_nb = {
-       .notifier_call = iommu_reconfig_notifier,
-};
-
 static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
 {
        struct device_node *pdn, *dn;
@@ -521,7 +499,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
 
        for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
             pdn = pdn->parent) {
-               dma_window = get_property(pdn, "ibm,dma-window", NULL);
+               dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
                if (dma_window)
                        break;
        }
@@ -554,15 +532,44 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
 
        dev->dev.archdata.dma_data = pci->iommu_table;
 }
+#else  /* CONFIG_PCI */
+#define pci_dma_bus_setup_pSeries      NULL
+#define pci_dma_dev_setup_pSeries      NULL
+#define pci_dma_bus_setup_pSeriesLP    NULL
+#define pci_dma_dev_setup_pSeriesLP    NULL
+#endif /* !CONFIG_PCI */
+
+static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
+{
+       int err = NOTIFY_OK;
+       struct device_node *np = node;
+       struct pci_dn *pci = PCI_DN(np);
+
+       switch (action) {
+       case PSERIES_RECONFIG_REMOVE:
+               if (pci && pci->iommu_table &&
+                   of_get_property(np, "ibm,dma-window", NULL))
+                       iommu_free_table(np);
+               break;
+       default:
+               err = NOTIFY_DONE;
+               break;
+       }
+       return err;
+}
+
+static struct notifier_block iommu_reconfig_nb = {
+       .notifier_call = iommu_reconfig_notifier,
+};
 
 /* These are called very early. */
 void iommu_init_early_pSeries(void)
 {
-       if (of_chosen && get_property(of_chosen, "linux,iommu-off", NULL)) {
+       if (of_chosen && of_get_property(of_chosen, "linux,iommu-off", NULL)) {
                /* Direct I/O, IOMMU off */
                ppc_md.pci_dma_dev_setup = NULL;
                ppc_md.pci_dma_bus_setup = NULL;
-               pci_dma_ops = &dma_direct_ops;
+               set_pci_dma_ops(&dma_direct_ops);
                return;
        }
 
@@ -588,6 +595,6 @@ void iommu_init_early_pSeries(void)
 
        pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
 
-       pci_dma_ops = &dma_iommu_ops;
+       set_pci_dma_ops(&dma_iommu_ops);
 }
 
index 843ee9643211885a76cc8a5a69c811ae3ad7d580..3a70e8ad7bc84120948dbfe7199180a561de2d11 100644 (file)
@@ -209,13 +209,13 @@ void __init find_udbg_vterm(void)
        /* find the boot console from /chosen/stdout */
        if (!of_chosen)
                return;
-       name = get_property(of_chosen, "linux,stdout-path", NULL);
+       name = of_get_property(of_chosen, "linux,stdout-path", NULL);
        if (name == NULL)
                return;
        stdout_node = of_find_node_by_path(name);
        if (!stdout_node)
                return;
-       name = get_property(stdout_node, "name", NULL);
+       name = of_get_property(stdout_node, "name", NULL);
        if (!name) {
                printk(KERN_WARNING "stdout node missing 'name' property!\n");
                goto out;
@@ -226,7 +226,7 @@ void __init find_udbg_vterm(void)
        /* Check if it's a virtual terminal */
        if (strncmp(name, "vty", 3) != 0)
                goto out;
-       termno = get_property(stdout_node, "reg", NULL);
+       termno = of_get_property(stdout_node, "reg", NULL);
        if (termno == NULL)
                goto out;
        vtermno = termno[0];
index 64163cecdf93f2819fd74481b034de89e470dda1..f68903e15bd5b30f6cf42b43c9790b3365b64796 100644 (file)
@@ -130,7 +130,7 @@ int __init pSeries_nvram_init(void)
        if (nvram == NULL)
                return -ENODEV;
 
-       nbytes_p = get_property(nvram, "#bytes", &proplen);
+       nbytes_p = of_get_property(nvram, "#bytes", &proplen);
        if (nbytes_p == NULL || proplen != sizeof(unsigned int))
                return -EIO;
 
index fa59124ce3febe98fe6c8015f071cb12e003b5bd..2c6ded29f73d3d5afbcdef6bd9719d777da0cd12 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/pci.h>
 #include <linux/string.h>
 
+#include <asm/eeh.h>
 #include <asm/pci-bridge.h>
 #include <asm/prom.h>
 #include <asm/ppc-pci.h>
@@ -39,7 +40,7 @@ void pcibios_name_device(struct pci_dev *dev)
         */
        dn = pci_device_to_OF_node(dev);
        if (dn) {
-               char *loc_code = get_property(dn, "ibm,loc-code", 0);
+               const char *loc_code = of_get_property(dn, "ibm,loc-code", 0);
                if (loc_code) {
                        int loc_len = strlen(loc_code);
                        if (loc_len < sizeof(dev->dev.name)) {
index ac56b868913a045ab44ce669b42b2076636c65f7..fdc1a369f767c971bee0b1ccf5f51b93cf539496 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/pci-bridge.h>
 #include <asm/ppc-pci.h>
 #include <asm/firmware.h>
+#include <asm/eeh.h>
 
 static struct pci_bus *
 find_bus_among_children(struct pci_bus *bus,
index edc0388731132f7c1daa63940591ac79dc39d428..53aa04101cedee646270b5841c6b64c9793bc244 100644 (file)
@@ -85,7 +85,7 @@ static void request_ras_irqs(struct device_node *np,
         * map those interrupts using the default interrupt host and default
         * trigger
         */
-       opicprop = get_property(np, "open-pic-interrupt", &opicplen);
+       opicprop = of_get_property(np, "open-pic-interrupt", &opicplen);
        if (opicprop) {
                opicplen /= sizeof(u32);
                for (i = 0; i < opicplen; i++) {
index 77d0937d5c07a334643f4e8518ad59ca7a854afd..9797b10b29351a44ea918aac081fe52fbec33790 100644 (file)
@@ -363,7 +363,7 @@ static int get_eventscan_parms(void)
 
        node = of_find_node_by_path("/rtas");
 
-       ip = get_property(node, "rtas-event-scan-rate", NULL);
+       ip = of_get_property(node, "rtas-event-scan-rate", NULL);
        if (ip == NULL) {
                printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n");
                of_node_put(node);
index 34aff47b1f551c670eca377eeb148a8f618dc946..33eec2822c668f21bac7c9a9577cc01ac94573e1 100644 (file)
@@ -65,6 +65,7 @@
 #include <asm/udbg.h>
 #include <asm/smp.h>
 #include <asm/firmware.h>
+#include <asm/eeh.h>
 
 #include "plpar_wrappers.h"
 #include "pseries.h"
@@ -92,7 +93,7 @@ static void pSeries_show_cpuinfo(struct seq_file *m)
 
        root = of_find_node_by_path("/");
        if (root)
-               model = get_property(root, "model", NULL);
+               model = of_get_property(root, "model", NULL);
        seq_printf(m, "machine\t\t: CHRP %s\n", model);
        of_node_put(root);
 }
@@ -138,8 +139,8 @@ static void __init pseries_mpic_init_IRQ(void)
        struct mpic *mpic;
 
        np = of_find_node_by_path("/");
-       naddr = prom_n_addr_cells(np);
-       opprop = get_property(np, "platform-open-pic", &opplen);
+       naddr = of_n_addr_cells(np);
+       opprop = of_get_property(np, "platform-open-pic", &opplen);
        if (opprop != 0) {
                openpic_addr = of_read_number(opprop, naddr);
                printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
@@ -188,11 +189,11 @@ static void __init pseries_mpic_init_IRQ(void)
                        break;
                if (strcmp(np->name, "pci") != 0)
                        continue;
-               addrp = get_property(np, "8259-interrupt-acknowledge",
+               addrp = of_get_property(np, "8259-interrupt-acknowledge",
                                            NULL);
                if (addrp == NULL)
                        continue;
-               naddr = prom_n_addr_cells(np);
+               naddr = of_n_addr_cells(np);
                intack = addrp[naddr-1];
                if (naddr > 1)
                        intack |= ((unsigned long)addrp[naddr-2]) << 32;
@@ -225,7 +226,7 @@ static void __init pseries_discover_pic(void)
 
        for (np = NULL; (np = of_find_node_by_name(np,
                                                   "interrupt-controller"));) {
-               typep = get_property(np, "compatible", NULL);
+               typep = of_get_property(np, "compatible", NULL);
                if (strstr(typep, "open-pic")) {
                        pSeries_mpic_node = of_node_get(np);
                        ppc_md.init_IRQ       = pseries_mpic_init_IRQ;
@@ -334,32 +335,6 @@ static void __init pSeries_init_early(void)
        DBG(" <- pSeries_init_early()\n");
 }
 
-
-static int pSeries_check_legacy_ioport(unsigned int baseport)
-{
-       struct device_node *np;
-
-#define I8042_DATA_REG 0x60
-#define FDC_BASE       0x3f0
-
-
-       switch(baseport) {
-       case I8042_DATA_REG:
-               np = of_find_node_by_type(NULL, "8042");
-               if (np == NULL)
-                       return -ENODEV;
-               of_node_put(np);
-               break;
-       case FDC_BASE:
-               np = of_find_node_by_type(NULL, "fdc");
-               if (np == NULL)
-                       return -ENODEV;
-               of_node_put(np);
-               break;
-       }
-       return 0;
-}
-
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
@@ -514,6 +489,10 @@ void pSeries_power_off(void)
        for (;;);
 }
 
+#ifndef CONFIG_PCI
+void pSeries_final_fixup(void) { }
+#endif
+
 define_machine(pseries) {
        .name                   = "pSeries",
        .probe                  = pSeries_probe,
@@ -532,7 +511,6 @@ define_machine(pseries) {
        .set_rtc_time           = rtas_set_rtc_time,
        .calibrate_decr         = generic_calibrate_decr,
        .progress               = rtas_progress,
-       .check_legacy_ioport    = pSeries_check_legacy_ioport,
        .system_reset_exception = pSeries_system_reset_exception,
        .machine_check_exception = pSeries_machine_check_exception,
 };
index 81d172d650389ee206eef128d912028a7bcd4933..896cbf340c429fd74615522532695d4b76880c7b 100644 (file)
@@ -576,7 +576,7 @@ static void __init xics_init_one_node(struct device_node *np,
         * This happens to be the case so far but we are playing with fire...
         * should be fixed one of these days. -BenH.
         */
-       ireg = get_property(np, "ibm,interrupt-server-ranges", NULL);
+       ireg = of_get_property(np, "ibm,interrupt-server-ranges", NULL);
 
        /* Do that ever happen ? we'll know soon enough... but even good'old
         * f80 does have that property ..
@@ -588,7 +588,7 @@ static void __init xics_init_one_node(struct device_node *np,
                 */
                *indx = *ireg;
        }
-       ireg = get_property(np, "reg", &ilen);
+       ireg = of_get_property(np, "reg", &ilen);
        if (!ireg)
                panic("xics_init_IRQ: can't find interrupt reg property");
 
@@ -640,10 +640,10 @@ static void __init xics_setup_8259_cascade(void)
                        break;
                if (strcmp(np->name, "pci") != 0)
                        continue;
-               addrp = get_property(np, "8259-interrupt-acknowledge", NULL);
+               addrp = of_get_property(np, "8259-interrupt-acknowledge", NULL);
                if (addrp == NULL)
                        continue;
-               naddr = prom_n_addr_cells(np);
+               naddr = of_n_addr_cells(np);
                intack = addrp[naddr-1];
                if (naddr > 1)
                        intack |= ((unsigned long)addrp[naddr-2]) << 32;
@@ -664,10 +664,11 @@ static struct device_node *cpuid_to_of_node(int cpu)
                int i, len;
                const u32 *intserv;
 
-               intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+               intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
+                                       &len);
 
                if (!intserv)
-                       intserv = get_property(np, "reg", &len);
+                       intserv = of_get_property(np, "reg", &len);
 
                i = len / sizeof(u32);
 
@@ -709,7 +710,7 @@ void __init xics_init_IRQ(void)
        /* Find the server numbers for the boot cpu. */
        np = cpuid_to_of_node(boot_cpuid);
        BUG_ON(!np);
-       ireg = get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+       ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
        if (!ireg)
                goto skip_gserver_check;
        i = ilen / sizeof(int);
@@ -725,7 +726,7 @@ void __init xics_init_IRQ(void)
                        default_server = hcpuid;
                        default_distrib_server = ireg[j+1];
 
-                       isize = get_property(np,
+                       isize = of_get_property(np,
                                        "ibm,interrupt-server#-size", NULL);
                        if (isize)
                                interrupt_server_size = *isize;
index 26ca3ffbc1dee7c12df2cf31bd002d1c937bbc45..e96ca9618dbb39541d42973aa4ae1528b3929cd2 100644 (file)
@@ -11,12 +11,17 @@ obj-$(CONFIG_PPC_PMI)               += pmi.o
 obj-$(CONFIG_U3_DART)          += dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)       += mmio_nvram.o
 obj-$(CONFIG_FSL_SOC)          += fsl_soc.o
+obj-$(CONFIG_FSL_PCIE)         += fsl_pcie.o
 obj-$(CONFIG_TSI108_BRIDGE)    += tsi108_pci.o tsi108_dev.o
 obj-$(CONFIG_QUICC_ENGINE)     += qe_lib/
 
+# contains only the suspend handler for time
+obj-$(CONFIG_PM)               += timer.o
+
 ifeq ($(CONFIG_PPC_MERGE),y)
 obj-$(CONFIG_PPC_I8259)                += i8259.o
 obj-$(CONFIG_PPC_83xx)         += ipic.o
+obj-$(CONFIG_4xx)              += uic.o
 endif
 
 # Temporary hack until we have migrated to asm-powerpc
index 1488535b0e136ddea4452a16de9736395af73460..336186dd7f10d2933a4ef02db41f625b6e9a51f8 100644 (file)
@@ -333,7 +333,7 @@ void iommu_init_early_dart(void)
                ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
 
                /* Setup pci_dma ops */
-               pci_dma_ops = &dma_iommu_ops;
+               set_pci_dma_ops(&dma_iommu_ops);
                return;
        }
 
@@ -343,7 +343,7 @@ void iommu_init_early_dart(void)
        ppc_md.pci_dma_bus_setup = NULL;
 
        /* Setup pci_dma ops */
-       pci_dma_ops = &dma_direct_ops;
+       set_pci_dma_ops(&dma_direct_ops);
 }
 
 
index 1fc5819e7d18d595b7f37e364ce9b52e8efe9591..574b6ef44e0bbfd59c56dbd3cf9afc28f24b9876 100644 (file)
@@ -26,7 +26,7 @@
 unsigned int dcr_resource_start(struct device_node *np, unsigned int index)
 {
        unsigned int ds;
-       const u32 *dr = get_property(np, "dcr-reg", &ds);
+       const u32 *dr = of_get_property(np, "dcr-reg", &ds);
 
        if (dr == NULL || ds & 1 || index >= (ds / 8))
                return 0;
@@ -37,7 +37,7 @@ unsigned int dcr_resource_start(struct device_node *np, unsigned int index)
 unsigned int dcr_resource_len(struct device_node *np, unsigned int index)
 {
        unsigned int ds;
-       const u32 *dr = get_property(np, "dcr-reg", &ds);
+       const u32 *dr = of_get_property(np, "dcr-reg", &ds);
 
        if (dr == NULL || ds & 1 || index >= (ds / 8))
                return 0;
@@ -53,9 +53,9 @@ static struct device_node * find_dcr_parent(struct device_node * node)
        const u32 *p;
 
        for (par = of_node_get(node); par;) {
-               if (get_property(par, "dcr-controller", NULL))
+               if (of_get_property(par, "dcr-controller", NULL))
                        break;
-               p = get_property(par, "dcr-parent", NULL);
+               p = of_get_property(par, "dcr-parent", NULL);
                tmp = par;
                if (p == NULL)
                        par = of_get_parent(par);
@@ -80,13 +80,13 @@ u64 of_translate_dcr_address(struct device_node *dev,
                return OF_BAD_ADDR;
 
        /* Stride is not properly defined yet, default to 0x10 for Axon */
-       p = get_property(dp, "dcr-mmio-stride", NULL);
+       p = of_get_property(dp, "dcr-mmio-stride", NULL);
        stride = (p == NULL) ? 0x10 : *p;
 
        /* XXX FIXME: Which property name is to use of the 2 following ? */
-       p = get_property(dp, "dcr-mmio-range", NULL);
+       p = of_get_property(dp, "dcr-mmio-range", NULL);
        if (p == NULL)
-               p = get_property(dp, "dcr-mmio-space", NULL);
+               p = of_get_property(dp, "dcr-mmio-space", NULL);
        if (p == NULL)
                return OF_BAD_ADDR;
 
similarity index 99%
rename from arch/powerpc/platforms/86xx/mpc86xx_pcie.c
rename to arch/powerpc/sysdev/fsl_pcie.c
index a2f4f730213e7f28b3a9fa8dc3a5e7569dba69d2..041c07e8b665aad108b8d5b76ff891157c4a875b 100644 (file)
@@ -24,8 +24,6 @@
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 
-#include "mpc86xx.h"
-
 #define PCI_CFG_OUT out_be32
 
 /* ERRATA PCI-Ex 14 PCIE Controller timeout */
diff --git a/arch/powerpc/sysdev/fsl_pcie.h b/arch/powerpc/sysdev/fsl_pcie.h
new file mode 100644 (file)
index 0000000..8d9779c
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * MPC85xx/86xx PCI Express structure define
+ *
+ * Copyright 2007 Freescale Semiconductor, Inc
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __POWERPC_FSL_PCIE_H
+#define __POWERPC_FSL_PCIE_H
+
+/* PCIE Express IO block registers in 85xx/86xx */
+
+struct ccsr_pex {
+       __be32 __iomem    pex_config_addr;      /* 0x.000 - PCI Express Configuration Address Register */
+       __be32 __iomem    pex_config_data;      /* 0x.004 - PCI Express Configuration Data Register */
+       u8 __iomem    res1[4];
+       __be32 __iomem    pex_otb_cpl_tor;      /* 0x.00c - PCI Express Outbound completion timeout register */
+       __be32 __iomem    pex_conf_tor;         /* 0x.010 - PCI Express configuration timeout register */
+       u8 __iomem    res2[12];
+       __be32 __iomem    pex_pme_mes_dr;       /* 0x.020 - PCI Express PME and message detect register */
+       __be32 __iomem    pex_pme_mes_disr;     /* 0x.024 - PCI Express PME and message disable register */
+       __be32 __iomem    pex_pme_mes_ier;      /* 0x.028 - PCI Express PME and message interrupt enable register */
+       __be32 __iomem    pex_pmcr;             /* 0x.02c - PCI Express power management command register */
+       u8 __iomem    res3[3024];
+       __be32 __iomem    pexotar0;             /* 0x.c00 - PCI Express outbound translation address register 0 */
+       __be32 __iomem    pexotear0;            /* 0x.c04 - PCI Express outbound translation extended address register 0*/
+       u8 __iomem    res4[8];
+       __be32 __iomem    pexowar0;             /* 0x.c10 - PCI Express outbound window attributes register 0*/
+       u8 __iomem    res5[12];
+       __be32 __iomem    pexotar1;             /* 0x.c20 - PCI Express outbound translation address register 1 */
+       __be32 __iomem    pexotear1;            /* 0x.c24 - PCI Express outbound translation extended address register 1*/
+       __be32 __iomem    pexowbar1;            /* 0x.c28 - PCI Express outbound window base address register 1*/
+       u8 __iomem    res6[4];
+       __be32 __iomem    pexowar1;             /* 0x.c30 - PCI Express outbound window attributes register 1*/
+       u8 __iomem    res7[12];
+       __be32 __iomem    pexotar2;             /* 0x.c40 - PCI Express outbound translation address register 2 */
+       __be32 __iomem    pexotear2;            /* 0x.c44 - PCI Express outbound translation extended address register 2*/
+       __be32 __iomem    pexowbar2;            /* 0x.c48 - PCI Express outbound window base address register 2*/
+       u8 __iomem    res8[4];
+       __be32 __iomem    pexowar2;             /* 0x.c50 - PCI Express outbound window attributes register 2*/
+       u8 __iomem    res9[12];
+       __be32 __iomem    pexotar3;             /* 0x.c60 - PCI Express outbound translation address register 3 */
+       __be32 __iomem    pexotear3;            /* 0x.c64 - PCI Express outbound translation extended address register 3*/
+       __be32 __iomem    pexowbar3;            /* 0x.c68 - PCI Express outbound window base address register 3*/
+       u8 __iomem    res10[4];
+       __be32 __iomem    pexowar3;             /* 0x.c70 - PCI Express outbound window attributes register 3*/
+       u8 __iomem    res11[12];
+       __be32 __iomem    pexotar4;             /* 0x.c80 - PCI Express outbound translation address register 4 */
+       __be32 __iomem    pexotear4;            /* 0x.c84 - PCI Express outbound translation extended address register 4*/
+       __be32 __iomem    pexowbar4;            /* 0x.c88 - PCI Express outbound window base address register 4*/
+       u8 __iomem    res12[4];
+       __be32 __iomem    pexowar4;             /* 0x.c90 - PCI Express outbound window attributes register 4*/
+       u8 __iomem    res13[12];
+       u8 __iomem    res14[256];
+       __be32 __iomem    pexitar3;             /* 0x.da0 - PCI Express inbound translation address register 3 */
+       u8 __iomem    res15[4];
+       __be32 __iomem    pexiwbar3;            /* 0x.da8 - PCI Express inbound window base address register 3 */
+       __be32 __iomem    pexiwbear3;           /* 0x.dac - PCI Express inbound window base extended address register 3 */
+       __be32 __iomem    pexiwar3;             /* 0x.db0 - PCI Express inbound window attributes register 3 */
+       u8 __iomem    res16[12];
+       __be32 __iomem    pexitar2;             /* 0x.dc0 - PCI Express inbound translation address register 2 */
+       u8 __iomem    res17[4];
+       __be32 __iomem    pexiwbar2;            /* 0x.dc8 - PCI Express inbound window base address register 2 */
+       __be32 __iomem    pexiwbear2;           /* 0x.dcc - PCI Express inbound window base extended address register 2 */
+       __be32 __iomem    pexiwar2;             /* 0x.dd0 - PCI Express inbound window attributes register 2 */
+       u8 __iomem    res18[12];
+       __be32 __iomem    pexitar1;             /* 0x.de0 - PCI Express inbound translation address register 2 */
+       u8 __iomem    res19[4];
+       __be32 __iomem    pexiwbar1;            /* 0x.de8 - PCI Express inbound window base address register 2 */
+       __be32 __iomem    pexiwbear1;           /* 0x.dec - PCI Express inbound window base extended address register 2 */
+       __be32 __iomem    pexiwar1;             /* 0x.df0 - PCI Express inbound window attributes register 2 */
+       u8 __iomem    res20[12];
+       __be32 __iomem    pex_err_dr;           /* 0x.e00 - PCI Express error detect register */
+       u8 __iomem    res21[4];
+       __be32 __iomem    pex_err_en;           /* 0x.e08 - PCI Express error interrupt enable register */
+       u8 __iomem    res22[4];
+       __be32 __iomem    pex_err_disr;         /* 0x.e10 - PCI Express error disable register */
+       u8 __iomem    res23[12];
+       __be32 __iomem    pex_err_cap_stat;     /* 0x.e20 - PCI Express error capture status register */
+       u8 __iomem    res24[4];
+       __be32 __iomem    pex_err_cap_r0;       /* 0x.e28 - PCI Express error capture register 0 */
+       __be32 __iomem    pex_err_cap_r1;       /* 0x.e2c - PCI Express error capture register 0 */
+       __be32 __iomem    pex_err_cap_r2;       /* 0x.e30 - PCI Express error capture register 0 */
+       __be32 __iomem    pex_err_cap_r3;       /* 0x.e34 - PCI Express error capture register 0 */
+};
+
+#endif /* __POWERPC_FSL_PCIE_H */
+#endif /* __KERNEL__ */
index d20f02927f7200a83812ad929c9317241718f7b3..8a123c71449fffd9315b085158f0e1a8d6f5795a 100644 (file)
@@ -52,7 +52,7 @@ phys_addr_t get_immrbase(void)
        soc = of_find_node_by_type(NULL, "soc");
        if (soc) {
                unsigned int size;
-               const void *prop = get_property(soc, "reg", &size);
+               const void *prop = of_get_property(soc, "reg", &size);
 
                if (prop)
                        immrbase = of_translate_address(soc, prop);
@@ -78,8 +78,8 @@ u32 get_brgfreq(void)
        node = of_find_node_by_type(NULL, "cpm");
        if (node) {
                unsigned int size;
-               const unsigned int *prop = get_property(node, "brg-frequency",
-                                       &size);
+               const unsigned int *prop = of_get_property(node,
+                                       "brg-frequency", &size);
 
                if (prop)
                        brgfreq = *prop;
@@ -103,8 +103,8 @@ u32 get_baudrate(void)
        node = of_find_node_by_type(NULL, "serial");
        if (node) {
                unsigned int size;
-               const unsigned int *prop = get_property(node, "current-speed",
-                               &size);
+               const unsigned int *prop = of_get_property(node,
+                               "current-speed", &size);
 
                if (prop)
                        fs_baudrate = *prop;
@@ -153,7 +153,8 @@ static int __init gfar_mdio_of_init(void)
                while ((child = of_get_next_child(np, child)) != NULL) {
                        int irq = irq_of_parse_and_map(child, 0);
                        if (irq != NO_IRQ) {
-                               const u32 *id = get_property(child, "reg", NULL);
+                               const u32 *id = of_get_property(child,
+                                                       "reg", NULL);
                                mdio_data.irq[*id] = irq;
                        }
                }
@@ -209,7 +210,7 @@ static int __init gfar_of_init(void)
 
                of_irq_to_resource(np, 0, &r[1]);
 
-               model = get_property(np, "model", NULL);
+               model = of_get_property(np, "model", NULL);
 
                /* If we aren't the FEC we have multiple interrupts */
                if (model && strcasecmp(model, "FEC")) {
@@ -253,7 +254,7 @@ static int __init gfar_of_init(void)
                            FSL_GIANFAR_DEV_HAS_VLAN |
                            FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
 
-               ph = get_property(np, "phy-handle", NULL);
+               ph = of_get_property(np, "phy-handle", NULL);
                phy = of_find_node_by_phandle(*ph);
 
                if (phy == NULL) {
@@ -263,7 +264,7 @@ static int __init gfar_of_init(void)
 
                mdio = of_get_parent(phy);
 
-               id = get_property(phy, "reg", NULL);
+               id = of_get_property(phy, "reg", NULL);
                ret = of_address_to_resource(mdio, 0, &res);
                if (ret) {
                        of_node_put(phy);
@@ -325,11 +326,11 @@ static int __init fsl_i2c_of_init(void)
                }
 
                i2c_data.device_flags = 0;
-               flags = get_property(np, "dfsrr", NULL);
+               flags = of_get_property(np, "dfsrr", NULL);
                if (flags)
                        i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
 
-               flags = get_property(np, "fsl5200-clocking", NULL);
+               flags = of_get_property(np, "fsl5200-clocking", NULL);
                if (flags)
                        i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
 
@@ -374,7 +375,7 @@ static int __init mpc83xx_wdt_init(void)
                goto nosoc;
        }
 
-       freq = get_property(soc, "bus-frequency", NULL);
+       freq = of_get_property(soc, "bus-frequency", NULL);
        if (!freq) {
                ret = -ENODEV;
                goto err;
@@ -466,15 +467,15 @@ static int __init fsl_usb_of_init(void)
 
                usb_data.operating_mode = FSL_USB2_MPH_HOST;
 
-               prop = get_property(np, "port0", NULL);
+               prop = of_get_property(np, "port0", NULL);
                if (prop)
                        usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
 
-               prop = get_property(np, "port1", NULL);
+               prop = of_get_property(np, "port1", NULL);
                if (prop)
                        usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
 
-               prop = get_property(np, "phy_type", NULL);
+               prop = of_get_property(np, "phy_type", NULL);
                usb_data.phy_mode = determine_usb_phy(prop);
 
                ret =
@@ -501,7 +502,7 @@ static int __init fsl_usb_of_init(void)
 
                of_irq_to_resource(np, 0, &r[1]);
 
-               prop = get_property(np, "dr_mode", NULL);
+               prop = of_get_property(np, "dr_mode", NULL);
 
                if (!prop || !strcmp(prop, "host")) {
                        usb_data.operating_mode = FSL_USB2_DR_HOST;
@@ -538,7 +539,7 @@ static int __init fsl_usb_of_init(void)
                        goto err;
                }
 
-               prop = get_property(np, "phy_type", NULL);
+               prop = of_get_property(np, "phy_type", NULL);
                usb_data.phy_mode = determine_usb_phy(prop);
 
                if (usb_dev_dr_host) {
@@ -633,7 +634,7 @@ static int __init fs_enet_of_init(void)
                        goto err;
                }
 
-               model = get_property(np, "model", NULL);
+               model = of_get_property(np, "model", NULL);
                if (model == NULL) {
                        ret = -ENODEV;
                        goto unreg;
@@ -643,7 +644,7 @@ static int __init fs_enet_of_init(void)
                if (mac_addr)
                        memcpy(fs_enet_data.macaddr, mac_addr, 6);
 
-               ph = get_property(np, "phy-handle", NULL);
+               ph = of_get_property(np, "phy-handle", NULL);
                phy = of_find_node_by_phandle(*ph);
 
                if (phy == NULL) {
@@ -651,12 +652,12 @@ static int __init fs_enet_of_init(void)
                        goto unreg;
                }
 
-               phy_addr = get_property(phy, "reg", NULL);
+               phy_addr = of_get_property(phy, "reg", NULL);
                fs_enet_data.phy_addr = *phy_addr;
 
-               phy_irq = get_property(phy, "interrupts", NULL);
+               phy_irq = of_get_property(phy, "interrupts", NULL);
 
-               id = get_property(np, "device-id", NULL);
+               id = of_get_property(np, "device-id", NULL);
                fs_enet_data.fs_no = *id;
                strcpy(fs_enet_data.fs_type, model);
 
@@ -668,8 +669,10 @@ static int __init fs_enet_of_init(void)
                         goto unreg;
                 }
 
-               fs_enet_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
-               fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
+               fs_enet_data.clk_rx = *((u32 *)of_get_property(np,
+                                               "rx-clock", NULL));
+               fs_enet_data.clk_tx = *((u32 *)of_get_property(np,
+                                               "tx-clock", NULL));
 
                if (strstr(model, "FCC")) {
                        int fcc_index = *id - 1;
@@ -690,7 +693,7 @@ static int __init fs_enet_of_init(void)
                        fs_enet_data.bus_id = (char*)&bus_id[(*id)];
                        fs_enet_data.init_ioports = init_fcc_ioports;
 
-                       mdio_bb_prop = get_property(phy, "bitbang", NULL);
+                       mdio_bb_prop = of_get_property(phy, "bitbang", NULL);
                        if (mdio_bb_prop) {
                                struct platform_device *fs_enet_mdio_bb_dev;
                                struct fs_mii_bb_platform_info fs_enet_mdio_bb_data;
@@ -796,10 +799,10 @@ static int __init cpm_uart_of_init(void)
                        goto err;
                }
 
-               id = get_property(np, "device-id", NULL);
+               id = of_get_property(np, "device-id", NULL);
                cpm_uart_data.fs_no = *id;
 
-               model = (char*)get_property(np, "model", NULL);
+               model = of_get_property(np, "model", NULL);
                strcpy(cpm_uart_data.fs_type, model);
 
                cpm_uart_data.uart_clk = ppc_proc_freq;
@@ -808,8 +811,10 @@ static int __init cpm_uart_of_init(void)
                cpm_uart_data.tx_buf_size = 32;
                cpm_uart_data.rx_num_fifo = 4;
                cpm_uart_data.rx_buf_size = 32;
-               cpm_uart_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
-               cpm_uart_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
+               cpm_uart_data.clk_rx = *((u32 *)of_get_property(np,
+                                               "rx-clock", NULL));
+               cpm_uart_data.clk_tx = *((u32 *)of_get_property(np,
+                                               "tx-clock", NULL));
 
                ret =
                    platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
@@ -833,7 +838,7 @@ arch_initcall(cpm_uart_of_init);
 #ifdef CONFIG_8xx
 
 extern void init_scc_ioports(struct fs_platform_info*);
-extern int platform_device_skip(char *model, int id);
+extern int platform_device_skip(const char *model, int id);
 
 static int __init fs_enet_mdio_of_init(void)
 {
@@ -900,21 +905,22 @@ static int __init fs_enet_of_init(void)
                struct resource r[4];
                struct device_node *phy = NULL, *mdio = NULL;
                struct fs_platform_info fs_enet_data;
-               unsigned int *id, *phy_addr;
+               const unsigned int *id;
+               const unsigned int *phy_addr;
                void *mac_addr;
-               phandle *ph;
-               char *model;
+               const phandle *ph;
+               const char *model;
 
                memset(r, 0, sizeof(r));
                memset(&fs_enet_data, 0, sizeof(fs_enet_data));
 
-               model = (char *)get_property(np, "model", NULL);
+               model = of_get_property(np, "model", NULL);
                if (model == NULL) {
                        ret = -ENODEV;
                        goto unreg;
                }
 
-               id = (u32 *) get_property(np, "device-id", NULL);
+               id = of_get_property(np, "device-id", NULL);
                fs_enet_data.fs_no = *id;
 
                if (platform_device_skip(model, *id))
@@ -929,12 +935,12 @@ static int __init fs_enet_of_init(void)
                if (mac_addr)
                        memcpy(fs_enet_data.macaddr, mac_addr, 6);
 
-               ph = (phandle *) get_property(np, "phy-handle", NULL);
+               ph = of_get_property(np, "phy-handle", NULL);
                if (ph != NULL)
                        phy = of_find_node_by_phandle(*ph);
 
                if (phy != NULL) {
-                       phy_addr = (u32 *) get_property(phy, "reg", NULL);
+                       phy_addr = of_get_property(phy, "reg", NULL);
                        fs_enet_data.phy_addr = *phy_addr;
                        fs_enet_data.has_phy = 1;
 
@@ -947,7 +953,7 @@ static int __init fs_enet_of_init(void)
                        }
                }
 
-               model = (char*)get_property(np, "model", NULL);
+               model = of_get_property(np, "model", NULL);
                strcpy(fs_enet_data.fs_type, model);
 
                if (strstr(model, "FEC")) {
@@ -1038,8 +1044,8 @@ static int __init cpm_smc_uart_of_init(void)
             i++) {
                struct resource r[3];
                struct fs_uart_platform_info cpm_uart_data;
-               int *id;
-               char *model;
+               const int *id;
+               const char *model;
 
                memset(r, 0, sizeof(r));
                memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
@@ -1066,10 +1072,10 @@ static int __init cpm_smc_uart_of_init(void)
                        goto err;
                }
 
-               model = (char*)get_property(np, "model", NULL);
+               model = of_get_property(np, "model", NULL);
                strcpy(cpm_uart_data.fs_type, model);
 
-               id = (int*)get_property(np, "device-id", NULL);
+               id = of_get_property(np, "device-id", NULL);
                cpm_uart_data.fs_no = *id;
                cpm_uart_data.uart_clk = ppc_proc_freq;
 
index bcfb900481f8fdb6180dc474ed991d1dc7dd164d..0b84b7c775d8c229ffe7289584810faf70d63710 100644 (file)
@@ -304,7 +304,7 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic)
        }
 }
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 
 /* Test if an interrupt is sourced from HyperTransport (used on broken U3s)
  * to force the edge setting on the MPIC and do the ack workaround.
@@ -476,7 +476,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
        }
 }
 
-#else /* CONFIG_MPIC_BROKEN_U3 */
+#else /* CONFIG_MPIC_U3_HT_IRQS */
 
 static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
 {
@@ -487,7 +487,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
 {
 }
 
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 
 #define mpic_irq_to_hw(virq)   ((unsigned int)irq_map[virq].hwirq)
@@ -615,7 +615,7 @@ static void mpic_end_irq(unsigned int irq)
        mpic_eoi(mpic);
 }
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 
 static void mpic_unmask_ht_irq(unsigned int irq)
 {
@@ -665,7 +665,7 @@ static void mpic_end_ht_irq(unsigned int irq)
                mpic_ht_end_irq(mpic, src);
        mpic_eoi(mpic);
 }
-#endif /* !CONFIG_MPIC_BROKEN_U3 */
+#endif /* !CONFIG_MPIC_U3_HT_IRQS */
 
 #ifdef CONFIG_SMP
 
@@ -788,7 +788,7 @@ static struct irq_chip mpic_ipi_chip = {
 };
 #endif /* CONFIG_SMP */
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 static struct irq_chip mpic_irq_ht_chip = {
        .startup        = mpic_startup_ht_irq,
        .shutdown       = mpic_shutdown_ht_irq,
@@ -797,7 +797,7 @@ static struct irq_chip mpic_irq_ht_chip = {
        .eoi            = mpic_end_ht_irq,
        .set_type       = mpic_set_irq_type,
 };
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 
 static int mpic_host_match(struct irq_host *h, struct device_node *node)
@@ -837,11 +837,11 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
        /* Default chip */
        chip = &mpic->hc_irq;
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
        /* Check for HT interrupts, override vecpri */
        if (mpic_is_ht_interrupt(mpic, hw))
                chip = &mpic->hc_ht_irq;
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
 
        DBG("mpic: mapping to irq chip @%p\n", chip);
 
@@ -937,12 +937,12 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->hc_irq.typename = name;
        if (flags & MPIC_PRIMARY)
                mpic->hc_irq.set_affinity = mpic_set_affinity;
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
        mpic->hc_ht_irq = mpic_irq_ht_chip;
        mpic->hc_ht_irq.typename = name;
        if (flags & MPIC_PRIMARY)
                mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 #ifdef CONFIG_SMP
        mpic->hc_ipi = mpic_ipi_chip;
@@ -970,7 +970,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->spurious_vec  = intvec_top;
 
        /* Check for "big-endian" in device-tree */
-       if (node && get_property(node, "big-endian", NULL) != NULL)
+       if (node && of_get_property(node, "big-endian", NULL) != NULL)
                mpic->flags |= MPIC_BIG_ENDIAN;
 
 
@@ -986,13 +986,13 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        BUG_ON(paddr == 0 && node == NULL);
 
        /* If no physical address passed in, check if it's dcr based */
-       if (paddr == 0 && get_property(node, "dcr-reg", NULL) != NULL)
+       if (paddr == 0 && of_get_property(node, "dcr-reg", NULL) != NULL)
                mpic->flags |= MPIC_USES_DCR;
 
 #ifdef CONFIG_PPC_DCR
        if (mpic->flags & MPIC_USES_DCR) {
                const u32 *dbasep;
-               dbasep = get_property(node, "dcr-reg", NULL);
+               dbasep = of_get_property(node, "dcr-reg", NULL);
                BUG_ON(dbasep == NULL);
                mpic->dcr_base = *dbasep;
                mpic->reg_type = mpic_access_dcr;
@@ -1006,7 +1006,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
         */
        if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) {
                const u32 *reg;
-               reg = get_property(node, "reg", NULL);
+               reg = of_get_property(node, "reg", NULL);
                BUG_ON(reg == NULL);
                paddr = of_translate_address(node, reg);
                BUG_ON(paddr == OF_BAD_ADDR);
@@ -1142,7 +1142,7 @@ void __init mpic_init(struct mpic *mpic)
 
        /* Do the HT PIC fixups on U3 broken mpic */
        DBG("MPIC flags: %x\n", mpic->flags);
-       if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
+       if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY))
                mpic_scan_ht_pics(mpic);
 
        for (i = 0; i < mpic->num_sources; i++) {
index a5282011d39e6b2f4bb0a31008cc4729cc3ce60c..85a7c99c1003682c10c4317a5f7f4888c0033c80 100644 (file)
@@ -33,7 +33,7 @@
 #include <asm/of_platform.h>
 #include <asm/io.h>
 #include <asm/pmi.h>
-
+#include <asm/prom.h>
 
 struct pmi_data {
        struct list_head        handler;
@@ -49,21 +49,6 @@ struct pmi_data {
 };
 
 
-
-static void __iomem *of_iomap(struct device_node *np)
-{
-       struct resource res;
-
-       if (of_address_to_resource(np, 0, &res))
-               return NULL;
-
-       pr_debug("Resource start: 0x%lx\n", res.start);
-       pr_debug("Resource end: 0x%lx\n", res.end);
-
-       return ioremap(res.start, 1 + res.end - res.start);
-}
-
-
 static int pmi_irq_handler(int irq, void *dev_id)
 {
        struct pmi_data *data;
@@ -118,6 +103,7 @@ out:
 
 static struct of_device_id pmi_match[] = {
        { .type = "ibm,pmi", .name = "ibm,pmi" },
+       { .type = "ibm,pmi" },
        {},
 };
 
@@ -153,7 +139,7 @@ static int pmi_of_probe(struct of_device *dev,
                goto out;
        }
 
-       data->pmi_reg = of_iomap(np);
+       data->pmi_reg = of_iomap(np, 0);
        if (!data->pmi_reg) {
                printk(KERN_ERR "pmi: invalid register address.\n");
                rc = -EFAULT;
@@ -279,6 +265,9 @@ void pmi_register_handler(struct of_device *device,
        struct pmi_data *data;
        data = device->dev.driver_data;
 
+       if (!data)
+               return;
+
        spin_lock(&data->handler_spinlock);
        list_add_tail(&handler->node, &data->handler);
        spin_unlock(&data->handler_spinlock);
@@ -289,10 +278,12 @@ void pmi_unregister_handler(struct of_device *device,
                            struct pmi_handler *handler)
 {
        struct pmi_data *data;
+       data = device->dev.driver_data;
 
-       pr_debug("pmi: unregistering handler %p\n", handler);
+       if (!data)
+               return;
 
-       data = device->dev.driver_data;
+       pr_debug("pmi: unregistering handler %p\n", handler);
 
        spin_lock(&data->handler_spinlock);
        list_del(&handler->node);
index a725e80befa8ef3644d34641533fa8e1bd7b3497..887739f3badc6a18ed203c9af86e25a4a9185368 100644 (file)
@@ -2,11 +2,8 @@
 # QE Communication options
 #
 
-menu "QE Options"
-       depends on QUICC_ENGINE
-
 config UCC_SLOW
-       bool "UCC Slow Protocols Support"
+       bool
        default n
        select UCC
        help
@@ -14,10 +11,9 @@ config UCC_SLOW
          protocols: UART, BISYNC, QMC
 
 config UCC_FAST
-       bool "UCC Fast Protocols Support"
+       bool
        default n
        select UCC
-       select UCC_SLOW
        help
          This option provides qe_lib support to UCC fast
          protocols: HDLC, Ethernet, ATM, transparent
@@ -26,5 +22,3 @@ config UCC
        bool
        default y if UCC_FAST || UCC_SLOW
 
-endmenu
-
index 43f6cc9d7ea0768068dd78de54e96cf7b037c8cc..7f4c0754396197bdc5bf571c698b7813ffd3b979 100644 (file)
@@ -71,7 +71,7 @@ phys_addr_t get_qe_base(void)
        qe = of_find_node_by_type(NULL, "qe");
        if (qe) {
                unsigned int size;
-               const void *prop = get_property(qe, "reg", &size);
+               const void *prop = of_get_property(qe, "reg", &size);
                qebase = of_translate_address(qe, prop);
                of_node_put(qe);
        };
@@ -158,7 +158,7 @@ unsigned int get_brg_clk(void)
        qe = of_find_node_by_type(NULL, "qe");
        if (qe) {
                unsigned int size;
-               const u32 *prop = get_property(qe, "brg-frequency", &size);
+               const u32 *prop = of_get_property(qe, "brg-frequency", &size);
                brg_clk = *prop;
                of_node_put(qe);
        };
index 0afe6bfe371455d90ba665bfcc57b9422159c471..e32b45bf9ff5364df15accd01b510f0f2721f5a7 100644 (file)
@@ -53,7 +53,7 @@ int par_io_init(struct device_node *np)
                return ret;
        par_io = ioremap(res.start, res.end - res.start + 1);
 
-       num_ports = get_property(np, "num-ports", NULL);
+       num_ports = of_get_property(np, "num-ports", NULL);
        if (num_ports)
                num_par_io_ports = *num_ports;
 
@@ -161,7 +161,7 @@ int par_io_of_config(struct device_node *np)
                return -1;
        }
 
-       ph = get_property(np, "pio-handle", NULL);
+       ph = of_get_property(np, "pio-handle", NULL);
        if (ph == 0) {
                printk(KERN_ERR "pio-handle not available \n");
                return -1;
@@ -169,7 +169,7 @@ int par_io_of_config(struct device_node *np)
 
        pio = of_find_node_by_phandle(*ph);
 
-       pio_map = get_property(pio, "pio-map", &pio_map_len);
+       pio_map = of_get_property(pio, "pio-map", &pio_map_len);
        if (pio_map == NULL) {
                printk(KERN_ERR "pio-map is not set! \n");
                return -1;
index a457ac1c663924b030c931cfd7a28c84801b2757..66137bf2dfb0ffb2c78a1613cd62079d6f447b38 100644 (file)
@@ -210,6 +210,9 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
        uf_regs = uccf->uf_regs;
        uccf->p_ucce = (u32 *) & (uf_regs->ucce);
        uccf->p_uccm = (u32 *) & (uf_regs->uccm);
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+       uccf->p_utodr = (u16 *) & (uf_regs->utodr);
+#endif
 #ifdef STATISTICS
        uccf->tx_frames = 0;
        uccf->rx_frames = 0;
index 817df73ecf56a8a9cf2810058e9e5e3a46ff7ce2..b930d686a4d18d1b06c5fe0915674f67492df900 100644 (file)
@@ -187,7 +187,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
        uccs->us_pram = qe_muram_addr(uccs->us_pram_offset);
 
        /* Init Guemr register */
-       if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->regs)))) {
+       if ((ret = ucc_init_guemr((struct ucc_common *) us_regs))) {
                printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__);
                ucc_slow_free(uccs);
                return ret;
@@ -195,7 +195,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
 
        /* Set UCC to slow type */
        if ((ret = ucc_set_type(us_info->ucc_num,
-                               (struct ucc_common *) (us_info->regs),
+                               (struct ucc_common *) us_regs,
                                UCC_SPEED_TYPE_SLOW))) {
                printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__);
                ucc_slow_free(uccs);
diff --git a/arch/powerpc/sysdev/timer.c b/arch/powerpc/sysdev/timer.c
new file mode 100644 (file)
index 0000000..4a01748
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Common code to keep time when machine suspends.
+ *
+ * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ */
+
+#include <linux/time.h>
+#include <linux/sysdev.h>
+#include <asm/rtc.h>
+
+static unsigned long suspend_rtc_time;
+
+/*
+ * Reset the time after a sleep.
+ */
+static int timer_resume(struct sys_device *dev)
+{
+       struct timeval tv;
+       struct timespec ts;
+       struct rtc_time cur_rtc_tm;
+       unsigned long cur_rtc_time, diff;
+
+       /* get current RTC time and convert to seconds */
+       get_rtc_time(&cur_rtc_tm);
+       rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time);
+
+       diff = cur_rtc_time - suspend_rtc_time;
+
+       /* adjust time of day by seconds that elapsed while
+        * we were suspended */
+       do_gettimeofday(&tv);
+       ts.tv_sec = tv.tv_sec + diff;
+       ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC;
+       do_settimeofday(&ts);
+
+       return 0;
+}
+
+static int timer_suspend(struct sys_device *dev, pm_message_t state)
+{
+       struct rtc_time suspend_rtc_tm;
+       WARN_ON(!ppc_md.get_rtc_time);
+
+       get_rtc_time(&suspend_rtc_tm);
+       rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time);
+
+       return 0;
+}
+
+static struct sysdev_class timer_sysclass = {
+       .resume = timer_resume,
+       .suspend = timer_suspend,
+       set_kset_name("timer"),
+};
+
+static struct sys_device device_timer = {
+       .id = 0,
+       .cls = &timer_sysclass,
+};
+
+static int time_init_device(void)
+{
+       int error = sysdev_class_register(&timer_sysclass);
+       if (!error)
+               error = sysdev_register(&device_timer);
+       return error;
+}
+
+device_initcall(time_init_device);
index 97f37ef4bbbf42e1c09d6bd535ebfb87e6c7f140..337039ee51e623acf3c8c940639886757e76ca12 100644 (file)
@@ -48,7 +48,7 @@ phys_addr_t get_csrbase(void)
        tsi = of_find_node_by_type(NULL, "tsi-bridge");
        if (tsi) {
                unsigned int size;
-               const void *prop = get_property(tsi, "reg", &size);
+               const void *prop = of_get_property(tsi, "reg", &size);
                tsi108_csr_base = of_translate_address(tsi, prop);
                of_node_put(tsi);
        };
@@ -77,10 +77,10 @@ static int __init tsi108_eth_of_init(void)
                struct resource r[2];
                struct device_node *phy;
                hw_info tsi_eth_data;
-               unsigned int *id;
-               unsigned int *phy_id;
+               const unsigned int *id;
+               const unsigned int *phy_id;
                const void *mac_addr;
-               phandle *ph;
+               const phandle *ph;
 
                memset(r, 0, sizeof(r));
                memset(&tsi_eth_data, 0, sizeof(tsi_eth_data));
@@ -107,10 +107,10 @@ static int __init tsi108_eth_of_init(void)
                        goto err;
                }
 
-               mac_addr = get_property(np, "address", NULL);
+               mac_addr = of_get_property(np, "address", NULL);
                memcpy(tsi_eth_data.mac_addr, mac_addr, 6);
 
-               ph = (phandle *) get_property(np, "phy-handle", NULL);
+               ph = of_get_property(np, "phy-handle", NULL);
                phy = of_find_node_by_phandle(*ph);
 
                if (phy == NULL) {
@@ -118,8 +118,8 @@ static int __init tsi108_eth_of_init(void)
                        goto unreg;
                }
 
-               id = (u32 *) get_property(phy, "reg", NULL);
-               phy_id = (u32 *) get_property(phy, "phy-id", NULL);
+               id = of_get_property(phy, "reg", NULL);
+               phy_id = of_get_property(phy, "phy-id", NULL);
                ret = of_address_to_resource(phy, 0, &res);
                if (ret) {
                        of_node_put(phy);
index ae249c6bbbcf3473920933b9aa7113718942321d..58b9e7f8abf276b51406b0ddf421f6a0bd415836 100644 (file)
@@ -211,7 +211,7 @@ int __init tsi108_setup_pci(struct device_node *dev)
        has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
 
        /* Get bus range if any */
-       bus_range = get_property(dev, "bus-range", &len);
+       bus_range = of_get_property(dev, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                printk(KERN_WARNING "Can't get bus-range for %s, assume"
                       " bus 0\n", dev->full_name);
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
new file mode 100644 (file)
index 0000000..968fb40
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * arch/powerpc/sysdev/uic.c
+ *
+ * IBM PowerPC 4xx Universal Interrupt Controller
+ *
+ * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/sysdev.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/dcr.h>
+
+#define NR_UIC_INTS    32
+
+#define UIC_SR         0x0
+#define UIC_ER         0x2
+#define UIC_CR         0x3
+#define UIC_PR         0x4
+#define UIC_TR         0x5
+#define UIC_MSR                0x6
+#define UIC_VR         0x7
+#define UIC_VCR                0x8
+
+#define uic_irq_to_hw(virq)    (irq_map[virq].hwirq)
+
+struct uic *primary_uic;
+
+struct uic {
+       int index;
+       int dcrbase;
+
+       spinlock_t lock;
+
+       /* The remapper for this UIC */
+       struct irq_host *irqhost;
+
+       /* For secondary UICs, the cascade interrupt's irqaction */
+       struct irqaction cascade;
+
+       /* The device node of the interrupt controller */
+       struct device_node *of_node;
+};
+
+static void uic_unmask_irq(unsigned int virq)
+{
+       struct uic *uic = get_irq_chip_data(virq);
+       unsigned int src = uic_irq_to_hw(virq);
+       unsigned long flags;
+       u32 er;
+
+       spin_lock_irqsave(&uic->lock, flags);
+       er = mfdcr(uic->dcrbase + UIC_ER);
+       er |= 1 << (31 - src);
+       mtdcr(uic->dcrbase + UIC_ER, er);
+       spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static void uic_mask_irq(unsigned int virq)
+{
+       struct uic *uic = get_irq_chip_data(virq);
+       unsigned int src = uic_irq_to_hw(virq);
+       unsigned long flags;
+       u32 er;
+
+       spin_lock_irqsave(&uic->lock, flags);
+       er = mfdcr(uic->dcrbase + UIC_ER);
+       er &= ~(1 << (31 - src));
+       mtdcr(uic->dcrbase + UIC_ER, er);
+       spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static void uic_ack_irq(unsigned int virq)
+{
+       struct uic *uic = get_irq_chip_data(virq);
+       unsigned int src = uic_irq_to_hw(virq);
+       unsigned long flags;
+
+       spin_lock_irqsave(&uic->lock, flags);
+       mtdcr(uic->dcrbase + UIC_SR, 1 << (31-src));
+       spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
+{
+       struct uic *uic = get_irq_chip_data(virq);
+       unsigned int src = uic_irq_to_hw(virq);
+       struct irq_desc *desc = get_irq_desc(virq);
+       unsigned long flags;
+       int trigger, polarity;
+       u32 tr, pr, mask;
+
+       switch (flow_type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_NONE:
+               uic_mask_irq(virq);
+               return 0;
+
+       case IRQ_TYPE_EDGE_RISING:
+               trigger = 1; polarity = 1;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               trigger = 1; polarity = 0;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               trigger = 0; polarity = 1;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               trigger = 0; polarity = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mask = ~(1 << (31 - src));
+
+       spin_lock_irqsave(&uic->lock, flags);
+       tr = mfdcr(uic->dcrbase + UIC_TR);
+       pr = mfdcr(uic->dcrbase + UIC_PR);
+       tr = (tr & mask) | (trigger << (31-src));
+       pr = (pr & mask) | (polarity << (31-src));
+
+       mtdcr(uic->dcrbase + UIC_PR, pr);
+       mtdcr(uic->dcrbase + UIC_TR, tr);
+
+       desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+       desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+       if (trigger)
+               desc->status |= IRQ_LEVEL;
+
+       spin_unlock_irqrestore(&uic->lock, flags);
+
+       return 0;
+}
+
+static struct irq_chip uic_irq_chip = {
+       .typename       = " UIC  ",
+       .unmask         = uic_unmask_irq,
+       .mask           = uic_mask_irq,
+/*     .mask_ack       = uic_mask_irq_and_ack, */
+       .ack            = uic_ack_irq,
+       .set_type       = uic_set_irq_type,
+};
+
+static int uic_host_match(struct irq_host *h, struct device_node *node)
+{
+       struct uic *uic = h->host_data;
+       return uic->of_node == node;
+}
+
+static int uic_host_map(struct irq_host *h, unsigned int virq,
+                       irq_hw_number_t hw)
+{
+       struct uic *uic = h->host_data;
+
+       set_irq_chip_data(virq, uic);
+       /* Despite the name, handle_level_irq() works for both level
+        * and edge irqs on UIC.  FIXME: check this is correct */
+       set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq);
+
+       /* Set default irq type */
+       set_irq_type(virq, IRQ_TYPE_NONE);
+
+       return 0;
+}
+
+static int uic_host_xlate(struct irq_host *h, struct device_node *ct,
+                         u32 *intspec, unsigned int intsize,
+                         irq_hw_number_t *out_hwirq, unsigned int *out_type)
+
+{
+       /* UIC intspecs must have 2 cells */
+       BUG_ON(intsize != 2);
+       *out_hwirq = intspec[0];
+       *out_type = intspec[1];
+       return 0;
+}
+
+static struct irq_host_ops uic_host_ops = {
+       .match  = uic_host_match,
+       .map    = uic_host_map,
+       .xlate  = uic_host_xlate,
+};
+
+irqreturn_t uic_cascade(int virq, void *data)
+{
+       struct uic *uic = data;
+       u32 msr;
+       int src;
+       int subvirq;
+
+       msr = mfdcr(uic->dcrbase + UIC_MSR);
+       src = 32 - ffs(msr);
+
+       subvirq = irq_linear_revmap(uic->irqhost, src);
+       generic_handle_irq(subvirq);
+
+       return IRQ_HANDLED;
+}
+
+static struct uic * __init uic_init_one(struct device_node *node)
+{
+       struct uic *uic;
+       const u32 *indexp, *dcrreg;
+       int len;
+
+       BUG_ON(! device_is_compatible(node, "ibm,uic"));
+
+       uic = alloc_bootmem(sizeof(*uic));
+       if (! uic)
+               return NULL; /* FIXME: panic? */
+
+       memset(uic, 0, sizeof(*uic));
+       spin_lock_init(&uic->lock);
+       uic->of_node = of_node_get(node);
+       indexp = of_get_property(node, "cell-index", &len);
+       if (!indexp || (len != sizeof(u32))) {
+               printk(KERN_ERR "uic: Device node %s has missing or invalid "
+                      "cell-index property\n", node->full_name);
+               return NULL;
+       }
+       uic->index = *indexp;
+
+       dcrreg = of_get_property(node, "dcr-reg", &len);
+       if (!dcrreg || (len != 2*sizeof(u32))) {
+               printk(KERN_ERR "uic: Device node %s has missing or invalid "
+                      "dcr-reg property\n", node->full_name);
+               return NULL;
+       }
+       uic->dcrbase = *dcrreg;
+
+       uic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_UIC_INTS,
+                                     &uic_host_ops, -1);
+       if (! uic->irqhost) {
+               of_node_put(node);
+               return NULL; /* FIXME: panic? */
+       }
+
+       uic->irqhost->host_data = uic;
+
+       /* Start with all interrupts disabled, level and non-critical */
+       mtdcr(uic->dcrbase + UIC_ER, 0);
+       mtdcr(uic->dcrbase + UIC_CR, 0);
+       mtdcr(uic->dcrbase + UIC_TR, 0);
+       /* Clear any pending interrupts, in case the firmware left some */
+       mtdcr(uic->dcrbase + UIC_SR, 0xffffffff);
+
+       printk ("UIC%d (%d IRQ sources) at DCR 0x%x\n", uic->index,
+               NR_UIC_INTS, uic->dcrbase);
+
+       return uic;
+}
+
+void __init uic_init_tree(void)
+{
+       struct device_node *np;
+       struct uic *uic;
+       const u32 *interrupts;
+
+       /* First locate and initialize the top-level UIC */
+
+       np = of_find_compatible_node(NULL, NULL, "ibm,uic");
+       while (np) {
+               interrupts = of_get_property(np, "interrupts", NULL);
+               if (! interrupts)
+                       break;
+
+               np = of_find_compatible_node(np, NULL, "ibm,uic");
+       }
+
+       BUG_ON(!np); /* uic_init_tree() assumes there's a UIC as the
+                     * top-level interrupt controller */
+       primary_uic = uic_init_one(np);
+       if (! primary_uic)
+               panic("Unable to initialize primary UIC %s\n", np->full_name);
+
+       irq_set_default_host(primary_uic->irqhost);
+       of_node_put(np);
+
+       /* The scan again for cascaded UICs */
+       np = of_find_compatible_node(NULL, NULL, "ibm,uic");
+       while (np) {
+               interrupts = of_get_property(np, "interrupts", NULL);
+               if (interrupts) {
+                       /* Secondary UIC */
+                       int cascade_virq;
+                       int ret;
+
+                       uic = uic_init_one(np);
+                       if (! uic)
+                               panic("Unable to initialize a secondary UIC %s\n",
+                                     np->full_name);
+
+                       cascade_virq = irq_of_parse_and_map(np, 0);
+
+                       uic->cascade.handler = uic_cascade;
+                       uic->cascade.name = "UIC cascade";
+                       uic->cascade.dev_id = uic;
+
+                       ret = setup_irq(cascade_virq, &uic->cascade);
+                       if (ret)
+                               printk(KERN_ERR "Failed to setup_irq(%d) for "
+                                      "UIC%d cascade\n", cascade_virq,
+                                      uic->index);
+
+                       /* FIXME: setup critical cascade?? */
+               }
+
+               np = of_find_compatible_node(np, NULL, "ibm,uic");
+       }
+}
+
+/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+unsigned int uic_get_irq(void)
+{
+       u32 msr;
+       int src;
+
+       BUG_ON(! primary_uic);
+
+       msr = mfdcr(primary_uic->dcrbase + UIC_MSR);
+       src = 32 - ffs(msr);
+
+       return irq_linear_revmap(primary_uic->irqhost, src);
+}
index bf299b66f3fc6c0198b0f88110ea718915251769..b481db1dacb4a7b3f2c35e49a0789612bbc591a7 100644 (file)
@@ -330,18 +330,17 @@ static void release_output_lock(void)
 static int xmon_core(struct pt_regs *regs, int fromipi)
 {
        int cmd = 0;
-       unsigned long msr;
        struct bpt *bp;
        long recurse_jmp[JMP_BUF_LEN];
        unsigned long offset;
+       unsigned long flags;
 #ifdef CONFIG_SMP
        int cpu;
        int secondary;
        unsigned long timeout;
 #endif
 
-       msr = mfmsr();
-       mtmsr(msr & ~MSR_EE);   /* disable interrupts */
+       local_irq_save(flags);
 
        bp = in_breakpoint_table(regs->nip, &offset);
        if (bp != NULL) {
@@ -516,7 +515,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
 
        insert_cpu_bpts();
 
-       mtmsr(msr);             /* restore interrupt enable */
+       local_irq_restore(flags);
 
        return cmd != 'X' && cmd != EOF;
 }
@@ -1360,8 +1359,12 @@ static void print_bug_trap(struct pt_regs *regs)
        if (is_warning_bug(bug))
                return;
 
+#ifdef CONFIG_DEBUG_BUGVERBOSE
        printf("kernel BUG at %s:%u!\n",
               bug->file, bug->line);
+#else
+       printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
+#endif
 }
 
 void excprint(struct pt_regs *fp)
index 57dacf978532f6cbbf43d0a9ebee0dc81a8ef7e5..c623e44f01ad253477e7cac3f5a5db0ee03831f3 100644 (file)
@@ -74,10 +74,6 @@ config ENET_BIG_BUFFERS
          Allocate large buffers for MPC8xx Ethernet. Increases throughput
          and decreases the likelihood of dropped packets, but costs memory.
 
-config HTDMSOUND
-       bool "Embedded Planet HIOX Audio"
-       depends on SOUND=y
-
 # This doesn't really belong here, but it is convenient to ask
 # 8xx specific questions.
 comment "Generic MPC8xx Options"
index d8760181fe9921c2b2d1ce2aeacfc8b6059290d1..1051a06df7e04b96a41d00ffd6e168f1052ed660 100644 (file)
@@ -7,4 +7,3 @@ obj-y                   := commproc.o
 obj-$(CONFIG_FEC_ENET) += fec.o
 obj-$(CONFIG_SCC_ENET) += enet.o
 obj-$(CONFIG_UCODE_PATCH) += micropatch.o
-obj-$(CONFIG_HTDMSOUND) += cs4218_tdm.o
diff --git a/arch/ppc/8xx_io/cs4218.h b/arch/ppc/8xx_io/cs4218.h
deleted file mode 100644 (file)
index e5f9430..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef _cs4218_h_
-/*
- *  Hacked version of linux/drivers/sound/dmasound/dmasound.h
- *
- *
- *  Minor numbers for the sound driver.
- *
- *  Unfortunately Creative called the codec chip of SB as a DSP. For this
- *  reason the /dev/dsp is reserved for digitized audio use. There is a
- *  device for true DSP processors but it will be called something else.
- *  In v3.0 it's /dev/sndproc but this could be a temporary solution.
- */
-#define _cs4218_h_
-
-#include <linux/types.h>
-
-#define SND_NDEVS      256     /* Number of supported devices */
-#define SND_DEV_CTL    0       /* Control port /dev/mixer */
-#define SND_DEV_SEQ    1       /* Sequencer output /dev/sequencer (FM
-                                  synthesizer and MIDI output) */
-#define SND_DEV_MIDIN  2       /* Raw midi access */
-#define SND_DEV_DSP    3       /* Digitized voice /dev/dsp */
-#define SND_DEV_AUDIO  4       /* Sparc compatible /dev/audio */
-#define SND_DEV_DSP16  5       /* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS 6       /* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2   8       /* /dev/sequencer, level 2 interface */
-#define SND_DEV_SNDPROC 9      /* /dev/sndproc for programmable devices */
-#define SND_DEV_PSS    SND_DEV_SNDPROC
-
-/* switch on various prinks */
-#define DEBUG_DMASOUND 1
-
-#define MAX_AUDIO_DEV  5
-#define MAX_MIXER_DEV  4
-#define MAX_SYNTH_DEV  3
-#define MAX_MIDI_DEV   6
-#define MAX_TIMER_DEV  3
-
-#define MAX_CATCH_RADIUS       10
-
-#define le2be16(x)     (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x)  (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
-       do { int error = get_user(ret, (int *)(arg)); \
-               if (error) return error; \
-       } while (0)
-#define IOCTL_OUT(arg, ret)    ioctl_return((int *)(arg), ret)
-
-static inline int ioctl_return(int *addr, int value)
-{
-       return value < 0 ? value : put_user(value, addr);
-}
-
-#define HAS_RECORD
-
-    /*
-     *  Initialization
-     */
-
-/* description of the set-up applies to either hard or soft settings */
-
-typedef struct {
-    int format;                /* AFMT_* */
-    int stereo;                /* 0 = mono, 1 = stereo */
-    int size;          /* 8/16 bit*/
-    int speed;         /* speed */
-} SETTINGS;
-
-    /*
-     *  Machine definitions
-     */
-
-typedef struct {
-    const char *name;
-    const char *name2;
-    void (*open)(void);
-    void (*release)(void);
-    void *(*dma_alloc)(unsigned int, gfp_t);
-    void (*dma_free)(void *, unsigned int);
-    int (*irqinit)(void);
-#ifdef MODULE
-    void (*irqcleanup)(void);
-#endif
-    void (*init)(void);
-    void (*silence)(void);
-    int (*setFormat)(int);
-    int (*setVolume)(int);
-    int (*setBass)(int);
-    int (*setTreble)(int);
-    int (*setGain)(int);
-    void (*play)(void);
-    void (*record)(void);              /* optional */
-    void (*mixer_init)(void);          /* optional */
-    int (*mixer_ioctl)(u_int, u_long); /* optional */
-    int (*write_sq_setup)(void);       /* optional */
-    int (*read_sq_setup)(void);                /* optional */
-    int (*sq_open)(mode_t);            /* optional */
-    int (*state_info)(char *, size_t); /* optional */
-    void (*abort_read)(void);          /* optional */
-    int min_dsp_speed;
-    int max_dsp_speed;
-    int version ;
-    int hardware_afmts ;               /* OSS says we only return h'ware info */
-                                       /* when queried via SNDCTL_DSP_GETFMTS */
-    int capabilities ;         /* low-level reply to SNDCTL_DSP_GETCAPS */
-    SETTINGS default_hard ;    /* open() or init() should set something valid */
-    SETTINGS default_soft ;    /* you can make it look like old OSS, if you want to */
-} MACHINE;
-
-    /*
-     *  Low level stuff
-     */
-
-typedef struct {
-    ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-} TRANS;
-
-
-    /*
-     * Sound queue stuff, the heart of the driver
-     */
-
-struct sound_queue {
-    /* buffers allocated for this queue */
-    int numBufs;               /* real limits on what the user can have */
-    int bufSize;               /* in bytes */
-    char **buffers;
-
-    /* current parameters */
-    int locked ;               /* params cannot be modified when != 0 */
-    int user_frags ;           /* user requests this many */
-    int user_frag_size ;       /* of this size */
-    int max_count;             /* actual # fragments <= numBufs */
-    int block_size;            /* internal block size in bytes */
-    int max_active;            /* in-use fragments <= max_count */
-
-    /* it shouldn't be necessary to declare any of these volatile */
-    int front, rear, count;
-    int rear_size;
-    /*
-     * The use of the playing field depends on the hardware
-     *
-     * Atari, PMac: The number of frames that are loaded/playing
-     *
-     * Amiga: Bit 0 is set: a frame is loaded
-     *        Bit 1 is set: a frame is playing
-     */
-    int active;
-    wait_queue_head_t action_queue, open_queue, sync_queue;
-    int open_mode;
-    int busy, syncing, xruns, died;
-};
-
-#define SLEEP(queue)           interruptible_sleep_on_timeout(&queue, HZ)
-#define WAKE_UP(queue)         (wake_up_interruptible(&queue))
-
-#endif /* _cs4218_h_ */
diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
deleted file mode 100644 (file)
index a956f28..0000000
+++ /dev/null
@@ -1,2833 +0,0 @@
-
-/* This is a modified version of linux/drivers/sound/dmasound.c to
- * support the CS4218 codec on the 8xx TDM port.  Thanks to everyone
- * that contributed to the dmasound software (which includes me :-).
- *
- * The CS4218 is configured in Mode 4, sub-mode 0.  This provides
- * left/right data only on the TDM port, as a 32-bit word, per frame
- * pulse.  The control of the CS4218 is provided by some other means,
- * like the SPI port.
- * Dan Malek (dmalek@jlc.net)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/sound.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-/* Should probably do something different with this path name.....
- * Actually, I should just stop using it...
- */
-#include "cs4218.h"
-#include <linux/soundcard.h>
-
-#include <asm/mpc8xx.h>
-#include <asm/8xx_immap.h>
-#include <asm/commproc.h>
-
-#define DMASND_CS4218          5
-
-#define MAX_CATCH_RADIUS       10
-#define MIN_BUFFERS            4
-#define MIN_BUFSIZE            4
-#define MAX_BUFSIZE            128
-
-#define HAS_8BIT_TABLES
-
-static int sq_unit = -1;
-static int mixer_unit = -1;
-static int state_unit = -1;
-static int irq_installed = 0;
-static char **sound_buffers = NULL;
-static char **sound_read_buffers = NULL;
-
-static DEFINE_SPINLOCK(cs4218_lock);
-
-/* Local copies of things we put in the control register.  Output
- * volume, like most codecs is really attenuation.
- */
-static int cs4218_rate_index;
-
-/*
- * Stuff for outputting a beep.  The values range from -327 to +327
- * so we can multiply by an amplitude in the range 0..100 to get a
- * signed short value to put in the output buffer.
- */
-static short beep_wform[256] = {
-       0,      40,     79,     117,    153,    187,    218,    245,
-       269,    288,    304,    316,    323,    327,    327,    324,
-       318,    310,    299,    288,    275,    262,    249,    236,
-       224,    213,    204,    196,    190,    186,    183,    182,
-       182,    183,    186,    189,    192,    196,    200,    203,
-       206,    208,    209,    209,    209,    207,    204,    201,
-       197,    193,    188,    183,    179,    174,    170,    166,
-       163,    161,    160,    159,    159,    160,    161,    162,
-       164,    166,    168,    169,    171,    171,    171,    170,
-       169,    167,    163,    159,    155,    150,    144,    139,
-       133,    128,    122,    117,    113,    110,    107,    105,
-       103,    103,    103,    103,    104,    104,    105,    105,
-       105,    103,    101,    97,     92,     86,     78,     68,
-       58,     45,     32,     18,     3,      -11,    -26,    -41,
-       -55,    -68,    -79,    -88,    -95,    -100,   -102,   -102,
-       -99,    -93,    -85,    -75,    -62,    -48,    -33,    -16,
-       0,      16,     33,     48,     62,     75,     85,     93,
-       99,     102,    102,    100,    95,     88,     79,     68,
-       55,     41,     26,     11,     -3,     -18,    -32,    -45,
-       -58,    -68,    -78,    -86,    -92,    -97,    -101,   -103,
-       -105,   -105,   -105,   -104,   -104,   -103,   -103,   -103,
-       -103,   -105,   -107,   -110,   -113,   -117,   -122,   -128,
-       -133,   -139,   -144,   -150,   -155,   -159,   -163,   -167,
-       -169,   -170,   -171,   -171,   -171,   -169,   -168,   -166,
-       -164,   -162,   -161,   -160,   -159,   -159,   -160,   -161,
-       -163,   -166,   -170,   -174,   -179,   -183,   -188,   -193,
-       -197,   -201,   -204,   -207,   -209,   -209,   -209,   -208,
-       -206,   -203,   -200,   -196,   -192,   -189,   -186,   -183,
-       -182,   -182,   -183,   -186,   -190,   -196,   -204,   -213,
-       -224,   -236,   -249,   -262,   -275,   -288,   -299,   -310,
-       -318,   -324,   -327,   -327,   -323,   -316,   -304,   -288,
-       -269,   -245,   -218,   -187,   -153,   -117,   -79,    -40,
-};
-
-#define BEEP_SPEED     5       /* 22050 Hz sample rate */
-#define BEEP_BUFLEN    512
-#define BEEP_VOLUME    15      /* 0 - 100 */
-
-static int beep_volume = BEEP_VOLUME;
-static int beep_playing = 0;
-static int beep_state = 0;
-static short *beep_buf;
-static void (*orig_mksound)(unsigned int, unsigned int);
-
-/* This is found someplace else......I guess in the keyboard driver
- * we don't include.
- */
-static void (*kd_mksound)(unsigned int, unsigned int);
-
-static int catchRadius = 0;
-static int numBufs = 4, bufSize = 32;
-static int numReadBufs = 4, readbufSize = 32;
-
-
-/* TDM/Serial transmit and receive buffer descriptors.
-*/
-static volatile cbd_t  *rx_base, *rx_cur, *tx_base, *tx_cur;
-
-module_param(catchRadius, int, 0);
-module_param(numBufs, int, 0);
-module_param(bufSize, int, 0);
-module_param(numreadBufs, int, 0);
-module_param(readbufSize, int, 0);
-
-#define arraysize(x)   (sizeof(x)/sizeof(*(x)))
-#define le2be16(x)     (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x)  (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
-       do { int error = get_user(ret, (int *)(arg)); \
-               if (error) return error; \
-       } while (0)
-#define IOCTL_OUT(arg, ret)    ioctl_return((int *)(arg), ret)
-
-/* CS4218 serial port control in mode 4.
-*/
-#define CS_INTMASK     ((uint)0x40000000)
-#define CS_DO1         ((uint)0x20000000)
-#define CS_LATTEN      ((uint)0x1f000000)
-#define CS_RATTEN      ((uint)0x00f80000)
-#define CS_MUTE                ((uint)0x00040000)
-#define CS_ISL         ((uint)0x00020000)
-#define CS_ISR         ((uint)0x00010000)
-#define CS_LGAIN       ((uint)0x0000f000)
-#define CS_RGAIN       ((uint)0x00000f00)
-
-#define CS_LATTEN_SET(X)       (((X) & 0x1f) << 24)
-#define CS_RATTEN_SET(X)       (((X) & 0x1f) << 19)
-#define CS_LGAIN_SET(X)                (((X) & 0x0f) << 12)
-#define CS_RGAIN_SET(X)                (((X) & 0x0f) << 8)
-
-#define CS_LATTEN_GET(X)       (((X) >> 24) & 0x1f)
-#define CS_RATTEN_GET(X)       (((X) >> 19) & 0x1f)
-#define CS_LGAIN_GET(X)                (((X) >> 12) & 0x0f)
-#define CS_RGAIN_GET(X)                (((X) >> 8) & 0x0f)
-
-/* The control register is effectively write only.  We have to keep a copy
- * of what we write.
- */
-static uint    cs4218_control;
-
-/* A place to store expanding information.
-*/
-static int     expand_bal;
-static int     expand_data;
-
-/* Since I can't make the microcode patch work for the SPI, I just
- * clock the bits using software.
- */
-static void    sw_spi_init(void);
-static void    sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt);
-static uint    cs4218_ctl_write(uint ctlreg);
-
-/*** Some low level helpers **************************************************/
-
-/* 16 bit mu-law */
-
-static short ulaw2dma16[] = {
-       -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
-       -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
-       -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
-       -11900, -11388, -10876, -10364, -9852,  -9340,  -8828,  -8316,
-       -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
-       -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
-       -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
-       -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
-       -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
-       -1372,  -1308,  -1244,  -1180,  -1116,  -1052,  -988,   -924,
-       -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
-       -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
-       -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
-       -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
-       -120,   -112,   -104,   -96,    -88,    -80,    -72,    -64,
-       -56,    -48,    -40,    -32,    -24,    -16,    -8,     0,
-       32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
-       23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
-       15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
-       11900,  11388,  10876,  10364,  9852,   9340,   8828,   8316,
-       7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
-       5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
-       3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
-       2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
-       1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
-       1372,   1308,   1244,   1180,   1116,   1052,   988,    924,
-       876,    844,    812,    780,    748,    716,    684,    652,
-       620,    588,    556,    524,    492,    460,    428,    396,
-       372,    356,    340,    324,    308,    292,    276,    260,
-       244,    228,    212,    196,    180,    164,    148,    132,
-       120,    112,    104,    96,     88,     80,     72,     64,
-       56,     48,     40,     32,     24,     16,     8,      0,
-};
-
-/* 16 bit A-law */
-
-static short alaw2dma16[] = {
-       -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
-       -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
-       -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
-       -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
-       -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
-       -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
-       -11008, -10496, -12032, -11520, -8960,  -8448,  -9984,  -9472,
-       -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
-       -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
-       -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
-       -88,    -72,    -120,   -104,   -24,    -8,     -56,    -40,
-       -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
-       -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
-       -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
-       -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
-       -944,   -912,   -1008,  -976,   -816,   -784,   -880,   -848,
-       5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
-       7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
-       2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
-       3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
-       22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
-       30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
-       11008,  10496,  12032,  11520,  8960,   8448,   9984,   9472,
-       15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
-       344,    328,    376,    360,    280,    264,    312,    296,
-       472,    456,    504,    488,    408,    392,    440,    424,
-       88,     72,     120,    104,    24,     8,      56,     40,
-       216,    200,    248,    232,    152,    136,    184,    168,
-       1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
-       1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
-       688,    656,    752,    720,    560,    528,    624,    592,
-       944,    912,    1008,   976,    816,    784,    880,    848,
-};
-
-
-/*** Translations ************************************************************/
-
-
-static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft);
-static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount,
-                         u_char frame[], ssize_t *frameUsed,
-                         ssize_t frameLeft);
-static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount,
-                         u_char frame[], ssize_t *frameUsed,
-                         ssize_t frameLeft);
-static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft);
-static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft);
-static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount,
-                           u_char frame[], ssize_t *frameUsed,
-                           ssize_t frameLeft);
-static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft);
-static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft);
-static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount,
-                           u_char frame[], ssize_t *frameUsed,
-                           ssize_t frameLeft);
-static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount,
-                           u_char frame[], ssize_t *frameUsed,
-                           ssize_t frameLeft);
-static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft);
-static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft);
-
-
-/*** Low level stuff *********************************************************/
-
-struct cs_sound_settings {
-       MACHINE mach;           /* machine dependent things */
-       SETTINGS hard;          /* hardware settings */
-       SETTINGS soft;          /* software settings */
-       SETTINGS dsp;           /* /dev/dsp default settings */
-       TRANS *trans_write;     /* supported translations for playback */
-       TRANS *trans_read;      /* supported translations for record */
-       int volume_left;        /* volume (range is machine dependent) */
-       int volume_right;
-       int bass;               /* tone (range is machine dependent) */
-       int treble;
-       int gain;
-       int minDev;             /* minor device number currently open */
-};
-
-static struct cs_sound_settings sound;
-
-static void *CS_Alloc(unsigned int size, gfp_t flags);
-static void CS_Free(void *ptr, unsigned int size);
-static int CS_IrqInit(void);
-#ifdef MODULE
-static void CS_IrqCleanup(void);
-#endif /* MODULE */
-static void CS_Silence(void);
-static void CS_Init(void);
-static void CS_Play(void);
-static void CS_Record(void);
-static int CS_SetFormat(int format);
-static int CS_SetVolume(int volume);
-static void cs4218_tdm_tx_intr(void *devid);
-static void cs4218_tdm_rx_intr(void *devid);
-static void cs4218_intr(void *devid);
-static int cs_get_volume(uint reg);
-static int cs_volume_setter(int volume, int mute);
-static int cs_get_gain(uint reg);
-static int cs_set_gain(int gain);
-static void cs_mksound(unsigned int hz, unsigned int ticks);
-static void cs_nosound(unsigned long xx);
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void);
-static void sound_init(void);
-static int sound_set_format(int format);
-static int sound_set_speed(int speed);
-static int sound_set_stereo(int stereo);
-static int sound_set_volume(int volume);
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
-                                   size_t userCount,
-                                   u_char frame[], ssize_t *frameUsed,
-                                   ssize_t frameLeft);
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
-                                   size_t userCount,
-                                   u_char frame[], ssize_t *frameUsed,
-                                   ssize_t frameLeft);
-
-
-/*
- * /dev/mixer abstraction
- */
-
-struct sound_mixer {
-    int busy;
-    int modify_counter;
-};
-
-static struct sound_mixer mixer;
-
-static struct sound_queue sq;
-static struct sound_queue read_sq;
-
-#define sq_block_address(i)    (sq.buffers[i])
-#define SIGNAL_RECEIVED        (signal_pending(current))
-#define NON_BLOCKING(open_mode)        (open_mode & O_NONBLOCK)
-#define ONE_SECOND     HZ      /* in jiffies (100ths of a second) */
-#define NO_TIME_LIMIT  0xffffffff
-
-/*
- * /dev/sndstat
- */
-
-struct sound_state {
-       int busy;
-       char buf[512];
-       int len, ptr;
-};
-
-static struct sound_state state;
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig);
-
-/*** Config & Setup **********************************************************/
-
-void dmasound_setup(char *str, int *ints);
-
-/*** Translations ************************************************************/
-
-
-/* ++TeSche: radically changed for new expanding purposes...
- *
- * These two routines now deal with copying/expanding/translating the samples
- * from user space into our buffer at the right frequency. They take care about
- * how much data there's actually to read, how much buffer space there is and
- * to convert samples into the right frequency/encoding. They will only work on
- * complete samples so it may happen they leave some bytes in the input stream
- * if the user didn't write a multiple of the current sample size. They both
- * return the number of bytes they've used from both streams so you may detect
- * such a situation. Luckily all programs should be able to cope with that.
- *
- * I think I've optimized anything as far as one can do in plain C, all
- * variables should fit in registers and the loops are really short. There's
- * one loop for every possible situation. Writing a more generalized and thus
- * parameterized loop would only produce slower code. Feel free to optimize
- * this in assembler if you like. :)
- *
- * I think these routines belong here because they're not yet really hardware
- * independent, especially the fact that the Falcon can play 16bit samples
- * only in stereo is hardcoded in both of them!
- *
- * ++geert: split in even more functions (one per format)
- */
-
-static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft)
-{
-       short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
-       ssize_t count, used;
-       short *p = (short *) &frame[*frameUsed];
-       int val, stereo = sound.soft.stereo;
-
-       frameLeft >>= 2;
-       if (stereo)
-               userCount >>= 1;
-       used = count = min(userCount, frameLeft);
-       while (count > 0) {
-               u_char data;
-               if (get_user(data, userPtr++))
-                       return -EFAULT;
-               val = table[data];
-               *p++ = val;
-               if (stereo) {
-                       if (get_user(data, userPtr++))
-                               return -EFAULT;
-                       val = table[data];
-               }
-               *p++ = val;
-               count--;
-       }
-       *frameUsed += used * 4;
-       return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount,
-                         u_char frame[], ssize_t *frameUsed,
-                         ssize_t frameLeft)
-{
-       ssize_t count, used;
-       short *p = (short *) &frame[*frameUsed];
-       int val, stereo = sound.soft.stereo;
-
-       frameLeft >>= 2;
-       if (stereo)
-               userCount >>= 1;
-       used = count = min(userCount, frameLeft);
-       while (count > 0) {
-               u_char data;
-               if (get_user(data, userPtr++))
-                       return -EFAULT;
-               val = data << 8;
-               *p++ = val;
-               if (stereo) {
-                       if (get_user(data, userPtr++))
-                               return -EFAULT;
-                       val = data << 8;
-               }
-               *p++ = val;
-               count--;
-       }
-       *frameUsed += used * 4;
-       return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount,
-                         u_char frame[], ssize_t *frameUsed,
-                         ssize_t frameLeft)
-{
-       ssize_t count, used;
-       short *p = (short *) &frame[*frameUsed];
-       int val, stereo = sound.soft.stereo;
-
-       frameLeft >>= 2;
-       if (stereo)
-               userCount >>= 1;
-       used = count = min(userCount, frameLeft);
-       while (count > 0) {
-               u_char data;
-               if (get_user(data, userPtr++))
-                       return -EFAULT;
-               val = (data ^ 0x80) << 8;
-               *p++ = val;
-               if (stereo) {
-                       if (get_user(data, userPtr++))
-                               return -EFAULT;
-                       val = (data ^ 0x80) << 8;
-               }
-               *p++ = val;
-               count--;
-       }
-       *frameUsed += used * 4;
-       return stereo? used * 2: used;
-}
-
-
-/* This is the default format of the codec.  Signed, 16-bit stereo
- * generated by an application shouldn't have to be copied at all.
- * We should just get the phsical address of the buffers and update
- * the TDM BDs directly.
- */
-static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft)
-{
-       ssize_t count, used;
-       int stereo = sound.soft.stereo;
-       short *fp = (short *) &frame[*frameUsed];
-
-       frameLeft >>= 2;
-       userCount >>= (stereo? 2: 1);
-       used = count = min(userCount, frameLeft);
-       if (!stereo) {
-               short *up = (short *) userPtr;
-               while (count > 0) {
-                       short data;
-                       if (get_user(data, up++))
-                               return -EFAULT;
-                       *fp++ = data;
-                       *fp++ = data;
-                       count--;
-               }
-       } else {
-               if (copy_from_user(fp, userPtr, count * 4))
-                       return -EFAULT;
-       }
-       *frameUsed += used * 4;
-       return stereo? used * 4: used * 2;
-}
-
-static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft)
-{
-       ssize_t count, used;
-       int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-       int stereo = sound.soft.stereo;
-       short *fp = (short *) &frame[*frameUsed];
-       short *up = (short *) userPtr;
-
-       frameLeft >>= 2;
-       userCount >>= (stereo? 2: 1);
-       used = count = min(userCount, frameLeft);
-       while (count > 0) {
-               int data;
-               if (get_user(data, up++))
-                       return -EFAULT;
-               data ^= mask;
-               *fp++ = data;
-               if (stereo) {
-                       if (get_user(data, up++))
-                               return -EFAULT;
-                       data ^= mask;
-               }
-               *fp++ = data;
-               count--;
-       }
-       *frameUsed += used * 4;
-       return stereo? used * 4: used * 2;
-}
-
-
-static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount,
-                           u_char frame[], ssize_t *frameUsed,
-                           ssize_t frameLeft)
-{
-       unsigned short *table = (unsigned short *)
-               (sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
-       unsigned int data = expand_data;
-       unsigned int *p = (unsigned int *) &frame[*frameUsed];
-       int bal = expand_bal;
-       int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-       int utotal, ftotal;
-       int stereo = sound.soft.stereo;
-
-       frameLeft >>= 2;
-       if (stereo)
-               userCount >>= 1;
-       ftotal = frameLeft;
-       utotal = userCount;
-       while (frameLeft) {
-               u_char c;
-               if (bal < 0) {
-                       if (userCount == 0)
-                               break;
-                       if (get_user(c, userPtr++))
-                               return -EFAULT;
-                       data = table[c];
-                       if (stereo) {
-                               if (get_user(c, userPtr++))
-                                       return -EFAULT;
-                               data = (data << 16) + table[c];
-                       } else
-                               data = (data << 16) + data;
-                       userCount--;
-                       bal += hSpeed;
-               }
-               *p++ = data;
-               frameLeft--;
-               bal -= sSpeed;
-       }
-       expand_bal = bal;
-       expand_data = data;
-       *frameUsed += (ftotal - frameLeft) * 4;
-       utotal -= userCount;
-       return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft)
-{
-       unsigned int *p = (unsigned int *) &frame[*frameUsed];
-       unsigned int data = expand_data;
-       int bal = expand_bal;
-       int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-       int stereo = sound.soft.stereo;
-       int utotal, ftotal;
-
-       frameLeft >>= 2;
-       if (stereo)
-               userCount >>= 1;
-       ftotal = frameLeft;
-       utotal = userCount;
-       while (frameLeft) {
-               u_char c;
-               if (bal < 0) {
-                       if (userCount == 0)
-                               break;
-                       if (get_user(c, userPtr++))
-                               return -EFAULT;
-                       data = c << 8;
-                       if (stereo) {
-                               if (get_user(c, userPtr++))
-                                       return -EFAULT;
-                               data = (data << 16) + (c << 8);
-                       } else
-                               data = (data << 16) + data;
-                       userCount--;
-                       bal += hSpeed;
-               }
-               *p++ = data;
-               frameLeft--;
-               bal -= sSpeed;
-       }
-       expand_bal = bal;
-       expand_data = data;
-       *frameUsed += (ftotal - frameLeft) * 4;
-       utotal -= userCount;
-       return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft)
-{
-       unsigned int *p = (unsigned int *) &frame[*frameUsed];
-       unsigned int data = expand_data;
-       int bal = expand_bal;
-       int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-       int stereo = sound.soft.stereo;
-       int utotal, ftotal;
-
-       frameLeft >>= 2;
-       if (stereo)
-               userCount >>= 1;
-       ftotal = frameLeft;
-       utotal = userCount;
-       while (frameLeft) {
-               u_char c;
-               if (bal < 0) {
-                       if (userCount == 0)
-                               break;
-                       if (get_user(c, userPtr++))
-                               return -EFAULT;
-                       data = (c ^ 0x80) << 8;
-                       if (stereo) {
-                               if (get_user(c, userPtr++))
-                                       return -EFAULT;
-                               data = (data << 16) + ((c ^ 0x80) << 8);
-                       } else
-                               data = (data << 16) + data;
-                       userCount--;
-                       bal += hSpeed;
-               }
-               *p++ = data;
-               frameLeft--;
-               bal -= sSpeed;
-       }
-       expand_bal = bal;
-       expand_data = data;
-       *frameUsed += (ftotal - frameLeft) * 4;
-       utotal -= userCount;
-       return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount,
-                           u_char frame[], ssize_t *frameUsed,
-                           ssize_t frameLeft)
-{
-       unsigned int *p = (unsigned int *) &frame[*frameUsed];
-       unsigned int data = expand_data;
-       unsigned short *up = (unsigned short *) userPtr;
-       int bal = expand_bal;
-       int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-       int stereo = sound.soft.stereo;
-       int utotal, ftotal;
-
-       frameLeft >>= 2;
-       userCount >>= (stereo? 2: 1);
-       ftotal = frameLeft;
-       utotal = userCount;
-       while (frameLeft) {
-               unsigned short c;
-               if (bal < 0) {
-                       if (userCount == 0)
-                               break;
-                       if (get_user(data, up++))
-                               return -EFAULT;
-                       if (stereo) {
-                               if (get_user(c, up++))
-                                       return -EFAULT;
-                               data = (data << 16) + c;
-                       } else
-                               data = (data << 16) + data;
-                       userCount--;
-                       bal += hSpeed;
-               }
-               *p++ = data;
-               frameLeft--;
-               bal -= sSpeed;
-       }
-       expand_bal = bal;
-       expand_data = data;
-       *frameUsed += (ftotal - frameLeft) * 4;
-       utotal -= userCount;
-       return stereo? utotal * 4: utotal * 2;
-}
-
-
-static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount,
-                           u_char frame[], ssize_t *frameUsed,
-                           ssize_t frameLeft)
-{
-       int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-       unsigned int *p = (unsigned int *) &frame[*frameUsed];
-       unsigned int data = expand_data;
-       unsigned short *up = (unsigned short *) userPtr;
-       int bal = expand_bal;
-       int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-       int stereo = sound.soft.stereo;
-       int utotal, ftotal;
-
-       frameLeft >>= 2;
-       userCount >>= (stereo? 2: 1);
-       ftotal = frameLeft;
-       utotal = userCount;
-       while (frameLeft) {
-               unsigned short c;
-               if (bal < 0) {
-                       if (userCount == 0)
-                               break;
-                       if (get_user(data, up++))
-                               return -EFAULT;
-                       data ^= mask;
-                       if (stereo) {
-                               if (get_user(c, up++))
-                                       return -EFAULT;
-                               data = (data << 16) + (c ^ mask);
-                       } else
-                               data = (data << 16) + data;
-                       userCount--;
-                       bal += hSpeed;
-               }
-               *p++ = data;
-               frameLeft--;
-               bal -= sSpeed;
-       }
-       expand_bal = bal;
-       expand_data = data;
-       *frameUsed += (ftotal - frameLeft) * 4;
-       utotal -= userCount;
-       return stereo? utotal * 4: utotal * 2;
-}
-
-static ssize_t cs4218_ct_s8_read(const u_char *userPtr, size_t userCount,
-                         u_char frame[], ssize_t *frameUsed,
-                         ssize_t frameLeft)
-{
-       ssize_t count, used;
-       short *p = (short *) &frame[*frameUsed];
-       int val, stereo = sound.soft.stereo;
-
-       frameLeft >>= 2;
-       if (stereo)
-               userCount >>= 1;
-       used = count = min(userCount, frameLeft);
-       while (count > 0) {
-               u_char data;
-
-               val = *p++;
-               data = val >> 8;
-               if (put_user(data, (u_char *)userPtr++))
-                       return -EFAULT;
-               if (stereo) {
-                       val = *p;
-                       data = val >> 8;
-                       if (put_user(data, (u_char *)userPtr++))
-                               return -EFAULT;
-               }
-               p++;
-               count--;
-       }
-       *frameUsed += used * 4;
-       return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_u8_read(const u_char *userPtr, size_t userCount,
-                         u_char frame[], ssize_t *frameUsed,
-                         ssize_t frameLeft)
-{
-       ssize_t count, used;
-       short *p = (short *) &frame[*frameUsed];
-       int val, stereo = sound.soft.stereo;
-
-       frameLeft >>= 2;
-       if (stereo)
-               userCount >>= 1;
-       used = count = min(userCount, frameLeft);
-       while (count > 0) {
-               u_char data;
-
-               val = *p++;
-               data = (val >> 8) ^ 0x80;
-               if (put_user(data, (u_char *)userPtr++))
-                       return -EFAULT;
-               if (stereo) {
-                       val = *p;
-                       data = (val >> 8) ^ 0x80;
-                       if (put_user(data, (u_char *)userPtr++))
-                               return -EFAULT;
-               }
-               p++;
-               count--;
-       }
-       *frameUsed += used * 4;
-       return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft)
-{
-       ssize_t count, used;
-       int stereo = sound.soft.stereo;
-       short *fp = (short *) &frame[*frameUsed];
-
-       frameLeft >>= 2;
-       userCount >>= (stereo? 2: 1);
-       used = count = min(userCount, frameLeft);
-       if (!stereo) {
-               short *up = (short *) userPtr;
-               while (count > 0) {
-                       short data;
-                       data = *fp;
-                       if (put_user(data, up++))
-                               return -EFAULT;
-                       fp+=2;
-                       count--;
-               }
-       } else {
-               if (copy_to_user((u_char *)userPtr, fp, count * 4))
-                       return -EFAULT;
-       }
-       *frameUsed += used * 4;
-       return stereo? used * 4: used * 2;
-}
-
-static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount,
-                          u_char frame[], ssize_t *frameUsed,
-                          ssize_t frameLeft)
-{
-       ssize_t count, used;
-       int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-       int stereo = sound.soft.stereo;
-       short *fp = (short *) &frame[*frameUsed];
-       short *up = (short *) userPtr;
-
-       frameLeft >>= 2;
-       userCount >>= (stereo? 2: 1);
-       used = count = min(userCount, frameLeft);
-       while (count > 0) {
-               int data;
-
-               data = *fp++;
-               data ^= mask;
-               if (put_user(data, up++))
-                       return -EFAULT;
-               if (stereo) {
-                       data = *fp;
-                       data ^= mask;
-                       if (put_user(data, up++))
-                               return -EFAULT;
-               }
-               fp++;
-               count--;
-       }
-       *frameUsed += used * 4;
-       return stereo? used * 4: used * 2;
-}
-
-static TRANS transCSNormal = {
-       cs4218_ct_law, cs4218_ct_law, cs4218_ct_s8, cs4218_ct_u8,
-       cs4218_ct_s16, cs4218_ct_u16, cs4218_ct_s16, cs4218_ct_u16
-};
-
-static TRANS transCSExpand = {
-       cs4218_ctx_law, cs4218_ctx_law, cs4218_ctx_s8, cs4218_ctx_u8,
-       cs4218_ctx_s16, cs4218_ctx_u16, cs4218_ctx_s16, cs4218_ctx_u16
-};
-
-static TRANS transCSNormalRead = {
-       NULL, NULL, cs4218_ct_s8_read, cs4218_ct_u8_read,
-       cs4218_ct_s16_read, cs4218_ct_u16_read,
-       cs4218_ct_s16_read, cs4218_ct_u16_read
-};
-
-/*** Low level stuff *********************************************************/
-
-static void *CS_Alloc(unsigned int size, gfp_t flags)
-{
-       int     order;
-
-       size >>= 13;
-       for (order=0; order < 5; order++) {
-               if (size == 0)
-                       break;
-               size >>= 1;
-       }
-       return (void *)__get_free_pages(flags, order);
-}
-
-static void CS_Free(void *ptr, unsigned int size)
-{
-       int     order;
-
-       size >>= 13;
-       for (order=0; order < 5; order++) {
-               if (size == 0)
-                       break;
-               size >>= 1;
-       }
-       free_pages((ulong)ptr, order);
-}
-
-static int __init CS_IrqInit(void)
-{
-       cpm_install_handler(CPMVEC_SMC2, cs4218_intr, NULL);
-       return 1;
-}
-
-#ifdef MODULE
-static void CS_IrqCleanup(void)
-{
-       volatile smc_t          *sp;
-       volatile cpm8xx_t       *cp;
-
-       /* First disable transmitter and receiver.
-       */
-       sp = &cpmp->cp_smc[1];
-       sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-
-       /* And now shut down the SMC.
-       */
-       cp = cpmp;      /* Get pointer to Communication Processor */
-       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
-                               CPM_CR_STOP_TX) | CPM_CR_FLG;
-       while (cp->cp_cpcr & CPM_CR_FLG);
-
-       /* Release the interrupt handler.
-       */
-       cpm_free_handler(CPMVEC_SMC2);
-
-       kfree(beep_buf);
-       kd_mksound = orig_mksound;
-}
-#endif /* MODULE */
-
-static void CS_Silence(void)
-{
-       volatile smc_t          *sp;
-
-       /* Disable transmitter.
-       */
-       sp = &cpmp->cp_smc[1];
-       sp->smc_smcmr &= ~SMCMR_TEN;
-}
-
-/* Frequencies depend upon external oscillator.  There are two
- * choices, 12.288 and 11.2896 MHz.  The RPCG audio supports both through
- * and external control register selection bit.
- */
-static int cs4218_freqs[] = {
-    /* 12.288  11.2896  */
-       48000, 44100,
-       32000, 29400,
-       24000, 22050,
-       19200, 17640,
-       16000, 14700,
-       12000, 11025,
-        9600,  8820,
-        8000,  7350
-};
-
-static void CS_Init(void)
-{
-       int i, tolerance;
-
-       switch (sound.soft.format) {
-       case AFMT_S16_LE:
-       case AFMT_U16_LE:
-               sound.hard.format = AFMT_S16_LE;
-               break;
-       default:
-               sound.hard.format = AFMT_S16_BE;
-               break;
-       }
-       sound.hard.stereo = 1;
-       sound.hard.size = 16;
-
-       /*
-        * If we have a sample rate which is within catchRadius percent
-        * of the requested value, we don't have to expand the samples.
-        * Otherwise choose the next higher rate.
-        */
-       i = (sizeof(cs4218_freqs) / sizeof(int));
-       do {
-               tolerance = catchRadius * cs4218_freqs[--i] / 100;
-       } while (sound.soft.speed > cs4218_freqs[i] + tolerance && i > 0);
-       if (sound.soft.speed >= cs4218_freqs[i] - tolerance)
-               sound.trans_write = &transCSNormal;
-       else
-               sound.trans_write = &transCSExpand;
-       sound.trans_read = &transCSNormalRead;
-       sound.hard.speed = cs4218_freqs[i];
-       cs4218_rate_index = i;
-
-       /* The CS4218 has seven selectable clock dividers for the sample
-        * clock.  The HIOX then provides one of two external rates.
-        * An even numbered frequency table index uses the high external
-        * clock rate.
-        */
-       *(uint *)HIOX_CSR4_ADDR &= ~(HIOX_CSR4_AUDCLKHI | HIOX_CSR4_AUDCLKSEL);
-       if ((i & 1) == 0)
-               *(uint *)HIOX_CSR4_ADDR |= HIOX_CSR4_AUDCLKHI;
-       i >>= 1;
-       *(uint *)HIOX_CSR4_ADDR |= (i & HIOX_CSR4_AUDCLKSEL);
-
-       expand_bal = -sound.soft.speed;
-}
-
-static int CS_SetFormat(int format)
-{
-       int size;
-
-       switch (format) {
-       case AFMT_QUERY:
-               return sound.soft.format;
-       case AFMT_MU_LAW:
-       case AFMT_A_LAW:
-       case AFMT_U8:
-       case AFMT_S8:
-               size = 8;
-               break;
-       case AFMT_S16_BE:
-       case AFMT_U16_BE:
-       case AFMT_S16_LE:
-       case AFMT_U16_LE:
-               size = 16;
-               break;
-       default: /* :-) */
-               printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
-                      format);
-               size = 8;
-               format = AFMT_U8;
-       }
-
-       sound.soft.format = format;
-       sound.soft.size = size;
-       if (sound.minDev == SND_DEV_DSP) {
-               sound.dsp.format = format;
-               sound.dsp.size = size;
-       }
-
-       CS_Init();
-
-       return format;
-}
-
-/* Volume is the amount of attenuation we tell the codec to impose
- * on the outputs.  There are 32 levels, with 0 the "loudest".
- */
-#define CS_VOLUME_TO_MASK(x)   (31 - ((((x) - 1) * 31) / 99))
-#define CS_MASK_TO_VOLUME(y)   (100 - ((y) * 99 / 31))
-
-static int cs_get_volume(uint reg)
-{
-       int volume;
-
-       volume = CS_MASK_TO_VOLUME(CS_LATTEN_GET(reg));
-       volume |= CS_MASK_TO_VOLUME(CS_RATTEN_GET(reg)) << 8;
-       return volume;
-}
-
-static int cs_volume_setter(int volume, int mute)
-{
-       uint tempctl;
-
-       if (mute && volume == 0) {
-               tempctl = cs4218_control | CS_MUTE;
-       } else {
-               tempctl = cs4218_control & ~CS_MUTE;
-               tempctl = tempctl & ~(CS_LATTEN | CS_RATTEN);
-               tempctl |= CS_LATTEN_SET(CS_VOLUME_TO_MASK(volume & 0xff));
-               tempctl |= CS_RATTEN_SET(CS_VOLUME_TO_MASK((volume >> 8) & 0xff));
-               volume = cs_get_volume(tempctl);
-       }
-       if (tempctl != cs4218_control) {
-               cs4218_ctl_write(tempctl);
-       }
-       return volume;
-}
-
-
-/* Gain has 16 steps from 0 to 15.  These are in 1.5dB increments from
- * 0 (no gain) to 22.5 dB.
- */
-#define CS_RECLEVEL_TO_GAIN(v) \
-       ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
-#define CS_GAIN_TO_RECLEVEL(v) (((v) * 20 + 2) / 3)
-
-static int cs_get_gain(uint reg)
-{
-       int gain;
-
-       gain = CS_GAIN_TO_RECLEVEL(CS_LGAIN_GET(reg));
-       gain |= CS_GAIN_TO_RECLEVEL(CS_RGAIN_GET(reg)) << 8;
-       return gain;
-}
-
-static int cs_set_gain(int gain)
-{
-       uint tempctl;
-
-       tempctl = cs4218_control & ~(CS_LGAIN | CS_RGAIN);
-       tempctl |= CS_LGAIN_SET(CS_RECLEVEL_TO_GAIN(gain & 0xff));
-       tempctl |= CS_RGAIN_SET(CS_RECLEVEL_TO_GAIN((gain >> 8) & 0xff));
-       gain = cs_get_gain(tempctl);
-
-       if (tempctl != cs4218_control) {
-               cs4218_ctl_write(tempctl);
-       }
-       return gain;
-}
-
-static int CS_SetVolume(int volume)
-{
-       return cs_volume_setter(volume, CS_MUTE);
-}
-
-static void CS_Play(void)
-{
-       int i, count;
-       unsigned long flags;
-       volatile cbd_t  *bdp;
-       volatile cpm8xx_t *cp;
-
-       /* Protect buffer */
-       spin_lock_irqsave(&cs4218_lock, flags);
-#if 0
-       if (awacs_beep_state) {
-               /* sound takes precedence over beeps */
-               out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
-               out_le32(&awacs->control,
-                        (in_le32(&awacs->control) & ~0x1f00)
-                        | (awacs_rate_index << 8));
-               out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
-               out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count])));
-
-               beep_playing = 0;
-               awacs_beep_state = 0;
-       }
-#endif
-       i = sq.front + sq.active;
-       if (i >= sq.max_count)
-               i -= sq.max_count;
-       while (sq.active < 2 && sq.active < sq.count) {
-               count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size;
-               if (count < sq.block_size && !sq.syncing)
-                       /* last block not yet filled, and we're not syncing. */
-                       break;
-
-               bdp = &tx_base[i];
-               bdp->cbd_datlen = count;
-
-               flush_dcache_range((ulong)sound_buffers[i],
-                                       (ulong)(sound_buffers[i] + count));
-
-               if (++i >= sq.max_count)
-                       i = 0;
-
-               if (sq.active == 0) {
-                       /* The SMC does not load its fifo until the first
-                        * TDM frame pulse, so the transmit data gets shifted
-                        * by one word.  To compensate for this, we incorrectly
-                        * transmit the first buffer and shorten it by one
-                        * word.  Subsequent buffers are then aligned properly.
-                        */
-                       bdp->cbd_datlen -= 2;
-
-                       /* Start up the SMC Transmitter.
-                       */
-                       cp = cpmp;
-                       cp->cp_smc[1].smc_smcmr |= SMCMR_TEN;
-                       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
-                                       CPM_CR_RESTART_TX) | CPM_CR_FLG;
-                       while (cp->cp_cpcr & CPM_CR_FLG);
-               }
-
-               /* Buffer is ready now.
-               */
-               bdp->cbd_sc |= BD_SC_READY;
-
-               ++sq.active;
-       }
-       spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-
-static void CS_Record(void)
-{
-       unsigned long flags;
-       volatile smc_t          *sp;
-
-       if (read_sq.active)
-               return;
-
-       /* Protect buffer */
-       spin_lock_irqsave(&cs4218_lock, flags);
-
-       /* This is all we have to do......Just start it up.
-       */
-       sp = &cpmp->cp_smc[1];
-       sp->smc_smcmr |= SMCMR_REN;
-
-       read_sq.active = 1;
-
-        spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-
-static void
-cs4218_tdm_tx_intr(void *devid)
-{
-       int i = sq.front;
-       volatile cbd_t *bdp;
-
-       while (sq.active > 0) {
-               bdp = &tx_base[i];
-               if (bdp->cbd_sc & BD_SC_READY)
-                       break;  /* this frame is still going */
-               --sq.count;
-               --sq.active;
-               if (++i >= sq.max_count)
-                       i = 0;
-       }
-       if (i != sq.front)
-               WAKE_UP(sq.action_queue);
-       sq.front = i;
-
-       CS_Play();
-
-       if (!sq.active)
-               WAKE_UP(sq.sync_queue);
-}
-
-
-static void
-cs4218_tdm_rx_intr(void *devid)
-{
-
-       /* We want to blow 'em off when shutting down.
-       */
-       if (read_sq.active == 0)
-               return;
-
-       /* Check multiple buffers in case we were held off from
-        * interrupt processing for a long time.  Geeze, I really hope
-        * this doesn't happen.
-        */
-       while ((rx_base[read_sq.rear].cbd_sc & BD_SC_EMPTY) == 0) {
-
-               /* Invalidate the data cache range for this buffer.
-               */
-               invalidate_dcache_range(
-                   (uint)(sound_read_buffers[read_sq.rear]),
-                   (uint)(sound_read_buffers[read_sq.rear] + read_sq.block_size));
-
-               /* Make buffer available again and move on.
-               */
-               rx_base[read_sq.rear].cbd_sc |= BD_SC_EMPTY;
-               read_sq.rear++;
-
-               /* Wrap the buffer ring.
-               */
-               if (read_sq.rear >= read_sq.max_active)
-                       read_sq.rear = 0;
-
-               /* If we have caught up to the front buffer, bump it.
-                * This will cause weird (but not fatal) results if the
-                * read loop is currently using this buffer.  The user is
-                * behind in this case anyway, so weird things are going
-                * to happen.
-                */
-               if (read_sq.rear == read_sq.front) {
-                       read_sq.front++;
-                       if (read_sq.front >= read_sq.max_active)
-                               read_sq.front = 0;
-               }
-       }
-
-       WAKE_UP(read_sq.action_queue);
-}
-
-static void cs_nosound(unsigned long xx)
-{
-       unsigned long flags;
-
-       /* not sure if this is needed, since hardware command is #if 0'd */
-       spin_lock_irqsave(&cs4218_lock, flags);
-       if (beep_playing) {
-#if 0
-               st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
-#endif
-               beep_playing = 0;
-       }
-       spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-static DEFINE_TIMER(beep_timer, cs_nosound, 0, 0);
-
-static void cs_mksound(unsigned int hz, unsigned int ticks)
-{
-       unsigned long flags;
-       int beep_speed = BEEP_SPEED;
-       int srate = cs4218_freqs[beep_speed];
-       int period, ncycles, nsamples;
-       int i, j, f;
-       short *p;
-       static int beep_hz_cache;
-       static int beep_nsamples_cache;
-       static int beep_volume_cache;
-
-       if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
-#if 1
-               /* this is a hack for broken X server code */
-               hz = 750;
-               ticks = 12;
-#else
-               /* cancel beep currently playing */
-               awacs_nosound(0);
-               return;
-#endif
-       }
-       /* lock while modifying beep_timer */
-       spin_lock_irqsave(&cs4218_lock, flags);
-       del_timer(&beep_timer);
-       if (ticks) {
-               beep_timer.expires = jiffies + ticks;
-               add_timer(&beep_timer);
-       }
-       if (beep_playing || sq.active || beep_buf == NULL) {
-               spin_unlock_irqrestore(&cs4218_lock, flags);
-               return;         /* too hard, sorry :-( */
-       }
-       beep_playing = 1;
-#if 0
-       st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
-#endif
-       spin_unlock_irqrestore(&cs4218_lock, flags);
-
-       if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
-               nsamples = beep_nsamples_cache;
-       } else {
-               period = srate * 256 / hz;      /* fixed point */
-               ncycles = BEEP_BUFLEN * 256 / period;
-               nsamples = (period * ncycles) >> 8;
-               f = ncycles * 65536 / nsamples;
-               j = 0;
-               p = beep_buf;
-               for (i = 0; i < nsamples; ++i, p += 2) {
-                       p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
-                       j = (j + f) & 0xffff;
-               }
-               beep_hz_cache = hz;
-               beep_volume_cache = beep_volume;
-               beep_nsamples_cache = nsamples;
-       }
-
-#if 0
-       st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
-       st_le16(&beep_dbdma_cmd->xfer_status, 0);
-       st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
-       st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
-       awacs_beep_state = 1;
-
-       spin_lock_irqsave(&cs4218_lock, flags);
-       if (beep_playing) {     /* i.e. haven't been terminated already */
-               out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
-               out_le32(&awacs->control,
-                        (in_le32(&awacs->control) & ~0x1f00)
-                        | (beep_speed << 8));
-               out_le32(&awacs->byteswap, 0);
-               out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
-               out_le32(&awacs_txdma->control, RUN | (RUN << 16));
-       }
-       spin_unlock_irqrestore(&cs4218_lock, flags);
-#endif
-}
-
-static MACHINE mach_cs4218 = {
-       .owner =        THIS_MODULE,
-       .name =         "HIOX CS4218",
-       .name2 =        "Built-in Sound",
-       .dma_alloc =    CS_Alloc,
-       .dma_free =     CS_Free,
-       .irqinit =      CS_IrqInit,
-#ifdef MODULE
-       .irqcleanup =   CS_IrqCleanup,
-#endif /* MODULE */
-       .init =         CS_Init,
-       .silence =      CS_Silence,
-       .setFormat =    CS_SetFormat,
-       .setVolume =    CS_SetVolume,
-       .play =         CS_Play
-};
-
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void)
-{
-       /* update hardware settings one more */
-       (*sound.mach.init)();
-
-       (*sound.mach.silence)();
-}
-
-
-static void sound_init(void)
-{
-       (*sound.mach.init)();
-}
-
-
-static int sound_set_format(int format)
-{
-       return(*sound.mach.setFormat)(format);
-}
-
-
-static int sound_set_speed(int speed)
-{
-       if (speed < 0)
-               return(sound.soft.speed);
-
-       sound.soft.speed = speed;
-       (*sound.mach.init)();
-       if (sound.minDev == SND_DEV_DSP)
-               sound.dsp.speed = sound.soft.speed;
-
-       return(sound.soft.speed);
-}
-
-
-static int sound_set_stereo(int stereo)
-{
-       if (stereo < 0)
-               return(sound.soft.stereo);
-
-       stereo = !!stereo;    /* should be 0 or 1 now */
-
-       sound.soft.stereo = stereo;
-       if (sound.minDev == SND_DEV_DSP)
-               sound.dsp.stereo = stereo;
-       (*sound.mach.init)();
-
-       return(stereo);
-}
-
-
-static int sound_set_volume(int volume)
-{
-       return(*sound.mach.setVolume)(volume);
-}
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
-                                   size_t userCount,
-                                   u_char frame[], ssize_t *frameUsed,
-                                   ssize_t frameLeft)
-{
-       ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
-       switch (sound.soft.format) {
-       case AFMT_MU_LAW:
-               ct_func = sound.trans_write->ct_ulaw;
-               break;
-       case AFMT_A_LAW:
-               ct_func = sound.trans_write->ct_alaw;
-               break;
-       case AFMT_S8:
-               ct_func = sound.trans_write->ct_s8;
-               break;
-       case AFMT_U8:
-               ct_func = sound.trans_write->ct_u8;
-               break;
-       case AFMT_S16_BE:
-               ct_func = sound.trans_write->ct_s16be;
-               break;
-       case AFMT_U16_BE:
-               ct_func = sound.trans_write->ct_u16be;
-               break;
-       case AFMT_S16_LE:
-               ct_func = sound.trans_write->ct_s16le;
-               break;
-       case AFMT_U16_LE:
-               ct_func = sound.trans_write->ct_u16le;
-               break;
-       }
-       if (ct_func)
-               return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
-       else
-               return 0;
-}
-
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
-                                   size_t userCount,
-                                   u_char frame[], ssize_t *frameUsed,
-                                   ssize_t frameLeft)
-{
-       ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
-       switch (sound.soft.format) {
-       case AFMT_MU_LAW:
-               ct_func = sound.trans_read->ct_ulaw;
-               break;
-       case AFMT_A_LAW:
-               ct_func = sound.trans_read->ct_alaw;
-               break;
-       case AFMT_S8:
-               ct_func = sound.trans_read->ct_s8;
-               break;
-       case AFMT_U8:
-               ct_func = sound.trans_read->ct_u8;
-               break;
-       case AFMT_S16_BE:
-               ct_func = sound.trans_read->ct_s16be;
-               break;
-       case AFMT_U16_BE:
-               ct_func = sound.trans_read->ct_u16be;
-               break;
-       case AFMT_S16_LE:
-               ct_func = sound.trans_read->ct_s16le;
-               break;
-       case AFMT_U16_LE:
-               ct_func = sound.trans_read->ct_u16le;
-               break;
-       }
-       if (ct_func)
-               return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
-       else
-               return 0;
-}
-
-
-/*
- * /dev/mixer abstraction
- */
-
-static int mixer_open(struct inode *inode, struct file *file)
-{
-       mixer.busy = 1;
-       return nonseekable_open(inode, file);
-}
-
-
-static int mixer_release(struct inode *inode, struct file *file)
-{
-       mixer.busy = 0;
-       return 0;
-}
-
-
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg)
-{
-       int data;
-       uint tmpcs;
-
-       if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-           mixer.modify_counter++;
-       if (cmd == OSS_GETVERSION)
-           return IOCTL_OUT(arg, SOUND_VERSION);
-       switch (cmd) {
-               case SOUND_MIXER_INFO: {
-                   mixer_info info;
-                   strlcpy(info.id, "CS4218_TDM", sizeof(info.id));
-                   strlcpy(info.name, "CS4218_TDM", sizeof(info.name));
-                   info.name[sizeof(info.name)-1] = 0;
-                   info.modify_counter = mixer.modify_counter;
-                   if (copy_to_user((int *)arg, &info, sizeof(info)))
-                               return -EFAULT;
-                   return 0;
-               }
-               case SOUND_MIXER_READ_DEVMASK:
-                       data = SOUND_MASK_VOLUME | SOUND_MASK_LINE
-                               | SOUND_MASK_MIC | SOUND_MASK_RECLEV
-                               | SOUND_MASK_ALTPCM;
-                       return IOCTL_OUT(arg, data);
-               case SOUND_MIXER_READ_RECMASK:
-                       data = SOUND_MASK_LINE | SOUND_MASK_MIC;
-                       return IOCTL_OUT(arg, data);
-               case SOUND_MIXER_READ_RECSRC:
-                       if (cs4218_control & CS_DO1)
-                               data = SOUND_MASK_LINE;
-                       else
-                               data = SOUND_MASK_MIC;
-                       return IOCTL_OUT(arg, data);
-               case SOUND_MIXER_WRITE_RECSRC:
-                       IOCTL_IN(arg, data);
-                       data &= (SOUND_MASK_LINE | SOUND_MASK_MIC);
-                       if (data & SOUND_MASK_LINE)
-                               tmpcs = cs4218_control |
-                                               (CS_ISL | CS_ISR | CS_DO1);
-                       if (data & SOUND_MASK_MIC)
-                               tmpcs = cs4218_control &
-                                               ~(CS_ISL | CS_ISR | CS_DO1);
-                       if (tmpcs != cs4218_control)
-                               cs4218_ctl_write(tmpcs);
-                       return IOCTL_OUT(arg, data);
-               case SOUND_MIXER_READ_STEREODEVS:
-                       data = SOUND_MASK_VOLUME | SOUND_MASK_RECLEV;
-                       return IOCTL_OUT(arg, data);
-               case SOUND_MIXER_READ_CAPS:
-                       return IOCTL_OUT(arg, 0);
-               case SOUND_MIXER_READ_VOLUME:
-                       data = (cs4218_control & CS_MUTE)? 0:
-                               cs_get_volume(cs4218_control);
-                       return IOCTL_OUT(arg, data);
-               case SOUND_MIXER_WRITE_VOLUME:
-                       IOCTL_IN(arg, data);
-                       return IOCTL_OUT(arg, sound_set_volume(data));
-               case SOUND_MIXER_WRITE_ALTPCM:  /* really bell volume */
-                       IOCTL_IN(arg, data);
-                       beep_volume = data & 0xff;
-                       /* fall through */
-               case SOUND_MIXER_READ_ALTPCM:
-                       return IOCTL_OUT(arg, beep_volume);
-               case SOUND_MIXER_WRITE_RECLEV:
-                       IOCTL_IN(arg, data);
-                       data = cs_set_gain(data);
-                       return IOCTL_OUT(arg, data);
-               case SOUND_MIXER_READ_RECLEV:
-                       data = cs_get_gain(cs4218_control);
-                       return IOCTL_OUT(arg, data);
-       }
-
-       return -EINVAL;
-}
-
-
-static const struct file_operations mixer_fops =
-{
-       .owner =        THIS_MODULE,
-       .llseek =       sound_lseek,
-       .ioctl =        mixer_ioctl,
-       .open =         mixer_open,
-       .release =      mixer_release,
-};
-
-
-static void __init mixer_init(void)
-{
-       mixer_unit = register_sound_mixer(&mixer_fops, -1);
-       if (mixer_unit < 0)
-               return;
-
-       mixer.busy = 0;
-       sound.treble = 0;
-       sound.bass = 0;
-
-       /* Set Line input, no gain, no attenuation.
-       */
-       cs4218_control = CS_ISL | CS_ISR | CS_DO1;
-       cs4218_control |= CS_LGAIN_SET(0) | CS_RGAIN_SET(0);
-       cs4218_control |= CS_LATTEN_SET(0) | CS_RATTEN_SET(0);
-       cs4218_ctl_write(cs4218_control);
-}
-
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-
-static int sq_allocate_buffers(void)
-{
-       int i;
-
-       if (sound_buffers)
-               return 0;
-       sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
-       if (!sound_buffers)
-               return -ENOMEM;
-       for (i = 0; i < numBufs; i++) {
-               sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
-               if (!sound_buffers[i]) {
-                       while (i--)
-                               sound.mach.dma_free (sound_buffers[i], bufSize << 10);
-                       kfree (sound_buffers);
-                       sound_buffers = 0;
-                       return -ENOMEM;
-               }
-       }
-       return 0;
-}
-
-
-static void sq_release_buffers(void)
-{
-       int i;
-
-       if (sound_buffers) {
-               for (i = 0; i < numBufs; i++)
-                       sound.mach.dma_free (sound_buffers[i], bufSize << 10);
-               kfree (sound_buffers);
-               sound_buffers = 0;
-       }
-}
-
-
-static int sq_allocate_read_buffers(void)
-{
-       int i;
-
-       if (sound_read_buffers)
-               return 0;
-       sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL);
-       if (!sound_read_buffers)
-               return -ENOMEM;
-       for (i = 0; i < numBufs; i++) {
-               sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10,
-                                                             GFP_KERNEL);
-               if (!sound_read_buffers[i]) {
-                       while (i--)
-                               sound.mach.dma_free (sound_read_buffers[i],
-                                                    readbufSize << 10);
-                       kfree (sound_read_buffers);
-                       sound_read_buffers = 0;
-                       return -ENOMEM;
-               }
-       }
-       return 0;
-}
-
-static void sq_release_read_buffers(void)
-{
-       int i;
-
-       if (sound_read_buffers) {
-               cpmp->cp_smc[1].smc_smcmr &= ~SMCMR_REN;
-               for (i = 0; i < numReadBufs; i++)
-                       sound.mach.dma_free (sound_read_buffers[i],
-                                            bufSize << 10);
-               kfree (sound_read_buffers);
-               sound_read_buffers = 0;
-       }
-}
-
-
-static void sq_setup(int numBufs, int bufSize, char **write_buffers)
-{
-       int i;
-       volatile cbd_t *bdp;
-       volatile cpm8xx_t       *cp;
-       volatile smc_t  *sp;
-
-       /* Make sure the SMC transmit is shut down.
-       */
-       cp = cpmp;
-       sp = &cpmp->cp_smc[1];
-       sp->smc_smcmr &= ~SMCMR_TEN;
-
-       sq.max_count = numBufs;
-       sq.max_active = numBufs;
-       sq.block_size = bufSize;
-       sq.buffers = write_buffers;
-
-       sq.front = sq.count = 0;
-       sq.rear = -1;
-       sq.syncing = 0;
-       sq.active = 0;
-
-       bdp = tx_base;
-       for (i=0; i<numBufs; i++) {
-               bdp->cbd_bufaddr = virt_to_bus(write_buffers[i]);
-               bdp++;
-       }
-
-       /* This causes the SMC to sync up with the first buffer again.
-       */
-       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_TX) | CPM_CR_FLG;
-       while (cp->cp_cpcr & CPM_CR_FLG);
-}
-
-static void read_sq_setup(int numBufs, int bufSize, char **read_buffers)
-{
-       int i;
-       volatile cbd_t *bdp;
-       volatile cpm8xx_t       *cp;
-       volatile smc_t  *sp;
-
-       /* Make sure the SMC receive is shut down.
-       */
-       cp = cpmp;
-       sp = &cpmp->cp_smc[1];
-       sp->smc_smcmr &= ~SMCMR_REN;
-
-       read_sq.max_count = numBufs;
-       read_sq.max_active = numBufs;
-       read_sq.block_size = bufSize;
-       read_sq.buffers = read_buffers;
-
-       read_sq.front = read_sq.count = 0;
-       read_sq.rear = 0;
-       read_sq.rear_size = 0;
-       read_sq.syncing = 0;
-       read_sq.active = 0;
-
-       bdp = rx_base;
-       for (i=0; i<numReadBufs; i++) {
-               bdp->cbd_bufaddr = virt_to_bus(read_buffers[i]);
-               bdp->cbd_datlen = read_sq.block_size;
-               bdp++;
-       }
-
-       /* This causes the SMC to sync up with the first buffer again.
-       */
-       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_RX) | CPM_CR_FLG;
-       while (cp->cp_cpcr & CPM_CR_FLG);
-}
-
-
-static void sq_play(void)
-{
-       (*sound.mach.play)();
-}
-
-
-/* ++TeSche: radically changed this one too */
-
-static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
-                       loff_t *ppos)
-{
-       ssize_t uWritten = 0;
-       u_char *dest;
-       ssize_t uUsed, bUsed, bLeft;
-
-       /* ++TeSche: Is something like this necessary?
-        * Hey, that's an honest question! Or does any other part of the
-        * filesystem already checks this situation? I really don't know.
-        */
-       if (uLeft == 0)
-               return 0;
-
-       /* The interrupt doesn't start to play the last, incomplete frame.
-        * Thus we can append to it without disabling the interrupts! (Note
-        * also that sq.rear isn't affected by the interrupt.)
-        */
-
-       if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
-               dest = sq_block_address(sq.rear);
-               bUsed = sq.rear_size;
-               uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-               if (uUsed <= 0)
-                       return uUsed;
-               src += uUsed;
-               uWritten += uUsed;
-               uLeft -= uUsed;
-               sq.rear_size = bUsed;
-       }
-
-       do {
-               while (sq.count == sq.max_active) {
-                       sq_play();
-                       if (NON_BLOCKING(sq.open_mode))
-                               return uWritten > 0 ? uWritten : -EAGAIN;
-                       SLEEP(sq.action_queue);
-                       if (SIGNAL_RECEIVED)
-                               return uWritten > 0 ? uWritten : -EINTR;
-               }
-
-               /* Here, we can avoid disabling the interrupt by first
-                * copying and translating the data, and then updating
-                * the sq variables. Until this is done, the interrupt
-                * won't see the new frame and we can work on it
-                * undisturbed.
-                */
-
-               dest = sq_block_address((sq.rear+1) % sq.max_count);
-               bUsed = 0;
-               bLeft = sq.block_size;
-               uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-               if (uUsed <= 0)
-                       break;
-               src += uUsed;
-               uWritten += uUsed;
-               uLeft -= uUsed;
-               if (bUsed) {
-                       sq.rear = (sq.rear+1) % sq.max_count;
-                       sq.rear_size = bUsed;
-                       sq.count++;
-               }
-       } while (bUsed);   /* uUsed may have been 0 */
-
-       sq_play();
-
-       return uUsed < 0? uUsed: uWritten;
-}
-
-
-/***********/
-
-/* Here is how the values are used for reading.
- * The value 'active' simply indicates the DMA is running.  This is
- * done so the driver semantics are DMA starts when the first read is
- * posted.  The value 'front' indicates the buffer we should next
- * send to the user.  The value 'rear' indicates the buffer the DMA is
- * currently filling.  When 'front' == 'rear' the buffer "ring" is
- * empty (we always have an empty available).  The 'rear_size' is used
- * to track partial offsets into the current buffer.  Right now, I just keep
- * The DMA running.  If the reader can't keep up, the interrupt tosses
- * the oldest buffer.  We could also shut down the DMA in this case.
- */
-static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
-                       loff_t *ppos)
-{
-
-       ssize_t uRead, bLeft, bUsed, uUsed;
-
-       if (uLeft == 0)
-               return 0;
-
-       if (!read_sq.active)
-               CS_Record();    /* Kick off the record process. */
-
-       uRead = 0;
-
-       /* Move what the user requests, depending upon other options.
-       */
-       while (uLeft > 0) {
-
-               /* When front == rear, the DMA is not done yet.
-               */
-               while (read_sq.front == read_sq.rear) {
-                       if (NON_BLOCKING(read_sq.open_mode)) {
-                              return uRead > 0 ? uRead : -EAGAIN;
-                       }
-                       SLEEP(read_sq.action_queue);
-                       if (SIGNAL_RECEIVED)
-                               return uRead > 0 ? uRead : -EINTR;
-               }
-
-               /* The amount we move is either what is left in the
-                * current buffer or what the user wants.
-                */
-               bLeft = read_sq.block_size - read_sq.rear_size;
-               bUsed = read_sq.rear_size;
-               uUsed = sound_copy_translate_read(dst, uLeft,
-                       read_sq.buffers[read_sq.front], &bUsed, bLeft);
-               if (uUsed <= 0)
-                       return uUsed;
-               dst += uUsed;
-               uRead += uUsed;
-               uLeft -= uUsed;
-               read_sq.rear_size += bUsed;
-               if (read_sq.rear_size >= read_sq.block_size) {
-                       read_sq.rear_size = 0;
-                       read_sq.front++;
-                       if (read_sq.front >= read_sq.max_active)
-                               read_sq.front = 0;
-               }
-       }
-       return uRead;
-}
-
-static int sq_open(struct inode *inode, struct file *file)
-{
-       int rc = 0;
-
-       if (file->f_mode & FMODE_WRITE) {
-               if (sq.busy) {
-                       rc = -EBUSY;
-                       if (NON_BLOCKING(file->f_flags))
-                               goto err_out;
-                       rc = -EINTR;
-                       while (sq.busy) {
-                               SLEEP(sq.open_queue);
-                               if (SIGNAL_RECEIVED)
-                                       goto err_out;
-                       }
-               }
-               sq.busy = 1; /* Let's play spot-the-race-condition */
-
-               if (sq_allocate_buffers()) goto err_out_nobusy;
-
-               sq_setup(numBufs, bufSize<<10,sound_buffers);
-               sq.open_mode = file->f_mode;
-       }
-
-
-       if (file->f_mode & FMODE_READ) {
-               if (read_sq.busy) {
-                       rc = -EBUSY;
-                       if (NON_BLOCKING(file->f_flags))
-                               goto err_out;
-                       rc = -EINTR;
-                       while (read_sq.busy) {
-                               SLEEP(read_sq.open_queue);
-                               if (SIGNAL_RECEIVED)
-                                       goto err_out;
-                       }
-                       rc = 0;
-               }
-               read_sq.busy = 1;
-               if (sq_allocate_read_buffers()) goto err_out_nobusy;
-
-               read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers);
-               read_sq.open_mode = file->f_mode;
-       }
-
-       /* Start up the 4218 by:
-        * Reset.
-        * Enable, unreset.
-        */
-       *((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_RSTAUDIO;
-       eieio();
-       *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_ENAUDIO;
-       mdelay(50);
-       *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO;
-
-       /* We need to send the current control word in case someone
-        * opened /dev/mixer and changed things while we were shut
-        * down.  Chances are good the initialization that follows
-        * would have done this, but it is still possible it wouldn't.
-        */
-       cs4218_ctl_write(cs4218_control);
-
-       sound.minDev = iminor(inode) & 0x0f;
-       sound.soft = sound.dsp;
-       sound.hard = sound.dsp;
-       sound_init();
-       if ((iminor(inode) & 0x0f) == SND_DEV_AUDIO) {
-               sound_set_speed(8000);
-               sound_set_stereo(0);
-               sound_set_format(AFMT_MU_LAW);
-       }
-
-       return nonseekable_open(inode, file);
-
-err_out_nobusy:
-       if (file->f_mode & FMODE_WRITE) {
-               sq.busy = 0;
-               WAKE_UP(sq.open_queue);
-       }
-       if (file->f_mode & FMODE_READ) {
-               read_sq.busy = 0;
-               WAKE_UP(read_sq.open_queue);
-       }
-err_out:
-       return rc;
-}
-
-
-static void sq_reset(void)
-{
-       sound_silence();
-       sq.active = 0;
-       sq.count = 0;
-       sq.front = (sq.rear+1) % sq.max_count;
-#if 0
-       init_tdm_buffers();
-#endif
-}
-
-
-static int sq_fsync(struct file *filp, struct dentry *dentry)
-{
-       int rc = 0;
-
-       sq.syncing = 1;
-       sq_play();      /* there may be an incomplete frame waiting */
-
-       while (sq.active) {
-               SLEEP(sq.sync_queue);
-               if (SIGNAL_RECEIVED) {
-                       /* While waiting for audio output to drain, an
-                        * interrupt occurred.  Stop audio output immediately
-                        * and clear the queue. */
-                       sq_reset();
-                       rc = -EINTR;
-                       break;
-               }
-       }
-
-       sq.syncing = 0;
-       return rc;
-}
-
-static int sq_release(struct inode *inode, struct file *file)
-{
-       int rc = 0;
-
-       if (sq.busy)
-               rc = sq_fsync(file, file->f_path.dentry);
-       sound.soft = sound.dsp;
-       sound.hard = sound.dsp;
-       sound_silence();
-
-       sq_release_read_buffers();
-       sq_release_buffers();
-
-       if (file->f_mode & FMODE_READ) {
-               read_sq.busy = 0;
-               WAKE_UP(read_sq.open_queue);
-       }
-
-       if (file->f_mode & FMODE_WRITE) {
-               sq.busy = 0;
-               WAKE_UP(sq.open_queue);
-       }
-
-       /* Shut down the SMC.
-       */
-       cpmp->cp_smc[1].smc_smcmr &= ~(SMCMR_TEN | SMCMR_REN);
-
-       /* Shut down the codec.
-       */
-       *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO;
-       eieio();
-       *((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_ENAUDIO;
-
-       /* Wake up a process waiting for the queue being released.
-        * Note: There may be several processes waiting for a call
-        * to open() returning. */
-
-       return rc;
-}
-
-
-static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                   u_long arg)
-{
-       u_long fmt;
-       int data;
-#if 0
-       int size, nbufs;
-#else
-       int size;
-#endif
-
-       switch (cmd) {
-       case SNDCTL_DSP_RESET:
-               sq_reset();
-               return 0;
-       case SNDCTL_DSP_POST:
-       case SNDCTL_DSP_SYNC:
-               return sq_fsync(file, file->f_path.dentry);
-
-               /* ++TeSche: before changing any of these it's
-                * probably wise to wait until sound playing has
-                * settled down. */
-       case SNDCTL_DSP_SPEED:
-               sq_fsync(file, file->f_path.dentry);
-               IOCTL_IN(arg, data);
-               return IOCTL_OUT(arg, sound_set_speed(data));
-       case SNDCTL_DSP_STEREO:
-               sq_fsync(file, file->f_path.dentry);
-               IOCTL_IN(arg, data);
-               return IOCTL_OUT(arg, sound_set_stereo(data));
-       case SOUND_PCM_WRITE_CHANNELS:
-               sq_fsync(file, file->f_path.dentry);
-               IOCTL_IN(arg, data);
-               return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
-       case SNDCTL_DSP_SETFMT:
-               sq_fsync(file, file->f_path.dentry);
-               IOCTL_IN(arg, data);
-               return IOCTL_OUT(arg, sound_set_format(data));
-       case SNDCTL_DSP_GETFMTS:
-               fmt = 0;
-               if (sound.trans_write) {
-                       if (sound.trans_write->ct_ulaw)
-                               fmt |= AFMT_MU_LAW;
-                       if (sound.trans_write->ct_alaw)
-                               fmt |= AFMT_A_LAW;
-                       if (sound.trans_write->ct_s8)
-                               fmt |= AFMT_S8;
-                       if (sound.trans_write->ct_u8)
-                               fmt |= AFMT_U8;
-                       if (sound.trans_write->ct_s16be)
-                               fmt |= AFMT_S16_BE;
-                       if (sound.trans_write->ct_u16be)
-                               fmt |= AFMT_U16_BE;
-                       if (sound.trans_write->ct_s16le)
-                               fmt |= AFMT_S16_LE;
-                       if (sound.trans_write->ct_u16le)
-                               fmt |= AFMT_U16_LE;
-               }
-               return IOCTL_OUT(arg, fmt);
-       case SNDCTL_DSP_GETBLKSIZE:
-               size = sq.block_size
-                       * sound.soft.size * (sound.soft.stereo + 1)
-                       / (sound.hard.size * (sound.hard.stereo + 1));
-               return IOCTL_OUT(arg, size);
-       case SNDCTL_DSP_SUBDIVIDE:
-               break;
-#if 0  /* Sorry can't do this at the moment.  The CPM allocated buffers
-        * long ago that can't be changed.
-        */
-       case SNDCTL_DSP_SETFRAGMENT:
-               if (sq.count || sq.active || sq.syncing)
-                       return -EINVAL;
-               IOCTL_IN(arg, size);
-               nbufs = size >> 16;
-               if (nbufs < 2 || nbufs > numBufs)
-                       nbufs = numBufs;
-               size &= 0xffff;
-               if (size >= 8 && size <= 30) {
-                       size = 1 << size;
-                       size *= sound.hard.size * (sound.hard.stereo + 1);
-                       size /= sound.soft.size * (sound.soft.stereo + 1);
-                       if (size > (bufSize << 10))
-                               size = bufSize << 10;
-               } else
-                       size = bufSize << 10;
-               sq_setup(numBufs, size, sound_buffers);
-               sq.max_active = nbufs;
-               return 0;
-#endif
-
-       default:
-               return mixer_ioctl(inode, file, cmd, arg);
-       }
-       return -EINVAL;
-}
-
-
-
-static const struct file_operations sq_fops =
-{
-       .owner =        THIS_MODULE,
-       .llseek =       sound_lseek,
-       .read =         sq_read,                        /* sq_read */
-       .write =        sq_write,
-       .ioctl =        sq_ioctl,
-       .open =         sq_open,
-       .release =      sq_release,
-};
-
-
-static void __init sq_init(void)
-{
-       sq_unit = register_sound_dsp(&sq_fops, -1);
-       if (sq_unit < 0)
-               return;
-
-       init_waitqueue_head(&sq.action_queue);
-       init_waitqueue_head(&sq.open_queue);
-       init_waitqueue_head(&sq.sync_queue);
-       init_waitqueue_head(&read_sq.action_queue);
-       init_waitqueue_head(&read_sq.open_queue);
-       init_waitqueue_head(&read_sq.sync_queue);
-
-       sq.busy = 0;
-       read_sq.busy = 0;
-
-       /* whatever you like as startup mode for /dev/dsp,
-        * (/dev/audio hasn't got a startup mode). note that
-        * once changed a new open() will *not* restore these!
-        */
-       sound.dsp.format = AFMT_S16_BE;
-       sound.dsp.stereo = 1;
-       sound.dsp.size = 16;
-
-       /* set minimum rate possible without expanding */
-       sound.dsp.speed = 8000;
-
-       /* before the first open to /dev/dsp this wouldn't be set */
-       sound.soft = sound.dsp;
-       sound.hard = sound.dsp;
-
-       sound_silence();
-}
-
-/*
- * /dev/sndstat
- */
-
-
-/* state.buf should not overflow! */
-
-static int state_open(struct inode *inode, struct file *file)
-{
-       char *buffer = state.buf, *mach = "", cs4218_buf[50];
-       int len = 0;
-
-       if (state.busy)
-               return -EBUSY;
-
-       state.ptr = 0;
-       state.busy = 1;
-
-       sprintf(cs4218_buf, "Crystal CS4218 on TDM, ");
-       mach = cs4218_buf;
-
-       len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
-
-       len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
-       switch (sound.soft.format) {
-       case AFMT_MU_LAW:
-               len += sprintf(buffer+len, " (mu-law)");
-               break;
-       case AFMT_A_LAW:
-               len += sprintf(buffer+len, " (A-law)");
-               break;
-       case AFMT_U8:
-               len += sprintf(buffer+len, " (unsigned 8 bit)");
-               break;
-       case AFMT_S8:
-               len += sprintf(buffer+len, " (signed 8 bit)");
-               break;
-       case AFMT_S16_BE:
-               len += sprintf(buffer+len, " (signed 16 bit big)");
-               break;
-       case AFMT_U16_BE:
-               len += sprintf(buffer+len, " (unsigned 16 bit big)");
-               break;
-       case AFMT_S16_LE:
-               len += sprintf(buffer+len, " (signed 16 bit little)");
-               break;
-       case AFMT_U16_LE:
-               len += sprintf(buffer+len, " (unsigned 16 bit little)");
-               break;
-       }
-       len += sprintf(buffer+len, "\n");
-       len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
-                      sound.soft.speed, sound.hard.speed);
-       len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
-                      sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
-       len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
-                      " sq.max_active = %d\n",
-                      sq.block_size, sq.max_count, sq.max_active);
-       len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
-                      sq.rear_size);
-       len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
-                      sq.active, sq.syncing);
-       state.len = len;
-       return nonseekable_open(inode, file);
-}
-
-
-static int state_release(struct inode *inode, struct file *file)
-{
-       state.busy = 0;
-       return 0;
-}
-
-
-static ssize_t state_read(struct file *file, char *buf, size_t count,
-                         loff_t *ppos)
-{
-       int n = state.len - state.ptr;
-       if (n > count)
-               n = count;
-       if (n <= 0)
-               return 0;
-       if (copy_to_user(buf, &state.buf[state.ptr], n))
-               return -EFAULT;
-       state.ptr += n;
-       return n;
-}
-
-
-static const struct file_operations state_fops =
-{
-       .owner =        THIS_MODULE,
-       .llseek =       sound_lseek,
-       .read =         state_read,
-       .open =         state_open,
-       .release =      state_release,
-};
-
-
-static void __init state_init(void)
-{
-       state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
-       if (state_unit < 0)
-               return;
-       state.busy = 0;
-}
-
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig)
-{
-       return -ESPIPE;
-}
-
-
-/*** Config & Setup **********************************************************/
-
-
-int __init tdm8xx_sound_init(void)
-{
-       int i, has_sound;
-       uint                    dp_offset;
-       volatile uint           *sirp;
-       volatile cbd_t          *bdp;
-       volatile cpm8xx_t       *cp;
-       volatile smc_t          *sp;
-       volatile smc_uart_t     *up;
-       volatile immap_t        *immap;
-
-       has_sound = 0;
-
-       /* Program the SI/TSA to use TDMa, connected to SMC2, for 4 bytes.
-       */
-       cp = cpmp;      /* Get pointer to Communication Processor */
-       immap = (immap_t *)IMAP_ADDR;   /* and to internal registers */
-
-       /* Set all TDMa control bits to zero.  This enables most features
-        * we want.
-        */
-       cp->cp_simode &= ~0x00000fff;
-
-       /* Enable common receive/transmit clock pins, use IDL format.
-        * Sync on falling edge, transmit rising clock, receive falling
-        * clock, delay 1 bit on both Tx and Rx.  Common Tx/Rx clocks and
-        * sync.
-        * Connect SMC2 to TSA.
-        */
-       cp->cp_simode |= 0x80000141;
-
-       /* Configure port A pins for TDMa operation.
-        * The RPX-Lite (MPC850/823) loses SMC2 when TDM is used.
-        */
-       immap->im_ioport.iop_papar |= 0x01c0; /* Enable TDMa functions */
-       immap->im_ioport.iop_padir |= 0x00c0; /* Enable TDMa Tx/Rx */
-       immap->im_ioport.iop_padir &= ~0x0100; /* Enable L1RCLKa */
-
-       immap->im_ioport.iop_pcpar |= 0x0800; /* Enable L1RSYNCa */
-       immap->im_ioport.iop_pcdir &= ~0x0800;
-
-       /* Initialize the SI TDM routing table.  We use TDMa only.
-        * The receive table and transmit table each have only one
-        * entry, to capture/send four bytes after each frame pulse.
-        * The 16-bit ram entry is 0000 0001 1000 1111. (SMC2)
-        */
-       cp->cp_sigmr = 0;
-       sirp = (uint *)cp->cp_siram;
-
-       *sirp = 0x018f0000;             /* Receive entry */
-       sirp += 64;
-       *sirp = 0x018f0000;             /* Tramsmit entry */
-
-       /* Enable single TDMa routing.
-       */
-       cp->cp_sigmr = 0x04;
-
-       /* Initialize the SMC for transparent operation.
-       */
-       sp = &cpmp->cp_smc[1];
-       up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC2];
-
-       /* We need to allocate a transmit and receive buffer
-        * descriptors from dual port ram.
-        */
-       dp_addr = cpm_dpalloc(sizeof(cbd_t) * numReadBufs, 8);
-
-       /* Set the physical address of the host memory
-        * buffers in the buffer descriptors, and the
-        * virtual address for us to work with.
-        */
-       bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
-       up->smc_rbase = dp_offset;
-       rx_cur = rx_base = (cbd_t *)bdp;
-
-       for (i=0; i<(numReadBufs-1); i++) {
-               bdp->cbd_bufaddr = 0;
-               bdp->cbd_datlen = 0;
-               bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
-               bdp++;
-       }
-       bdp->cbd_bufaddr = 0;
-       bdp->cbd_datlen = 0;
-       bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
-
-       /* Now, do the same for the transmit buffers.
-       */
-       dp_offset = cpm_dpalloc(sizeof(cbd_t) * numBufs, 8);
-
-       bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
-       up->smc_tbase = dp_offset;
-       tx_cur = tx_base = (cbd_t *)bdp;
-
-       for (i=0; i<(numBufs-1); i++) {
-               bdp->cbd_bufaddr = 0;
-               bdp->cbd_datlen = 0;
-               bdp->cbd_sc = BD_SC_INTRPT;
-               bdp++;
-       }
-       bdp->cbd_bufaddr = 0;
-       bdp->cbd_datlen = 0;
-       bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
-
-       /* Set transparent SMC mode.
-        * A few things are specific to our application.  The codec interface
-        * is MSB first, hence the REVD selection.  The CD/CTS pulse are
-        * used by the TSA to indicate the frame start to the SMC.
-        */
-       up->smc_rfcr = SCC_EB;
-       up->smc_tfcr = SCC_EB;
-       up->smc_mrblr = readbufSize * 1024;
-
-       /* Set 16-bit reversed data, transparent mode.
-       */
-       sp->smc_smcmr = smcr_mk_clen(15) |
-               SMCMR_SM_TRANS | SMCMR_REVD | SMCMR_BS;
-
-       /* Enable and clear events.
-        * Because of FIFO delays, all we need is the receive interrupt
-        * and we can process both the current receive and current
-        * transmit interrupt within a few microseconds of the transmit.
-        */
-       sp->smc_smce = 0xff;
-       sp->smc_smcm = SMCM_TXE | SMCM_TX | SMCM_RX;
-
-       /* Send the CPM an initialize command.
-       */
-       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
-                               CPM_CR_INIT_TRX) | CPM_CR_FLG;
-       while (cp->cp_cpcr & CPM_CR_FLG);
-
-       sound.mach = mach_cs4218;
-       has_sound = 1;
-
-       /* Initialize beep stuff */
-       orig_mksound = kd_mksound;
-       kd_mksound = cs_mksound;
-       beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
-       if (beep_buf == NULL)
-               printk(KERN_WARNING "dmasound: no memory for "
-                      "beep buffer\n");
-
-       if (!has_sound)
-               return -ENODEV;
-
-       /* Initialize the software SPI.
-       */
-       sw_spi_init();
-
-       /* Set up sound queue, /dev/audio and /dev/dsp. */
-
-       /* Set default settings. */
-       sq_init();
-
-       /* Set up /dev/sndstat. */
-       state_init();
-
-       /* Set up /dev/mixer. */
-       mixer_init();
-
-       if (!sound.mach.irqinit()) {
-               printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
-               return -ENODEV;
-       }
-#ifdef MODULE
-       irq_installed = 1;
-#endif
-
-       printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
-              numBufs, bufSize);
-
-       return 0;
-}
-
-/* Due to FIFOs and bit delays, the transmit interrupt occurs a few
- * microseconds ahead of the receive interrupt.
- * When we get an interrupt, we service the transmit first, then
- * check for a receive to prevent the overhead of returning through
- * the interrupt handler only to get back here right away during
- * full duplex operation.
- */
-static void
-cs4218_intr(void *dev_id)
-{
-       volatile smc_t  *sp;
-       volatile cpm8xx_t       *cp;
-
-       sp = &cpmp->cp_smc[1];
-
-       if (sp->smc_smce & SCCM_TX) {
-               sp->smc_smce = SCCM_TX;
-               cs4218_tdm_tx_intr((void *)sp);
-       }
-
-       if (sp->smc_smce & SCCM_RX) {
-               sp->smc_smce = SCCM_RX;
-               cs4218_tdm_rx_intr((void *)sp);
-       }
-
-       if (sp->smc_smce & SCCM_TXE) {
-               /* Transmit underrun.  This happens with the application
-                * didn't keep up sending buffers.  We tell the SMC to
-                * restart, which will cause it to poll the current (next)
-                * BD.  If the user supplied data since this occurred,
-                * we just start running again.  If they didn't, the SMC
-                * will poll the descriptor until data is placed there.
-                */
-               sp->smc_smce = SCCM_TXE;
-               cp = cpmp;      /* Get pointer to Communication Processor */
-               cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
-                                       CPM_CR_RESTART_TX) | CPM_CR_FLG;
-               while (cp->cp_cpcr & CPM_CR_FLG);
-       }
-}
-
-
-#define MAXARGS                8       /* Should be sufficient for now */
-
-void __init dmasound_setup(char *str, int *ints)
-{
-       /* check the bootstrap parameter for "dmasound=" */
-
-       switch (ints[0]) {
-       case 3:
-               if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
-                       printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
-               else
-                       catchRadius = ints[3];
-               /* fall through */
-       case 2:
-               if (ints[1] < MIN_BUFFERS)
-                       printk("dmasound_setup: invalid number of buffers, using default = %d\n", numBufs);
-               else
-                       numBufs = ints[1];
-               if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
-                       printk("dmasound_setup: invalid buffer size, using default = %d\n", bufSize);
-               else
-                       bufSize = ints[2];
-               break;
-       case 0:
-               break;
-       default:
-               printk("dmasound_setup: invalid number of arguments\n");
-       }
-}
-
-/* Software SPI functions.
- * These are on Port B.
- */
-#define PB_SPICLK      ((uint)0x00000002)
-#define PB_SPIMOSI     ((uint)0x00000004)
-#define PB_SPIMISO     ((uint)0x00000008)
-
-static
-void   sw_spi_init(void)
-{
-       volatile cpm8xx_t       *cp;
-       volatile uint           *hcsr4;
-
-       hcsr4 = (volatile uint *)HIOX_CSR4_ADDR;
-       cp = cpmp;      /* Get pointer to Communication Processor */
-
-       *hcsr4 &= ~HIOX_CSR4_AUDSPISEL; /* Disable SPI select */
-
-       /* Make these Port B signals general purpose I/O.
-        * First, make sure the clock is low.
-        */
-       cp->cp_pbdat &= ~PB_SPICLK;
-       cp->cp_pbpar &= ~(PB_SPICLK | PB_SPIMOSI | PB_SPIMISO);
-
-       /* Clock and Master Output are outputs.
-       */
-       cp->cp_pbdir |= (PB_SPICLK | PB_SPIMOSI);
-
-       /* Master Input.
-       */
-       cp->cp_pbdir &= ~PB_SPIMISO;
-
-}
-
-/* Write the CS4218 control word out the SPI port.  While the
- * the control word is going out, the status word is arriving.
- */
-static
-uint   cs4218_ctl_write(uint ctlreg)
-{
-       uint    status;
-
-       sw_spi_io((u_char *)&ctlreg, (u_char *)&status, 4);
-
-       /* Shadow the control register.....I guess we could do
-        * the same for the status, but for now we just return it
-        * and let the caller decide.
-        */
-       cs4218_control = ctlreg;
-       return status;
-}
-
-static
-void   sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt)
-{
-       int     bits, i;
-       u_char  outbyte, inbyte;
-       volatile cpm8xx_t       *cp;
-       volatile uint           *hcsr4;
-
-       hcsr4 = (volatile uint *)HIOX_CSR4_ADDR;
-       cp = cpmp;      /* Get pointer to Communication Processor */
-
-       /* The timing on the bus is pretty slow.  Code inefficiency
-        * and eieio() is our friend here :-).
-        */
-       cp->cp_pbdat &= ~PB_SPICLK;
-       *hcsr4 |= HIOX_CSR4_AUDSPISEL;  /* Enable SPI select */
-       eieio();
-
-       /* Clock in/out the bytes.  Data is valid on the falling edge
-        * of the clock.  Data is MSB first.
-        */
-       for (i=0; i<bcnt; i++) {
-               outbyte = *obuf++;
-               inbyte = 0;
-               for (bits=0; bits<8; bits++) {
-                       eieio();
-                       cp->cp_pbdat |= PB_SPICLK;
-                       eieio();
-                       if (outbyte & 0x80)
-                               cp->cp_pbdat |= PB_SPIMOSI;
-                       else
-                               cp->cp_pbdat &= ~PB_SPIMOSI;
-                       eieio();
-                       cp->cp_pbdat &= ~PB_SPICLK;
-                       eieio();
-                       outbyte <<= 1;
-                       inbyte <<= 1;
-                       if (cp->cp_pbdat & PB_SPIMISO)
-                               inbyte |= 1;
-               }
-               *ibuf++ = inbyte;
-       }
-
-       *hcsr4 &= ~HIOX_CSR4_AUDSPISEL; /* Disable SPI select */
-       eieio();
-}
-
-void cleanup_module(void)
-{
-       if (irq_installed) {
-               sound_silence();
-#ifdef MODULE
-               sound.mach.irqcleanup();
-#endif
-       }
-
-       sq_release_read_buffers();
-       sq_release_buffers();
-
-       if (mixer_unit >= 0)
-               unregister_sound_mixer(mixer_unit);
-       if (state_unit >= 0)
-               unregister_sound_special(state_unit);
-       if (sq_unit >= 0)
-               unregister_sound_dsp(sq_unit);
-}
-
-module_init(tdm8xx_sound_init);
-module_exit(cleanup_module);
-
index 8e1fccd96fc029a252f58c67c181bca0012abc10..9589969cec725d86b1817d0248efc244ec8b73ae 100644 (file)
@@ -57,7 +57,8 @@ unsigned char *ISA_io = NULL;
 
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
        || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-       || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+       || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+       || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
 extern unsigned long com_port;
 
 extern int serial_tstc(unsigned long com_port);
@@ -80,7 +81,8 @@ int tstc(void)
 {
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
        || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-       || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+       || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+       || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
        if(keyb_present)
                return (CRT_tstc() || serial_tstc(com_port));
        else
@@ -95,7 +97,8 @@ int getc(void)
        while (1) {
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
        || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-       || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+       || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+       || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
                if (serial_tstc(com_port))
                        return (serial_getc(com_port));
 #endif /* serial console */
@@ -112,7 +115,8 @@ putc(const char c)
 
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
        || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-       || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+       || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+       || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
        serial_putc(com_port, c);
        if ( c == '\n' )
                serial_putc(com_port, '\r');
@@ -161,7 +165,8 @@ void puts(const char *s)
        while ( ( c = *s++ ) != '\0' ) {
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
        || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-       || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+       || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+       || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
                serial_putc(com_port, c);
                if ( c == '\n' ) serial_putc(com_port, '\r');
 #endif /* serial console */
index bcfb6cde70c4c90b8463ec37fc25a1291b90eda6..5b877792d14f6566feee08f21cb9b5ce8d000451 100644 (file)
@@ -201,6 +201,7 @@ boot-$(CONFIG_8260)         += m8260_tty.o
 endif
 boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE)  += mpc52xx_tty.o
 boot-$(CONFIG_SERIAL_MPSC_CONSOLE)     += mv64x60_tty.o
+boot-$(CONFIG_SERIAL_UARTLITE_CONSOLE) += uartlite_tty.o
 
 LIBS                           := $(common)/lib.a $(bootlib)/lib.a
 ifeq ($(CONFIG_PPC_PREP),y)
diff --git a/arch/ppc/boot/simple/uartlite_tty.c b/arch/ppc/boot/simple/uartlite_tty.c
new file mode 100644 (file)
index 0000000..0eae1ea
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Xilinx UARTLITE bootloader driver
+ *
+ * Copyright (c) 2007 Secret Lab Technologies Ltd.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+#define UARTLITE_BASEADDR ((void*)(XPAR_UARTLITE_0_BASEADDR))
+
+void
+serial_putc(unsigned long com_port, unsigned char c)
+{
+       while ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x08) != 0); /* spin */
+       out_be32(UARTLITE_BASEADDR + 0x4, c);
+}
+
+unsigned char
+serial_getc(unsigned long com_port)
+{
+       while ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x01) == 0); /* spin */
+       return in_be32(UARTLITE_BASEADDR);
+}
+
+int
+serial_tstc(unsigned long com_port)
+{
+       return ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x01) != 0);
+}
index 1f91eca2f3d70125f7e408a44d9e28feb16e4ec7..c5850a272650b688e462a9b1415e9c3514df5f1c 100644 (file)
@@ -40,7 +40,6 @@ main(void)
        DEFINE(PTRACE, offsetof(struct task_struct, ptrace));
        DEFINE(KSP, offsetof(struct thread_struct, ksp));
        DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
-       DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
        DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
        DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
        DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
index a9d455369dc6b5a6ddb9455747c695dbe4079d04..ab64256110bd2ab2547d34f359877b40874b0717 100644 (file)
@@ -191,7 +191,6 @@ stack_ovf:
 0:
 
 _GLOBAL(DoSyscall)
-       stw     r0,THREAD+LAST_SYSCALL(r2)
        stw     r3,ORIG_GPR3(r1)
        li      r12,0
        stw     r12,RESULT(r1)
index 705ae56016f002e7f17e55eb1364bdc10063822e..76551b6790300b8879ee0dfa0afeff71cadc8d1f 100644 (file)
@@ -29,6 +29,7 @@ config CPCI405
 
 config EP405
        bool "EP405/EP405PC"
+       select EMBEDDEDBOOT
        help
          This option enables support for the EP405/EP405PC boards.
 
@@ -54,11 +55,15 @@ config WALNUT
 
 config XILINX_ML300
        bool "Xilinx-ML300"
+       select XILINX_VIRTEX_II_PRO
+       select EMBEDDEDBOOT
        help
          This option enables support for the Xilinx ML300 evaluation board.
 
 config XILINX_ML403
        bool "Xilinx-ML403"
+       select XILINX_VIRTEX_4_FX
+       select EMBEDDEDBOOT
        help
          This option enables support for the Xilinx ML403 evaluation board.
 endchoice
@@ -215,18 +220,14 @@ config 405GPR
 
 config XILINX_VIRTEX_II_PRO
        bool
-       depends on XILINX_ML300
-       default y
+       select XILINX_VIRTEX
 
 config XILINX_VIRTEX_4_FX
        bool
-       depends on XILINX_ML403
-       default y
+       select XILINX_VIRTEX
 
 config XILINX_VIRTEX
        bool
-       depends on XILINX_VIRTEX_II_PRO || XILINX_VIRTEX_4_FX
-       default y
 
 config STB03xxx
        bool
@@ -235,8 +236,6 @@ config STB03xxx
 
 config EMBEDDEDBOOT
        bool
-       depends on EP405 || XILINX_ML300 || XILINX_ML403
-       default y
 
 config IBM_OPENBIOS
        bool
index fa6610bccaf9872fa6be6af592d025f51652f56e..723ad7985cc65e1109192601aea7082742c0acd8 100644 (file)
@@ -28,5 +28,4 @@ obj-$(CONFIG_440SP)           += ibm440sp.o
 obj-$(CONFIG_440SPE)           += ppc440spe.o
 obj-$(CONFIG_405EP)            += ibm405ep.o
 obj-$(CONFIG_405GPR)           += ibm405gpr.o
-obj-$(CONFIG_XILINX_VIRTEX)    += virtex.o
 
index 84e999d9a7bb950494675f6f09dd49c25ed6ffff..5e994e146ba864858c05159cd7c52efb2aa909b0 100644 (file)
@@ -178,7 +178,7 @@ ocotea_setup_pcix(void)
        /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
        PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
        PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
-       PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+       PCIX_WRITEL(0x80000007, PCIX0_PIM0SA);
 
        eieio();
 }
@@ -289,7 +289,7 @@ ocotea_setup_arch(void)
         * from FPGA, because it can be changed by on-board switches
         * --ebs
         */
-       ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200);
+       ibm440gx_get_clocks(&clocks, 33300000, 6 * 1843200);
        ocp_sys_info.opb_bus_freq = clocks.opb;
 
        /* Setup TODC access */
index bb0253eef45ab0c19bd739e1e1ba3a478160317c..5d9af8ddb155d84da625a147c2bf19b582ba0498 100644 (file)
@@ -235,7 +235,7 @@ taishan_setup_pcix(void)
        /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
        PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
        PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
-       PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+       PCIX_WRITEL(0x80000007, PCIX0_PIM0SA);
        PCIX_WRITEL(0xffffffff, PCIX0_PIM0SAH);
 
        iounmap(pcix_reg_base);
diff --git a/arch/ppc/platforms/4xx/virtex.c b/arch/ppc/platforms/4xx/virtex.c
deleted file mode 100644 (file)
index 133a831..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Virtex-II Pro & Virtex-4 FX common infrastructure
- *
- * Maintainer: Grant Likely <grant.likely@secretlab.ca>
- *
- * Copyright 2005 Secret Lab Technologies Ltd.
- * Copyright 2005 General Dynamics Canada Ltd.
- * Copyright 2005 Freescale Semiconductor Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/serial_8250.h>
-#include <asm/ppc_sys.h>
-#include <platforms/4xx/virtex.h>
-#include <platforms/4xx/xparameters/xparameters.h>
-
-#define XPAR_UART(num) { \
-               .mapbase  = XPAR_UARTNS550_##num##_BASEADDR + 3, \
-               .irq      = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
-               .iotype   = UPIO_MEM, \
-               .uartclk  = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \
-               .flags    = UPF_BOOT_AUTOCONF, \
-               .regshift = 2, \
-       }
-
-struct plat_serial8250_port serial_platform_data[] = {
-#ifdef XPAR_UARTNS550_0_BASEADDR
-       XPAR_UART(0),
-#endif
-#ifdef XPAR_UARTNS550_1_BASEADDR
-       XPAR_UART(1),
-#endif
-#ifdef XPAR_UARTNS550_2_BASEADDR
-       XPAR_UART(2),
-#endif
-#ifdef XPAR_UARTNS550_3_BASEADDR
-       XPAR_UART(3),
-#endif
-       { }, /* terminated by empty record */
-};
-
-struct platform_device ppc_sys_platform_devices[] = {
-       [VIRTEX_UART] = {
-               .name           = "serial8250",
-               .id             = 0,
-               .dev.platform_data = serial_platform_data,
-       },
-};
-
index c14325dfd7b1fe2eda759d91f90f43bca4806220..738280420be5627a01b5c6f7e929d6f3edea5681 100644 (file)
@@ -1,35 +1,35 @@
 /*
- * arch/ppc/platforms/4xx/virtex.h
+ * Basic Virtex platform defines, included by <asm/ibm4xx.h>
  *
- * Include file that defines the Xilinx Virtex-II Pro processor
+ * 2005-2007 (c) Secret Lab Technologies Ltd.
+ * 2002-2004 (c) MontaVista Software, Inc.
  *
- * Author: MontaVista Software, Inc.
- *         source@mvista.com
- *
- * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
- * terms of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
  */
 
 #ifdef __KERNEL__
 #ifndef __ASM_VIRTEX_H__
 #define __ASM_VIRTEX_H__
 
-/* serial defines */
-
 #include <asm/ibm405.h>
+#include <asm/ppcboot.h>
 
 /* Ugly, ugly, ugly! BASE_BAUD defined here to keep 8250.c happy. */
 #if !defined(BASE_BAUD)
  #define BASE_BAUD             (0) /* dummy value; not used */
 #endif
-  
-/* Device type enumeration for platform bus definitions */
+
 #ifndef __ASSEMBLY__
-enum ppc_sys_devices {
-       VIRTEX_UART, NUM_PPC_SYS_DEVS,
-};
-#endif
-  
+extern const char* virtex_machine_name;
+#define PPC4xx_MACHINE_NAME (virtex_machine_name)
+#endif /* !__ASSEMBLY__ */
+
+/* We don't need anything mapped.  Size of zero will accomplish that. */
+#define PPC4xx_ONB_IO_PADDR    0u
+#define PPC4xx_ONB_IO_VADDR    0u
+#define PPC4xx_ONB_IO_SIZE     0u
+
 #endif                         /* __ASM_VIRTEX_H__ */
 #endif                         /* __KERNEL__ */
index fb5f0b5e13d1e5461abc98872140ed0799e76d24..6e522fefc26f779c17b62bbbd96ae5c7eba0169b 100644 (file)
@@ -18,9 +18,9 @@
 #include <linux/serialP.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/ppc_sys.h>
 
 #include <syslib/gen550.h>
+#include <syslib/virtex_devices.h>
 #include <platforms/4xx/xparameters/xparameters.h>
 
 /*
  *          ppc4xx_pic_init                    arch/ppc/syslib/xilinx_pic.c
  */
 
-/* Board specifications structures */
-struct ppc_sys_spec *cur_ppc_sys_spec;
-struct ppc_sys_spec ppc_sys_specs[] = {
-       {
-               /* Only one entry, always assume the same design */
-               .ppc_sys_name   = "Xilinx ML300 Reference Design",
-               .mask           = 0x00000000,
-               .value          = 0x00000000,
-               .num_devices    = 1,
-               .device_list    = (enum ppc_sys_devices[])
-               {
-                       VIRTEX_UART,
-               },
-       },
-};
+const char* virtex_machine_name = "ML300 Reference Design";
 
 #if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
-
 static volatile unsigned *powerdown_base =
     (volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
 
@@ -95,52 +80,14 @@ ml300_map_io(void)
 #endif
 }
 
-/* Early serial support functions */
-static void __init
-ml300_early_serial_init(int num, struct plat_serial8250_port *pdata)
-{
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
-       struct uart_port serial_req;
-
-       memset(&serial_req, 0, sizeof(serial_req));
-       serial_req.mapbase      = pdata->mapbase;
-       serial_req.membase      = pdata->membase;
-       serial_req.irq          = pdata->irq;
-       serial_req.uartclk      = pdata->uartclk;
-       serial_req.regshift     = pdata->regshift;
-       serial_req.iotype       = pdata->iotype;
-       serial_req.flags        = pdata->flags;
-       gen550_init(num, &serial_req);
-#endif
-}
-
-void __init
-ml300_early_serial_map(void)
-{
-#ifdef CONFIG_SERIAL_8250
-       struct plat_serial8250_port *pdata;
-       int i = 0;
-
-       pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART);
-       while(pdata && pdata->flags)
-       {
-               pdata->membase = ioremap(pdata->mapbase, 0x100);
-               ml300_early_serial_init(i, pdata);
-               pdata++;
-               i++;
-       }
-#endif /* CONFIG_SERIAL_8250 */
-}
-
 void __init
 ml300_setup_arch(void)
 {
-       ml300_early_serial_map();
+       virtex_early_serial_map();
        ppc4xx_setup_arch();    /* calls ppc4xx_find_bridges() */
 
        /* Identify the system */
-       printk(KERN_INFO "Xilinx Virtex-II Pro port\n");
-       printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+       printk(KERN_INFO "Xilinx ML300 Reference System (Virtex-II Pro)\n");
 }
 
 /* Called after board_setup_irq from ppc4xx_init_IRQ(). */
@@ -156,8 +103,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 {
        ppc4xx_init(r3, r4, r5, r6, r7);
 
-       identify_ppc_sys_by_id(mfspr(SPRN_PVR));
-
        ppc_md.setup_arch = ml300_setup_arch;
        ppc_md.setup_io_mappings = ml300_map_io;
        ppc_md.init_IRQ = ml300_init_irq;
@@ -167,7 +112,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 #endif
 
 #ifdef CONFIG_KGDB
-       ppc_md.early_serial_map = ml300_early_serial_map;
+       ppc_md.early_serial_map = virtex_early_serial_map;
 #endif
 }
 
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.h b/arch/ppc/platforms/4xx/xilinx_ml300.h
deleted file mode 100644 (file)
index 3d57332..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Include file that defines the Xilinx ML300 evaluation board
- *
- * Author: MontaVista Software, Inc.
- *         source@mvista.com
- *
- * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
- * terms of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_XILINX_ML300_H__
-#define __ASM_XILINX_ML300_H__
-
-/* ML300 has a Xilinx Virtex-II Pro processor */
-#include <platforms/4xx/virtex.h>
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-typedef struct board_info {
-       unsigned int     bi_memsize;            /* DRAM installed, in bytes */
-       unsigned char    bi_enetaddr[6];        /* Local Ethernet MAC address */
-       unsigned int     bi_intfreq;            /* Processor speed, in Hz */
-       unsigned int     bi_busfreq;            /* PLB Bus speed, in Hz */
-       unsigned int     bi_pci_busfreq;        /* PCI Bus speed, in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-#endif /* !__ASSEMBLY__ */
-
-/* We don't need anything mapped.  Size of zero will accomplish that. */
-#define PPC4xx_ONB_IO_PADDR    0u
-#define PPC4xx_ONB_IO_VADDR    0u
-#define PPC4xx_ONB_IO_SIZE     0u
-
-#define PPC4xx_MACHINE_NAME "Xilinx ML300 Reference System"
-
-#endif /* __ASM_XILINX_ML300_H__ */
-#endif /* __KERNEL__ */
index cb3bf7a2bcbed6295ea7c8d9fca72acc1beb955d..bc3ace3762e78d6f3885df4ee325ec30140e7d57 100644 (file)
@@ -1,11 +1,9 @@
 /*
- * arch/ppc/platforms/4xx/xilinx_ml403.c
- *
  * Xilinx ML403 evaluation board initialization
  *
  * Author: Grant Likely <grant.likely@secretlab.ca>
  *
- * 2005 (c) Secret Lab Technologies Ltd.
+ * 2005-2007 (c) Secret Lab Technologies Ltd.
  * 2002-2004 (c) MontaVista Software, Inc.
  *
  * This file is licensed under the terms of the GNU General Public License
@@ -22,9 +20,9 @@
 #include <linux/serialP.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/ppc_sys.h>
 
 #include <syslib/gen550.h>
+#include <syslib/virtex_devices.h>
 #include <platforms/4xx/xparameters/xparameters.h>
 
 /*
  *          ppc4xx_pic_init                    arch/ppc/syslib/xilinx_pic.c
  */
 
-/* Board specifications structures */
-struct ppc_sys_spec *cur_ppc_sys_spec;
-struct ppc_sys_spec ppc_sys_specs[] = {
-       {
-               /* Only one entry, always assume the same design */
-               .ppc_sys_name   = "Xilinx ML403 Reference Design",
-               .mask           = 0x00000000,
-               .value          = 0x00000000,
-               .num_devices    = 1,
-               .device_list    = (enum ppc_sys_devices[])
-               {
-                       VIRTEX_UART,
-               },
-       },
-};
+const char* virtex_machine_name = "ML403 Reference Design";
 
 #if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
-
 static volatile unsigned *powerdown_base =
     (volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
 
@@ -99,47 +82,10 @@ ml403_map_io(void)
 #endif
 }
 
-/* Early serial support functions */
-static void __init
-ml403_early_serial_init(int num, struct plat_serial8250_port *pdata)
-{
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
-       struct uart_port serial_req;
-
-       memset(&serial_req, 0, sizeof(serial_req));
-       serial_req.mapbase      = pdata->mapbase;
-       serial_req.membase      = pdata->membase;
-       serial_req.irq          = pdata->irq;
-       serial_req.uartclk      = pdata->uartclk;
-       serial_req.regshift     = pdata->regshift;
-       serial_req.iotype       = pdata->iotype;
-       serial_req.flags        = pdata->flags;
-       gen550_init(num, &serial_req);
-#endif
-}
-
-void __init
-ml403_early_serial_map(void)
-{
-#ifdef CONFIG_SERIAL_8250
-       struct plat_serial8250_port *pdata;
-       int i = 0;
-
-       pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART);
-       while(pdata && pdata->flags)
-       {
-               pdata->membase = ioremap(pdata->mapbase, 0x100);
-               ml403_early_serial_init(i, pdata);
-               pdata++;
-               i++;
-       }
-#endif /* CONFIG_SERIAL_8250 */
-}
-
 void __init
 ml403_setup_arch(void)
 {
-       ml403_early_serial_map();
+       virtex_early_serial_map();
        ppc4xx_setup_arch();    /* calls ppc4xx_find_bridges() */
 
        /* Identify the system */
@@ -159,8 +105,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 {
        ppc4xx_init(r3, r4, r5, r6, r7);
 
-       identify_ppc_sys_by_id(mfspr(SPRN_PVR));
-
        ppc_md.setup_arch = ml403_setup_arch;
        ppc_md.setup_io_mappings = ml403_map_io;
        ppc_md.init_IRQ = ml403_init_irq;
@@ -170,7 +114,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 #endif
 
 #ifdef CONFIG_KGDB
-       ppc_md.early_serial_map = ml403_early_serial_map;
+       ppc_md.early_serial_map = virtex_early_serial_map;
 #endif
 }
 
diff --git a/arch/ppc/platforms/4xx/xilinx_ml403.h b/arch/ppc/platforms/4xx/xilinx_ml403.h
deleted file mode 100644 (file)
index 4735969..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * arch/ppc/platforms/4xx/xilinx_ml403.h
- *
- * Include file that defines the Xilinx ML403 reference design
- *
- * Author: Grant Likely <grant.likely@secretlab.ca>
- *
- * 2005 (c) Secret Lab Technologies Ltd.
- * 2002-2004 (c) MontaVista Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_XILINX_ML403_H__
-#define __ASM_XILINX_ML403_H__
-
-/* ML403 has a Xilinx Virtex-4 FPGA with a PPC405 hard core */
-#include <platforms/4xx/virtex.h>
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-typedef struct board_info {
-       unsigned int     bi_memsize;            /* DRAM installed, in bytes */
-       unsigned char    bi_enetaddr[6];        /* Local Ethernet MAC address */
-       unsigned int     bi_intfreq;            /* Processor speed, in Hz */
-       unsigned int     bi_busfreq;            /* PLB Bus speed, in Hz */
-       unsigned int     bi_pci_busfreq;        /* PCI Bus speed, in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-#endif /* !__ASSEMBLY__ */
-
-/* We don't need anything mapped.  Size of zero will accomplish that. */
-#define PPC4xx_ONB_IO_PADDR    0u
-#define PPC4xx_ONB_IO_VADDR    0u
-#define PPC4xx_ONB_IO_SIZE     0u
-
-#define PPC4xx_MACHINE_NAME "Xilinx ML403 Reference Design"
-
-#endif /* __ASM_XILINX_ML403_H__ */
-#endif /* __KERNEL__ */
index 66ec5f35f306c096600f22bf7834ebd433b10b15..01aa043ff381354cb38fea8f13b06e0ddd7b8fb7 100644 (file)
        .io_type         = SERIAL_IO_MEM,                               \
   },
 #endif
+
+/*
+ * A few reasonable defaults for the #defines which could be missing depending
+ * on the IP version or variant (e.g. OPB vs PLB)
+ */
+
+#ifndef XPAR_EMAC_0_CAM_EXIST
+#define XPAR_EMAC_0_CAM_EXIST 0
+#endif
+#ifndef XPAR_EMAC_0_JUMBO_EXIST
+#define XPAR_EMAC_0_JUMBO_EXIST 0
+#endif
+#ifndef XPAR_EMAC_0_TX_DRE_TYPE
+#define XPAR_EMAC_0_TX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_0_RX_DRE_TYPE
+#define XPAR_EMAC_0_RX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_0_TX_INCLUDE_CSUM
+#define XPAR_EMAC_0_TX_INCLUDE_CSUM 0
+#endif
+#ifndef XPAR_EMAC_0_RX_INCLUDE_CSUM
+#define XPAR_EMAC_0_RX_INCLUDE_CSUM 0
+#endif
+
+#ifndef XPAR_EMAC_1_CAM_EXIST
+#define XPAR_EMAC_1_CAM_EXIST 0
+#endif
+#ifndef XPAR_EMAC_1_JUMBO_EXIST
+#define XPAR_EMAC_1_JUMBO_EXIST 0
+#endif
+#ifndef XPAR_EMAC_1_TX_DRE_TYPE
+#define XPAR_EMAC_1_TX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_1_RX_DRE_TYPE
+#define XPAR_EMAC_1_RX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_1_TX_INCLUDE_CSUM
+#define XPAR_EMAC_1_TX_INCLUDE_CSUM 0
+#endif
+#ifndef XPAR_EMAC_1_RX_INCLUDE_CSUM
+#define XPAR_EMAC_1_RX_INCLUDE_CSUM 0
+#endif
+
+#ifndef XPAR_GPIO_0_IS_DUAL
+#define XPAR_GPIO_0_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_1_IS_DUAL
+#define XPAR_GPIO_1_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_2_IS_DUAL
+#define XPAR_GPIO_2_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_3_IS_DUAL
+#define XPAR_GPIO_3_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_4_IS_DUAL
+#define XPAR_GPIO_4_IS_DUAL 0
+#endif
+
index 57a2a55dab8c57a7fc26d89a3a967ebbbfe34064..a3c1118e5b0930344356a0cb27e7b855a16db2ac 100644 (file)
@@ -69,10 +69,6 @@ extern bd_t m8xx_board_info;
 #define BCSR2_QSPACESEL                ((uint)0x00004000)
 #define BCSR2_FETHLEDMODE      ((uint)0x00000800)      /* CLLF */
 
-#if defined(CONFIG_HTDMSOUND)
-#include <platforms/rpxhiox.h>
-#endif
-
 /* define IO_BASE for pcmcia, CLLF only */
 #if !defined(CONFIG_PCI)
 #define _IO_BASE 0x80000000
diff --git a/arch/ppc/platforms/rpxhiox.h b/arch/ppc/platforms/rpxhiox.h
deleted file mode 100644 (file)
index c3fa5a6..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * The Embedded Planet HIOX expansion card definitions.
- * There were a few different versions of these cards, but only
- * the one that escaped real production is defined here.
- *
- * Copyright (c) 2000 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_RPX_HIOX_DEFS
-#define __MACH_RPX_HIOX_DEFS
-
-#define HIOX_CSR_ADDR          ((uint)0xfac00000)
-#define HIOX_CSR_SIZE          ((uint)(4 * 1024))
-#define HIOX_CSR0_ADDR         HIOX_CSR_ADDR
-#define HIOX_CSR4_ADDR         ((uint)0xfac00004)
-
-#define HIOX_CSR0_DEFAULT      ((uint)0x380f3c00)
-#define HIOX_CSR0_ENSCC2       ((uint)0x80000000)
-#define HIOX_CSR0_ENSMC2       ((uint)0x04000000)
-#define HIOX_CSR0_ENVDOCLK     ((uint)0x02000000)
-#define HIOX_CSR0_VDORST_HL    ((uint)0x01000000)
-#define HIOX_CSR0_RS232SEL     ((uint)0x0000c000)
-#define HIOX_CSR0_SCC3SEL      ((uint)0x0000c000)
-#define HIOX_CSR0_SMC1SEL      ((uint)0x00008000)
-#define HIOX_CSR0_SCC1SEL      ((uint)0x00004000)
-#define HIOX_CSR0_ENTOUCH      ((uint)0x00000080)
-#define HIOX_CSR0_PDOWN100     ((uint)0x00000060)
-#define HIOX_CSR0_PDOWN10      ((uint)0x00000040)
-#define HIOX_CSR0_PDOWN1       ((uint)0x00000020)
-#define HIOX_CSR0_TSELSPI      ((uint)0x00000010)
-#define HIOX_CSR0_TIRQSTAT     ((uint)0x00000008)
-#define HIOX_CSR4_DEFAULT      ((uint)0x00000000)
-#define HIOX_CSR4_ENTIRQ2      ((uint)0x20000000)
-#define HIOX_CSR4_ENTIRQ3      ((uint)0x10000000)
-#define HIOX_CSR4_ENAUDIO      ((uint)0x00000080)
-#define HIOX_CSR4_RSTAUDIO     ((uint)0x00000040)      /* 0 == reset */
-#define HIOX_CSR4_AUDCLKHI     ((uint)0x00000020)
-#define HIOX_CSR4_AUDSPISEL    ((uint)0x00000010)
-#define HIOX_CSR4_AUDIRQSTAT   ((uint)0x00000008)
-#define HIOX_CSR4_AUDCLKSEL    ((uint)0x00000007)
-
-#endif
index 71978064627062bde4541f1728eab037cc5bfdab..b615501d55fc468a047665a5881b52291638798e 100644 (file)
@@ -57,10 +57,6 @@ extern bd_t m8xx_board_info;
 #define BCSR1_PCVCTL6          ((uint)0x00020000)
 #define BCSR1_PCVCTL7          ((uint)0x00010000)
 
-#if defined(CONFIG_HTDMSOUND)
-#include <platforms/rpxhiox.h>
-#endif
-
 /* define IO_BASE for pcmcia */
 #define _IO_BASE 0x80000000
 #define _IO_BASE_SIZE 0x1000
index 09911118c6750c4c7bda5a8999061afc8e89342b..95694159b22602310fa088e39c8bb4d628792674 100644 (file)
@@ -18,7 +18,8 @@ obj-$(CONFIG_440SP)           += ibm440gx_common.o ibm440sp_common.o
 obj-$(CONFIG_440SPE)           += ibm440gx_common.o ibm440sp_common.o ppc440spe_pcie.o
 ifeq ($(CONFIG_4xx),y)
 ifeq ($(CONFIG_XILINX_VIRTEX),y)
-obj-$(CONFIG_40x)              += xilinx_pic.o ppc_sys.o
+obj-$(CONFIG_40x)              += xilinx_pic.o
+obj-y                          += virtex_devices.o
 else
 ifeq ($(CONFIG_403),y)
 obj-$(CONFIG_40x)              += ppc403_pic.o
diff --git a/arch/ppc/syslib/cpc710.h b/arch/ppc/syslib/cpc710.h
deleted file mode 100644 (file)
index 5299bf8..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Definitions for the IBM CPC710 PCI Host Bridge
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __PPC_PLATFORMS_CPC710_H
-#define __PPC_PLATFORMS_CPC710_H
-
-/* General bridge and memory controller registers */
-#define PIDR   0xff000008
-#define        CNFR    0xff00000c
-#define        RSTR    0xff000010
-#define UCTL   0xff001000
-#define        MPSR    0xff001010
-#define        SIOC    0xff001020
-#define        ABCNTL  0xff001030
-#define SRST   0xff001040
-#define        ERRC    0xff001050
-#define        SESR    0xff001060
-#define        SEAR    0xff001070
-#define        SIOC1   0xff001090
-#define        PGCHP   0xff001100
-#define        GPDIR   0xff001130
-#define        GPOUT   0xff001150
-#define        ATAS    0xff001160
-#define        AVDG    0xff001170
-#define        MCCR    0xff001200
-#define        MESR    0xff001220
-#define        MEAR    0xff001230
-#define        MCER0   0xff001300
-#define        MCER1   0xff001310
-#define        MCER2   0xff001320
-#define        MCER3   0xff001330
-#define        MCER4   0xff001340
-#define        MCER5   0xff001350
-#define        MCER6   0xff001360
-#define        MCER7   0xff001370
-
-/*
- * PCI32/64 configuration registers
- * Given as offsets from their
- * respective physical segment BAR
- */
-#define PIBAR  0x000f7800
-#define PMBAR  0x000f7810
-#define MSIZE  0x000f7f40
-#define IOSIZE 0x000f7f60
-#define SMBAR  0x000f7f80
-#define SIBAR  0x000f7fc0
-#define PSSIZE 0x000f8100
-#define PPSIZE 0x000f8110
-#define BARPS  0x000f8120
-#define BARPP  0x000f8130
-#define PSBAR  0x000f8140
-#define PPBAR  0x000f8150
-#define BPMDLK 0x000f8200      /* Bottom of Peripheral Memory Space */
-#define TPMDLK 0x000f8210      /* Top of Peripheral Memory Space */
-#define BIODLK 0x000f8220      /* Bottom of Peripheral I/O Space */
-#define TIODLK 0x000f8230      /* Top of Perioheral I/O Space */
-#define DLKCTRL        0x000f8240      /* Deadlock control */
-#define DLKDEV 0x000f8250      /* Deadlock device */
-
-/* System standard configuration registers space */
-#define        DCR     0xff200000
-#define        DID     0xff200004
-#define        BAR     0xff200018
-
-/* Device specific configuration space */
-#define        PCIENB  0xff201000
-
-/* Configuration space registers */
-#define CPC710_BUS_NUMBER      0x40
-#define CPC710_SUB_BUS_NUMBER  0x41
-
-#endif /* __PPC_PLATFORMS_CPC710_H */
index 01e48d88f22d482e912070f86830bb5461a504bd..9caf850c9b3854a456fb3bcacc66da13a549dcdb 100644 (file)
@@ -413,7 +413,7 @@ m8xx_map_io(void)
        io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
 #endif
 #endif
-#if defined(CONFIG_HTDMSOUND) || defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
+#if defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
        io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO);
 #endif
 #ifdef CONFIG_FADS
index 2f83e162971f67be9800f2302ad90b76bf6b255b..939abe3c1f454363c6362656940a398ec0109c47 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/dma-mapping.h>
 #include <asm/ppc4xx_dma.h>
 
 void
diff --git a/arch/ppc/syslib/virtex_devices.c b/arch/ppc/syslib/virtex_devices.c
new file mode 100644 (file)
index 0000000..1654678
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Virtex hard ppc405 core common device listing
+ *
+ * Copyright 2005-2007 Secret Lab Technologies Ltd.
+ * Copyright 2005 Freescale Semiconductor Inc.
+ * Copyright 2002-2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <syslib/virtex_devices.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+#include <asm/io.h>
+
+/*
+ * UARTLITE: shortcut macro for single instance
+ */
+#define XPAR_UARTLITE(num) { \
+       .name = "uartlite", \
+       .id = num, \
+       .num_resources = 2, \
+       .resource = (struct resource[]) { \
+               { \
+                       .start = XPAR_UARTLITE_##num##_BASEADDR + 3, \
+                       .end = XPAR_UARTLITE_##num##_HIGHADDR, \
+                       .flags = IORESOURCE_MEM, \
+               }, \
+               { \
+                       .start = XPAR_INTC_0_UARTLITE_##num##_VEC_ID, \
+                       .flags = IORESOURCE_IRQ, \
+               }, \
+       }, \
+}
+
+/*
+ * Full UART: shortcut macro for single instance + platform data structure
+ */
+#define XPAR_UART(num) { \
+       .mapbase = XPAR_UARTNS550_##num##_BASEADDR + 3, \
+       .irq = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
+       .iotype = UPIO_MEM, \
+       .uartclk = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \
+       .flags = UPF_BOOT_AUTOCONF, \
+       .regshift = 2, \
+}
+
+/*
+ * SystemACE: shortcut macro for single instance
+ */
+#define XPAR_SYSACE(num) { \
+       .name           = "xsysace", \
+       .id             = XPAR_SYSACE_##num##_DEVICE_ID, \
+       .num_resources  = 2, \
+       .resource = (struct resource[]) { \
+               { \
+                       .start  = XPAR_SYSACE_##num##_BASEADDR, \
+                       .end    = XPAR_SYSACE_##num##_HIGHADDR, \
+                       .flags  = IORESOURCE_MEM, \
+               }, \
+               { \
+                       .start  = XPAR_INTC_0_SYSACE_##num##_VEC_ID, \
+                       .flags  = IORESOURCE_IRQ, \
+               }, \
+       }, \
+}
+
+
+/* UART 8250 driver platform data table */
+struct plat_serial8250_port virtex_serial_platform_data[] = {
+#if defined(XPAR_UARTNS550_0_BASEADDR)
+       XPAR_UART(0),
+#endif
+#if defined(XPAR_UARTNS550_1_BASEADDR)
+       XPAR_UART(1),
+#endif
+#if defined(XPAR_UARTNS550_2_BASEADDR)
+       XPAR_UART(2),
+#endif
+#if defined(XPAR_UARTNS550_3_BASEADDR)
+       XPAR_UART(3),
+#endif
+#if defined(XPAR_UARTNS550_4_BASEADDR)
+       XPAR_UART(4),
+#endif
+#if defined(XPAR_UARTNS550_5_BASEADDR)
+       XPAR_UART(5),
+#endif
+#if defined(XPAR_UARTNS550_6_BASEADDR)
+       XPAR_UART(6),
+#endif
+#if defined(XPAR_UARTNS550_7_BASEADDR)
+       XPAR_UART(7),
+#endif
+       { }, /* terminated by empty record */
+};
+
+
+struct platform_device virtex_platform_devices[] = {
+       /* UARTLITE instances */
+#if defined(XPAR_UARTLITE_0_BASEADDR)
+       XPAR_UARTLITE(0),
+#endif
+#if defined(XPAR_UARTLITE_1_BASEADDR)
+       XPAR_UARTLITE(1),
+#endif
+#if defined(XPAR_UARTLITE_2_BASEADDR)
+       XPAR_UARTLITE(2),
+#endif
+#if defined(XPAR_UARTLITE_3_BASEADDR)
+       XPAR_UARTLITE(3),
+#endif
+#if defined(XPAR_UARTLITE_4_BASEADDR)
+       XPAR_UARTLITE(4),
+#endif
+#if defined(XPAR_UARTLITE_5_BASEADDR)
+       XPAR_UARTLITE(5),
+#endif
+#if defined(XPAR_UARTLITE_6_BASEADDR)
+       XPAR_UARTLITE(6),
+#endif
+#if defined(XPAR_UARTLITE_7_BASEADDR)
+       XPAR_UARTLITE(7),
+#endif
+
+       /* Full UART instances */
+#if defined(XPAR_UARTNS550_0_BASEADDR)
+       {
+               .name           = "serial8250",
+               .id             = 0,
+               .dev.platform_data = virtex_serial_platform_data,
+       },
+#endif
+
+       /* SystemACE instances */
+#if defined(XPAR_SYSACE_0_BASEADDR)
+       XPAR_SYSACE(0),
+#endif
+#if defined(XPAR_SYSACE_1_BASEADDR)
+       XPAR_SYSACE(1),
+#endif
+
+       /* ML300/403 reference design framebuffer */
+#if defined(XPAR_TFT_0_BASEADDR)
+       {
+               .name           = "xilinxfb",
+               .id             = 0,
+               .num_resources  = 1,
+               .resource = (struct resource[]) {
+                       {
+                               .start  = XPAR_TFT_0_BASEADDR,
+                               .end    = XPAR_TFT_0_BASEADDR+7,
+                               .flags  = IORESOURCE_IO,
+                       },
+               },
+       },
+#endif
+};
+
+/* Early serial support functions */
+static void __init
+virtex_early_serial_init(int num, struct plat_serial8250_port *pdata)
+{
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+       struct uart_port serial_req;
+
+       memset(&serial_req, 0, sizeof(serial_req));
+       serial_req.mapbase      = pdata->mapbase;
+       serial_req.membase      = pdata->membase;
+       serial_req.irq          = pdata->irq;
+       serial_req.uartclk      = pdata->uartclk;
+       serial_req.regshift     = pdata->regshift;
+       serial_req.iotype       = pdata->iotype;
+       serial_req.flags        = pdata->flags;
+       gen550_init(num, &serial_req);
+#endif
+}
+
+void __init
+virtex_early_serial_map(void)
+{
+#ifdef CONFIG_SERIAL_8250
+       struct plat_serial8250_port *pdata;
+       int i = 0;
+
+       pdata = virtex_serial_platform_data;
+       while(pdata && pdata->flags) {
+               pdata->membase = ioremap(pdata->mapbase, 0x100);
+               virtex_early_serial_init(i, pdata);
+               pdata++;
+               i++;
+       }
+#endif /* CONFIG_SERIAL_8250 */
+}
+
+/*
+ * default fixup routine; do nothing and return success.
+ *
+ * Reimplement this routine in your custom board support file to
+ * override the default behaviour
+ */
+int __attribute__ ((weak))
+virtex_device_fixup(struct platform_device *dev)
+{
+       return 0;
+}
+
+static int __init virtex_init(void)
+{
+       struct platform_device *index = virtex_platform_devices;
+       unsigned int ret = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(virtex_platform_devices); i++, index++) {
+               if (virtex_device_fixup(index) != 0)
+                       continue;
+
+               if (platform_device_register(index)) {
+                       ret = 1;
+                       printk(KERN_ERR "cannot register dev %s:%d\n",
+                              index->name, index->id);
+               }
+       }
+       return ret;
+}
+
+subsys_initcall(virtex_init);
diff --git a/arch/ppc/syslib/virtex_devices.h b/arch/ppc/syslib/virtex_devices.h
new file mode 100644 (file)
index 0000000..4a17dd3
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Common support header for virtex ppc405 platforms
+ *
+ * Copyright 2007 Secret Lab Technologies Ltd.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __ASM_VIRTEX_DEVICES_H__
+#define __ASM_VIRTEX_DEVICES_H__
+
+#include <linux/platform_device.h>
+
+void __init virtex_early_serial_map(void);
+
+/* Prototype for device fixup routine.  Implement this routine in the
+ * board specific fixup code and the generic setup code will call it for
+ * each device is the platform device list.
+ *
+ * If the hook returns a non-zero value, then the device will not get
+ * registered with the platform bus
+ */
+int virtex_device_fixup(struct platform_device *dev);
+
+#endif  /* __ASM_VIRTEX_DEVICES_H__ */
index 7a1e251e333ddfc505dcc3e68cfa10acb19a46dd..b26378815b9145ead9183f55113395d7271bfee0 100644 (file)
@@ -631,7 +631,6 @@ CONFIG_SATA_SIL=y
 CONFIG_SATA_VIA=y
 # CONFIG_SATA_VITESSE is not set
 # CONFIG_SATA_INIC162X is not set
-CONFIG_SATA_INTEL_COMBINED=y
 CONFIG_SATA_ACPI=y
 # CONFIG_PATA_ALI is not set
 # CONFIG_PATA_AMD is not set
index f92ba2a869b4fe32348002cf00260ce6ac943542..64df3fa303b0929eeac9e9609b3e71e7f88b6d2c 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/module.h>
 #include <linux/blkdev.h>
 #include <linux/elevator.h>
-#include <linux/hash.h>
 #include <linux/rbtree.h>
 #include <linux/ioprio.h>
 
@@ -26,19 +25,17 @@ static int cfq_slice_async = HZ / 25;
 static const int cfq_slice_async_rq = 2;
 static int cfq_slice_idle = HZ / 125;
 
+/*
+ * grace period before allowing idle class to get disk access
+ */
 #define CFQ_IDLE_GRACE         (HZ / 10)
-#define CFQ_SLICE_SCALE                (5)
-
-#define CFQ_KEY_ASYNC          (0)
 
 /*
- * for the hash of cfqq inside the cfqd
+ * below this threshold, we consider thinktime immediate
  */
-#define CFQ_QHASH_SHIFT                6
-#define CFQ_QHASH_ENTRIES      (1 << CFQ_QHASH_SHIFT)
-#define list_entry_qhash(entry)        hlist_entry((entry), struct cfq_queue, cfq_hash)
+#define CFQ_MIN_TT             (2)
 
-#define list_entry_cfqq(ptr)   list_entry((ptr), struct cfq_queue, cfq_list)
+#define CFQ_SLICE_SCALE                (5)
 
 #define RQ_CIC(rq)             ((struct cfq_io_context*)(rq)->elevator_private)
 #define RQ_CFQQ(rq)            ((rq)->elevator_private2)
@@ -56,16 +53,20 @@ static struct completion *ioc_gone;
 #define ASYNC                  (0)
 #define SYNC                   (1)
 
-#define cfq_cfqq_dispatched(cfqq)      \
-       ((cfqq)->on_dispatch[ASYNC] + (cfqq)->on_dispatch[SYNC])
-
-#define cfq_cfqq_class_sync(cfqq)      ((cfqq)->key != CFQ_KEY_ASYNC)
-
-#define cfq_cfqq_sync(cfqq)            \
-       (cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC])
-
 #define sample_valid(samples)  ((samples) > 80)
 
+/*
+ * Most of our rbtree usage is for sorting with min extraction, so
+ * if we cache the leftmost node we don't have to walk down the tree
+ * to find it. Idea borrowed from Ingo Molnars CFS scheduler. We should
+ * move this into the elevator for the rq sorting as well.
+ */
+struct cfq_rb_root {
+       struct rb_root rb;
+       struct rb_node *left;
+};
+#define CFQ_RB_ROOT    (struct cfq_rb_root) { RB_ROOT, NULL, }
+
 /*
  * Per block device queue structure
  */
@@ -75,18 +76,11 @@ struct cfq_data {
        /*
         * rr list of queues with requests and the count of them
         */
-       struct list_head rr_list[CFQ_PRIO_LISTS];
-       struct list_head busy_rr;
-       struct list_head cur_rr;
-       struct list_head idle_rr;
+       struct cfq_rb_root service_tree;
        unsigned int busy_queues;
 
-       /*
-        * cfqq lookup hash
-        */
-       struct hlist_head *cfq_hash;
-
        int rq_in_driver;
+       int sync_flight;
        int hw_tag;
 
        /*
@@ -97,12 +91,10 @@ struct cfq_data {
 
        struct cfq_queue *active_queue;
        struct cfq_io_context *active_cic;
-       int cur_prio, cur_end_prio;
-       unsigned int dispatch_slice;
 
        struct timer_list idle_class_timer;
 
-       sector_t last_sector;
+       sector_t last_position;
        unsigned long last_end_request;
 
        /*
@@ -117,6 +109,9 @@ struct cfq_data {
        unsigned int cfq_slice_idle;
 
        struct list_head cic_list;
+
+       sector_t new_seek_mean;
+       u64 new_seek_total;
 };
 
 /*
@@ -127,12 +122,10 @@ struct cfq_queue {
        atomic_t ref;
        /* parent cfq_data */
        struct cfq_data *cfqd;
-       /* cfqq lookup hash */
-       struct hlist_node cfq_hash;
-       /* hash key */
-       unsigned int key;
-       /* member of the rr/busy/cur/idle cfqd list */
-       struct list_head cfq_list;
+       /* service_tree member */
+       struct rb_node rb_node;
+       /* service_tree key */
+       unsigned long rb_key;
        /* sorted list of pending requests */
        struct rb_root sort_list;
        /* if fifo isn't expired, next request to serve */
@@ -147,11 +140,10 @@ struct cfq_queue {
        struct list_head fifo;
 
        unsigned long slice_end;
-       unsigned long service_last;
        long slice_resid;
 
-       /* number of requests that are on the dispatch list */
-       int on_dispatch[2];
+       /* number of requests that are on the dispatch list or inside driver */
+       int dispatched;
 
        /* io prio of this group */
        unsigned short ioprio, org_ioprio;
@@ -159,6 +151,8 @@ struct cfq_queue {
 
        /* various state flags, see below */
        unsigned int flags;
+
+       sector_t last_request_pos;
 };
 
 enum cfqq_state_flags {
@@ -172,6 +166,7 @@ enum cfqq_state_flags {
        CFQ_CFQQ_FLAG_prio_changed,     /* task priority has changed */
        CFQ_CFQQ_FLAG_queue_new,        /* queue never been serviced */
        CFQ_CFQQ_FLAG_slice_new,        /* no requests dispatched in slice */
+       CFQ_CFQQ_FLAG_sync,             /* synchronous queue */
 };
 
 #define CFQ_CFQQ_FNS(name)                                             \
@@ -198,11 +193,38 @@ CFQ_CFQQ_FNS(idle_window);
 CFQ_CFQQ_FNS(prio_changed);
 CFQ_CFQQ_FNS(queue_new);
 CFQ_CFQQ_FNS(slice_new);
+CFQ_CFQQ_FNS(sync);
 #undef CFQ_CFQQ_FNS
 
-static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
 static void cfq_dispatch_insert(request_queue_t *, struct request *);
-static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask);
+static struct cfq_queue *cfq_get_queue(struct cfq_data *, int,
+                                      struct task_struct *, gfp_t);
+static struct cfq_io_context *cfq_cic_rb_lookup(struct cfq_data *,
+                                               struct io_context *);
+
+static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
+                                           int is_sync)
+{
+       return cic->cfqq[!!is_sync];
+}
+
+static inline void cic_set_cfqq(struct cfq_io_context *cic,
+                               struct cfq_queue *cfqq, int is_sync)
+{
+       cic->cfqq[!!is_sync] = cfqq;
+}
+
+/*
+ * We regard a request as SYNC, if it's either a read or has the SYNC bit
+ * set (in which case it could also be direct WRITE).
+ */
+static inline int cfq_bio_sync(struct bio *bio)
+{
+       if (bio_data_dir(bio) == READ || bio_sync(bio))
+               return 1;
+
+       return 0;
+}
 
 /*
  * scheduler run of queue, if there are requests pending and no one in the
@@ -221,44 +243,31 @@ static int cfq_queue_empty(request_queue_t *q)
        return !cfqd->busy_queues;
 }
 
-static inline pid_t cfq_queue_pid(struct task_struct *task, int rw, int is_sync)
-{
-       /*
-        * Use the per-process queue, for read requests and syncronous writes
-        */
-       if (!(rw & REQ_RW) || is_sync)
-               return task->pid;
-
-       return CFQ_KEY_ASYNC;
-}
-
 /*
  * Scale schedule slice based on io priority. Use the sync time slice only
  * if a queue is marked sync and has sync io queued. A sync queue with async
  * io only, should not get full sync slice length.
  */
-static inline int
-cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+static inline int cfq_prio_slice(struct cfq_data *cfqd, int sync,
+                                unsigned short prio)
 {
-       const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];
+       const int base_slice = cfqd->cfq_slice[sync];
 
-       WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+       WARN_ON(prio >= IOPRIO_BE_NR);
+
+       return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - prio));
+}
 
-       return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio));
+static inline int
+cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+       return cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio);
 }
 
 static inline void
 cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
-       cfqq->slice_end += cfqq->slice_resid;
-
-       /*
-        * Don't carry over residual for more than one slice, we only want
-        * to slightly correct the fairness. Carrying over forever would
-        * easily introduce oscillations.
-        */
-       cfqq->slice_resid = 0;
 }
 
 /*
@@ -307,7 +316,7 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
        s1 = rq1->sector;
        s2 = rq2->sector;
 
-       last = cfqd->last_sector;
+       last = cfqd->last_position;
 
        /*
         * by definition, 1KiB is 2 sectors
@@ -371,6 +380,26 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
        }
 }
 
+/*
+ * The below is leftmost cache rbtree addon
+ */
+static struct rb_node *cfq_rb_first(struct cfq_rb_root *root)
+{
+       if (!root->left)
+               root->left = rb_first(&root->rb);
+
+       return root->left;
+}
+
+static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root)
+{
+       if (root->left == n)
+               root->left = NULL;
+
+       rb_erase(n, &root->rb);
+       RB_CLEAR_NODE(n);
+}
+
 /*
  * would be nice to take fifo expire time into account as well
  */
@@ -398,78 +427,96 @@ cfq_find_next_rq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        return cfq_choose_req(cfqd, next, prev);
 }
 
-static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
+static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
+                                     struct cfq_queue *cfqq)
 {
-       struct cfq_data *cfqd = cfqq->cfqd;
-       struct list_head *list, *n;
-       struct cfq_queue *__cfqq;
-
        /*
-        * Resorting requires the cfqq to be on the RR list already.
+        * just an approximation, should be ok.
         */
-       if (!cfq_cfqq_on_rr(cfqq))
-               return;
+       return (cfqd->busy_queues - 1) * (cfq_prio_slice(cfqd, 1, 0) -
+                      cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio));
+}
 
-       list_del(&cfqq->cfq_list);
+/*
+ * The cfqd->service_tree holds all pending cfq_queue's that have
+ * requests waiting to be processed. It is sorted in the order that
+ * we will service the queues.
+ */
+static void cfq_service_tree_add(struct cfq_data *cfqd,
+                                   struct cfq_queue *cfqq, int add_front)
+{
+       struct rb_node **p = &cfqd->service_tree.rb.rb_node;
+       struct rb_node *parent = NULL;
+       unsigned long rb_key;
+       int left;
+
+       if (!add_front) {
+               rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies;
+               rb_key += cfqq->slice_resid;
+               cfqq->slice_resid = 0;
+       } else
+               rb_key = 0;
 
-       if (cfq_class_rt(cfqq))
-               list = &cfqd->cur_rr;
-       else if (cfq_class_idle(cfqq))
-               list = &cfqd->idle_rr;
-       else {
+       if (!RB_EMPTY_NODE(&cfqq->rb_node)) {
                /*
-                * if cfqq has requests in flight, don't allow it to be
-                * found in cfq_set_active_queue before it has finished them.
-                * this is done to increase fairness between a process that
-                * has lots of io pending vs one that only generates one
-                * sporadically or synchronously
+                * same position, nothing more to do
                 */
-               if (cfq_cfqq_dispatched(cfqq))
-                       list = &cfqd->busy_rr;
-               else
-                       list = &cfqd->rr_list[cfqq->ioprio];
+               if (rb_key == cfqq->rb_key)
+                       return;
+
+               cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
        }
 
-       if (preempted || cfq_cfqq_queue_new(cfqq)) {
-               /*
-                * If this queue was preempted or is new (never been serviced),
-                * let it be added first for fairness but beind other new
-                * queues.
-                */
-               n = list;
-               while (n->next != list) {
-                       __cfqq = list_entry_cfqq(n->next);
-                       if (!cfq_cfqq_queue_new(__cfqq))
-                               break;
+       left = 1;
+       while (*p) {
+               struct cfq_queue *__cfqq;
+               struct rb_node **n;
+
+               parent = *p;
+               __cfqq = rb_entry(parent, struct cfq_queue, rb_node);
 
-                       n = n->next;
-               }
-               list_add_tail(&cfqq->cfq_list, n);
-       } else if (!cfq_cfqq_class_sync(cfqq)) {
-               /*
-                * async queue always goes to the end. this wont be overly
-                * unfair to writes, as the sort of the sync queue wont be
-                * allowed to pass the async queue again.
-                */
-               list_add_tail(&cfqq->cfq_list, list);
-       } else {
                /*
-                * sort by last service, but don't cross a new or async
-                * queue. we don't cross a new queue because it hasn't been
-                * service before, and we don't cross an async queue because
-                * it gets added to the end on expire.
+                * sort RT queues first, we always want to give
+                * preference to them. IDLE queues goes to the back.
+                * after that, sort on the next service time.
                 */
-               n = list;
-               while ((n = n->prev) != list) {
-                       struct cfq_queue *__cfqq = list_entry_cfqq(n);
+               if (cfq_class_rt(cfqq) > cfq_class_rt(__cfqq))
+                       n = &(*p)->rb_left;
+               else if (cfq_class_rt(cfqq) < cfq_class_rt(__cfqq))
+                       n = &(*p)->rb_right;
+               else if (cfq_class_idle(cfqq) < cfq_class_idle(__cfqq))
+                       n = &(*p)->rb_left;
+               else if (cfq_class_idle(cfqq) > cfq_class_idle(__cfqq))
+                       n = &(*p)->rb_right;
+               else if (rb_key < __cfqq->rb_key)
+                       n = &(*p)->rb_left;
+               else
+                       n = &(*p)->rb_right;
 
-                       if (!cfq_cfqq_class_sync(cfqq) || !__cfqq->service_last)
-                               break;
-                       if (time_before(__cfqq->service_last, cfqq->service_last))
-                               break;
-               }
-               list_add(&cfqq->cfq_list, n);
+               if (n == &(*p)->rb_right)
+                       left = 0;
+
+               p = n;
        }
+
+       if (left)
+               cfqd->service_tree.left = &cfqq->rb_node;
+
+       cfqq->rb_key = rb_key;
+       rb_link_node(&cfqq->rb_node, parent, p);
+       rb_insert_color(&cfqq->rb_node, &cfqd->service_tree.rb);
+}
+
+/*
+ * Update cfqq's position in the service tree.
+ */
+static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+       /*
+        * Resorting requires the cfqq to be on the RR list already.
+        */
+       if (cfq_cfqq_on_rr(cfqq))
+               cfq_service_tree_add(cfqd, cfqq, 0);
 }
 
 /*
@@ -483,15 +530,21 @@ cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        cfq_mark_cfqq_on_rr(cfqq);
        cfqd->busy_queues++;
 
-       cfq_resort_rr_list(cfqq, 0);
+       cfq_resort_rr_list(cfqd, cfqq);
 }
 
+/*
+ * Called when the cfqq no longer has requests pending, remove it from
+ * the service tree.
+ */
 static inline void
 cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        BUG_ON(!cfq_cfqq_on_rr(cfqq));
        cfq_clear_cfqq_on_rr(cfqq);
-       list_del_init(&cfqq->cfq_list);
+
+       if (!RB_EMPTY_NODE(&cfqq->rb_node))
+               cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
 
        BUG_ON(!cfqd->busy_queues);
        cfqd->busy_queues--;
@@ -552,10 +605,14 @@ static struct request *
 cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
 {
        struct task_struct *tsk = current;
-       pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio), bio_sync(bio));
+       struct cfq_io_context *cic;
        struct cfq_queue *cfqq;
 
-       cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
+       cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+       if (!cic)
+               return NULL;
+
+       cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
        if (cfqq) {
                sector_t sector = bio->bi_sector + bio_sectors(bio);
 
@@ -579,6 +636,8 @@ static void cfq_activate_request(request_queue_t *q, struct request *rq)
         */
        if (!cfqd->hw_tag && cfqd->rq_in_driver > 4)
                cfqd->hw_tag = 1;
+
+       cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors;
 }
 
 static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
@@ -605,8 +664,7 @@ static void cfq_remove_request(struct request *rq)
        }
 }
 
-static int
-cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
+static int cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
        struct request *__rq;
@@ -648,23 +706,24 @@ static int cfq_allow_merge(request_queue_t *q, struct request *rq,
                           struct bio *bio)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
-       const int rw = bio_data_dir(bio);
+       struct cfq_io_context *cic;
        struct cfq_queue *cfqq;
-       pid_t key;
 
        /*
         * Disallow merge of a sync bio into an async request.
         */
-       if ((bio_data_dir(bio) == READ || bio_sync(bio)) && !rq_is_sync(rq))
+       if (cfq_bio_sync(bio) && !rq_is_sync(rq))
                return 0;
 
        /*
         * Lookup the cfqq that this bio will be queued with. Allow
         * merge only if rq is queued there.
         */
-       key = cfq_queue_pid(current, rw, bio_sync(bio));
-       cfqq = cfq_find_cfq_hash(cfqd, key, current->ioprio);
+       cic = cfq_cic_rb_lookup(cfqd, current->io_context);
+       if (!cic)
+               return 0;
 
+       cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
        if (cfqq == RQ_CFQQ(rq))
                return 1;
 
@@ -684,6 +743,7 @@ __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
                cfq_clear_cfqq_must_alloc_slice(cfqq);
                cfq_clear_cfqq_fifo_expire(cfqq);
                cfq_mark_cfqq_slice_new(cfqq);
+               cfq_clear_cfqq_queue_new(cfqq);
        }
 
        cfqd->active_queue = cfqq;
@@ -694,23 +754,21 @@ __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
  */
 static void
 __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
-                   int preempted, int timed_out)
+                   int timed_out)
 {
        if (cfq_cfqq_wait_request(cfqq))
                del_timer(&cfqd->idle_slice_timer);
 
        cfq_clear_cfqq_must_dispatch(cfqq);
        cfq_clear_cfqq_wait_request(cfqq);
-       cfq_clear_cfqq_queue_new(cfqq);
 
        /*
-        * store what was left of this slice, if the queue idled out
-        * or was preempted
+        * store what was left of this slice, if the queue idled/timed out
         */
        if (timed_out && !cfq_cfqq_slice_new(cfqq))
                cfqq->slice_resid = cfqq->slice_end - jiffies;
 
-       cfq_resort_rr_list(cfqq, preempted);
+       cfq_resort_rr_list(cfqd, cfqq);
 
        if (cfqq == cfqd->active_queue)
                cfqd->active_queue = NULL;
@@ -719,163 +777,152 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                put_io_context(cfqd->active_cic->ioc);
                cfqd->active_cic = NULL;
        }
-
-       cfqd->dispatch_slice = 0;
 }
 
-static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted,
-                                    int timed_out)
+static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out)
 {
        struct cfq_queue *cfqq = cfqd->active_queue;
 
        if (cfqq)
-               __cfq_slice_expired(cfqd, cfqq, preempted, timed_out);
+               __cfq_slice_expired(cfqd, cfqq, timed_out);
 }
 
 /*
- * 0
- * 0,1
- * 0,1,2
- * 0,1,2,3
- * 0,1,2,3,4
- * 0,1,2,3,4,5
- * 0,1,2,3,4,5,6
- * 0,1,2,3,4,5,6,7
+ * Get next queue for service. Unless we have a queue preemption,
+ * we'll simply select the first cfqq in the service tree.
  */
-static int cfq_get_next_prio_level(struct cfq_data *cfqd)
+static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd)
 {
-       int prio, wrap;
+       struct cfq_queue *cfqq;
+       struct rb_node *n;
 
-       prio = -1;
-       wrap = 0;
-       do {
-               int p;
+       if (RB_EMPTY_ROOT(&cfqd->service_tree.rb))
+               return NULL;
 
-               for (p = cfqd->cur_prio; p <= cfqd->cur_end_prio; p++) {
-                       if (!list_empty(&cfqd->rr_list[p])) {
-                               prio = p;
-                               break;
-                       }
-               }
+       n = cfq_rb_first(&cfqd->service_tree);
+       cfqq = rb_entry(n, struct cfq_queue, rb_node);
 
-               if (prio != -1)
-                       break;
-               cfqd->cur_prio = 0;
-               if (++cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
-                       cfqd->cur_end_prio = 0;
-                       if (wrap)
-                               break;
-                       wrap = 1;
-               }
-       } while (1);
+       if (cfq_class_idle(cfqq)) {
+               unsigned long end;
 
-       if (unlikely(prio == -1))
-               return -1;
+               /*
+                * if we have idle queues and no rt or be queues had
+                * pending requests, either allow immediate service if
+                * the grace period has passed or arm the idle grace
+                * timer
+                */
+               end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+               if (time_before(jiffies, end)) {
+                       mod_timer(&cfqd->idle_class_timer, end);
+                       cfqq = NULL;
+               }
+       }
 
-       BUG_ON(prio >= CFQ_PRIO_LISTS);
+       return cfqq;
+}
 
-       list_splice_init(&cfqd->rr_list[prio], &cfqd->cur_rr);
+/*
+ * Get and set a new active queue for service.
+ */
+static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+{
+       struct cfq_queue *cfqq;
 
-       cfqd->cur_prio = prio + 1;
-       if (cfqd->cur_prio > cfqd->cur_end_prio) {
-               cfqd->cur_end_prio = cfqd->cur_prio;
-               cfqd->cur_prio = 0;
-       }
-       if (cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
-               cfqd->cur_prio = 0;
-               cfqd->cur_end_prio = 0;
-       }
+       cfqq = cfq_get_next_queue(cfqd);
+       __cfq_set_active_queue(cfqd, cfqq);
+       return cfqq;
+}
 
-       return prio;
+static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
+                                         struct request *rq)
+{
+       if (rq->sector >= cfqd->last_position)
+               return rq->sector - cfqd->last_position;
+       else
+               return cfqd->last_position - rq->sector;
 }
 
-static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+static inline int cfq_rq_close(struct cfq_data *cfqd, struct request *rq)
 {
-       struct cfq_queue *cfqq = NULL;
+       struct cfq_io_context *cic = cfqd->active_cic;
 
-       if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1) {
-               /*
-                * if current list is non-empty, grab first entry. if it is
-                * empty, get next prio level and grab first entry then if any
-                * are spliced
-                */
-               cfqq = list_entry_cfqq(cfqd->cur_rr.next);
-       } else if (!list_empty(&cfqd->busy_rr)) {
-               /*
-                * If no new queues are available, check if the busy list has
-                * some before falling back to idle io.
-                */
-               cfqq = list_entry_cfqq(cfqd->busy_rr.next);
-       } else if (!list_empty(&cfqd->idle_rr)) {
-               /*
-                * if we have idle queues and no rt or be queues had pending
-                * requests, either allow immediate service if the grace period
-                * has passed or arm the idle grace timer
-                */
-               unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+       if (!sample_valid(cic->seek_samples))
+               return 0;
 
-               if (time_after_eq(jiffies, end))
-                       cfqq = list_entry_cfqq(cfqd->idle_rr.next);
-               else
-                       mod_timer(&cfqd->idle_class_timer, end);
-       }
+       return cfq_dist_from_last(cfqd, rq) <= cic->seek_mean;
+}
 
-       __cfq_set_active_queue(cfqd, cfqq);
-       return cfqq;
+static int cfq_close_cooperator(struct cfq_data *cfq_data,
+                               struct cfq_queue *cfqq)
+{
+       /*
+        * We should notice if some of the queues are cooperating, eg
+        * working closely on the same area of the disk. In that case,
+        * we can group them together and don't waste time idling.
+        */
+       return 0;
 }
 
-#define CIC_SEEKY(cic) ((cic)->seek_mean > (128 * 1024))
+#define CIC_SEEKY(cic) ((cic)->seek_mean > (8 * 1024))
 
-static int cfq_arm_slice_timer(struct cfq_data *cfqd)
+static void cfq_arm_slice_timer(struct cfq_data *cfqd)
 {
        struct cfq_queue *cfqq = cfqd->active_queue;
        struct cfq_io_context *cic;
        unsigned long sl;
 
        WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list));
+       WARN_ON(cfq_cfqq_slice_new(cfqq));
 
        /*
         * idle is disabled, either manually or by past process history
         */
-       if (!cfqd->cfq_slice_idle)
-               return 0;
-       if (!cfq_cfqq_idle_window(cfqq))
-               return 0;
+       if (!cfqd->cfq_slice_idle || !cfq_cfqq_idle_window(cfqq))
+               return;
+
        /*
         * task has exited, don't wait
         */
        cic = cfqd->active_cic;
        if (!cic || !cic->ioc->task)
-               return 0;
+               return;
+
+       /*
+        * See if this prio level has a good candidate
+        */
+       if (cfq_close_cooperator(cfqd, cfqq) &&
+           (sample_valid(cic->ttime_samples) && cic->ttime_mean > 2))
+               return;
 
        cfq_mark_cfqq_must_dispatch(cfqq);
        cfq_mark_cfqq_wait_request(cfqq);
 
-       sl = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
-
        /*
         * we don't want to idle for seeks, but we do want to allow
         * fair distribution of slice time for a process doing back-to-back
         * seeks. so allow a little bit of time for him to submit a new rq
         */
+       sl = cfqd->cfq_slice_idle;
        if (sample_valid(cic->seek_samples) && CIC_SEEKY(cic))
-               sl = min(sl, msecs_to_jiffies(2));
+               sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT));
 
        mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
-       return 1;
 }
 
+/*
+ * Move request from internal lists to the request queue dispatch list.
+ */
 static void cfq_dispatch_insert(request_queue_t *q, struct request *rq)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
        struct cfq_queue *cfqq = RQ_CFQQ(rq);
 
        cfq_remove_request(rq);
-       cfqq->on_dispatch[rq_is_sync(rq)]++;
+       cfqq->dispatched++;
        elv_dispatch_sort(q, rq);
 
-       rq = list_entry(q->queue_head.prev, struct request, queuelist);
-       cfqd->last_sector = rq->sector + rq->nr_sectors;
+       if (cfq_cfqq_sync(cfqq))
+               cfqd->sync_flight++;
 }
 
 /*
@@ -895,13 +942,13 @@ static inline struct request *cfq_check_fifo(struct cfq_queue *cfqq)
        if (list_empty(&cfqq->fifo))
                return NULL;
 
-       fifo = cfq_cfqq_class_sync(cfqq);
+       fifo = cfq_cfqq_sync(cfqq);
        rq = rq_entry_fifo(cfqq->fifo.next);
 
-       if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo]))
-               return rq;
+       if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo]))
+               return NULL;
 
-       return NULL;
+       return rq;
 }
 
 static inline int
@@ -915,7 +962,8 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 }
 
 /*
- * get next queue for service
+ * Select a queue for service. If we have a current active queue,
+ * check whether to continue servicing it, or retrieve and set a new one.
  */
 static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
 {
@@ -926,33 +974,41 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
                goto new_queue;
 
        /*
-        * slice has expired
+        * The active queue has run out of time, expire it and select new.
         */
-       if (!cfq_cfqq_must_dispatch(cfqq) && cfq_slice_used(cfqq))
+       if (cfq_slice_used(cfqq))
                goto expire;
 
        /*
-        * if queue has requests, dispatch one. if not, check if
-        * enough slice is left to wait for one
+        * The active queue has requests and isn't expired, allow it to
+        * dispatch.
         */
        if (!RB_EMPTY_ROOT(&cfqq->sort_list))
                goto keep_queue;
-       else if (cfq_cfqq_slice_new(cfqq) || cfq_cfqq_dispatched(cfqq)) {
+
+       /*
+        * No requests pending. If the active queue still has requests in
+        * flight or is idling for a new request, allow either of these
+        * conditions to happen (or time out) before selecting a new queue.
+        */
+       if (timer_pending(&cfqd->idle_slice_timer) ||
+           (cfqq->dispatched && cfq_cfqq_idle_window(cfqq))) {
                cfqq = NULL;
                goto keep_queue;
-       } else if (cfq_cfqq_class_sync(cfqq)) {
-               if (cfq_arm_slice_timer(cfqd))
-                       return NULL;
        }
 
 expire:
-       cfq_slice_expired(cfqd, 0, 0);
+       cfq_slice_expired(cfqd, 0);
 new_queue:
        cfqq = cfq_set_active_queue(cfqd);
 keep_queue:
        return cfqq;
 }
 
+/*
+ * Dispatch some requests from cfqq, moving them to the request queue
+ * dispatch list.
+ */
 static int
 __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                        int max_dispatch)
@@ -975,7 +1031,6 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                 */
                cfq_dispatch_insert(cfqd->queue, rq);
 
-               cfqd->dispatch_slice++;
                dispatched++;
 
                if (!cfqd->active_cic) {
@@ -993,57 +1048,54 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
         * queue always expire after 1 dispatch round.
         */
        if (cfqd->busy_queues > 1 && ((!cfq_cfqq_sync(cfqq) &&
-           cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
+           dispatched >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
            cfq_class_idle(cfqq))) {
                cfqq->slice_end = jiffies + 1;
-               cfq_slice_expired(cfqd, 0, 0);
+               cfq_slice_expired(cfqd, 0);
        }
 
        return dispatched;
 }
 
-static int
-cfq_forced_dispatch_cfqqs(struct list_head *list)
+static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
 {
-       struct cfq_queue *cfqq, *next;
-       int dispatched;
+       int dispatched = 0;
 
-       dispatched = 0;
-       list_for_each_entry_safe(cfqq, next, list, cfq_list) {
-               while (cfqq->next_rq) {
-                       cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq);
-                       dispatched++;
-               }
-               BUG_ON(!list_empty(&cfqq->fifo));
+       while (cfqq->next_rq) {
+               cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq);
+               dispatched++;
        }
 
+       BUG_ON(!list_empty(&cfqq->fifo));
        return dispatched;
 }
 
-static int
-cfq_forced_dispatch(struct cfq_data *cfqd)
+/*
+ * Drain our current requests. Used for barriers and when switching
+ * io schedulers on-the-fly.
+ */
+static int cfq_forced_dispatch(struct cfq_data *cfqd)
 {
-       int i, dispatched = 0;
+       int dispatched = 0;
+       struct rb_node *n;
 
-       for (i = 0; i < CFQ_PRIO_LISTS; i++)
-               dispatched += cfq_forced_dispatch_cfqqs(&cfqd->rr_list[i]);
+       while ((n = cfq_rb_first(&cfqd->service_tree)) != NULL) {
+               struct cfq_queue *cfqq = rb_entry(n, struct cfq_queue, rb_node);
 
-       dispatched += cfq_forced_dispatch_cfqqs(&cfqd->busy_rr);
-       dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr);
-       dispatched += cfq_forced_dispatch_cfqqs(&cfqd->idle_rr);
+               dispatched += __cfq_forced_dispatch_cfqq(cfqq);
+       }
 
-       cfq_slice_expired(cfqd, 0, 0);
+       cfq_slice_expired(cfqd, 0);
 
        BUG_ON(cfqd->busy_queues);
 
        return dispatched;
 }
 
-static int
-cfq_dispatch_requests(request_queue_t *q, int force)
+static int cfq_dispatch_requests(request_queue_t *q, int force)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
-       struct cfq_queue *cfqq, *prev_cfqq;
+       struct cfq_queue *cfqq;
        int dispatched;
 
        if (!cfqd->busy_queues)
@@ -1053,36 +1105,28 @@ cfq_dispatch_requests(request_queue_t *q, int force)
                return cfq_forced_dispatch(cfqd);
 
        dispatched = 0;
-       prev_cfqq = NULL;
        while ((cfqq = cfq_select_queue(cfqd)) != NULL) {
                int max_dispatch;
 
-               if (cfqd->busy_queues > 1) {
-                       /*
-                        * Don't repeat dispatch from the previous queue.
-                        */
-                       if (prev_cfqq == cfqq)
-                               break;
+               max_dispatch = cfqd->cfq_quantum;
+               if (cfq_class_idle(cfqq))
+                       max_dispatch = 1;
 
-                       /*
-                        * So we have dispatched before in this round, if the
-                        * next queue has idling enabled (must be sync), don't
-                        * allow it service until the previous have continued.
-                        */
-                       if (cfqd->rq_in_driver && cfq_cfqq_idle_window(cfqq))
+               if (cfqq->dispatched >= max_dispatch) {
+                       if (cfqd->busy_queues > 1)
+                               break;
+                       if (cfqq->dispatched >= 4 * max_dispatch)
                                break;
                }
 
+               if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq))
+                       break;
+
                cfq_clear_cfqq_must_dispatch(cfqq);
                cfq_clear_cfqq_wait_request(cfqq);
                del_timer(&cfqd->idle_slice_timer);
 
-               max_dispatch = cfqd->cfq_quantum;
-               if (cfq_class_idle(cfqq))
-                       max_dispatch = 1;
-
                dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
-               prev_cfqq = cfqq;
        }
 
        return dispatched;
@@ -1108,48 +1152,21 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
        BUG_ON(cfq_cfqq_on_rr(cfqq));
 
        if (unlikely(cfqd->active_queue == cfqq)) {
-               __cfq_slice_expired(cfqd, cfqq, 0, 0);
+               __cfq_slice_expired(cfqd, cfqq, 0);
                cfq_schedule_dispatch(cfqd);
        }
 
-       /*
-        * it's on the empty list and still hashed
-        */
-       list_del(&cfqq->cfq_list);
-       hlist_del(&cfqq->cfq_hash);
        kmem_cache_free(cfq_pool, cfqq);
 }
 
-static struct cfq_queue *
-__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
-                   const int hashval)
-{
-       struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
-       struct hlist_node *entry;
-       struct cfq_queue *__cfqq;
-
-       hlist_for_each_entry(__cfqq, entry, hash_list, cfq_hash) {
-               const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->org_ioprio_class, __cfqq->org_ioprio);
-
-               if (__cfqq->key == key && (__p == prio || !prio))
-                       return __cfqq;
-       }
-
-       return NULL;
-}
-
-static struct cfq_queue *
-cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
-{
-       return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
-}
-
 static void cfq_free_io_context(struct io_context *ioc)
 {
        struct cfq_io_context *__cic;
        struct rb_node *n;
        int freed = 0;
 
+       ioc->ioc_data = NULL;
+
        while ((n = rb_first(&ioc->cic_root)) != NULL) {
                __cic = rb_entry(n, struct cfq_io_context, rb_node);
                rb_erase(&__cic->rb_node, &ioc->cic_root);
@@ -1166,7 +1183,7 @@ static void cfq_free_io_context(struct io_context *ioc)
 static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        if (unlikely(cfqq == cfqd->active_queue)) {
-               __cfq_slice_expired(cfqd, cfqq, 0, 0);
+               __cfq_slice_expired(cfqd, cfqq, 0);
                cfq_schedule_dispatch(cfqd);
        }
 
@@ -1191,10 +1208,6 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
        }
 }
 
-
-/*
- * Called with interrupts disabled
- */
 static void cfq_exit_single_io_context(struct cfq_io_context *cic)
 {
        struct cfq_data *cfqd = cic->key;
@@ -1208,15 +1221,20 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic)
        }
 }
 
+/*
+ * The process that ioc belongs to has exited, we need to clean up
+ * and put the internal structures we have that belongs to that process.
+ */
 static void cfq_exit_io_context(struct io_context *ioc)
 {
        struct cfq_io_context *__cic;
        struct rb_node *n;
 
+       ioc->ioc_data = NULL;
+
        /*
         * put the reference this task is holding to the various queues
         */
-
        n = rb_first(&ioc->cic_root);
        while (n != NULL) {
                __cic = rb_entry(n, struct cfq_io_context, rb_node);
@@ -1284,8 +1302,6 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
         */
        cfqq->org_ioprio = cfqq->ioprio;
        cfqq->org_ioprio_class = cfqq->ioprio_class;
-
-       cfq_resort_rr_list(cfqq, 0);
        cfq_clear_cfqq_prio_changed(cfqq);
 }
 
@@ -1303,7 +1319,7 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
        cfqq = cic->cfqq[ASYNC];
        if (cfqq) {
                struct cfq_queue *new_cfqq;
-               new_cfqq = cfq_get_queue(cfqd, CFQ_KEY_ASYNC, cic->ioc->task,
+               new_cfqq = cfq_get_queue(cfqd, ASYNC, cic->ioc->task,
                                         GFP_ATOMIC);
                if (new_cfqq) {
                        cic->cfqq[ASYNC] = new_cfqq;
@@ -1335,16 +1351,16 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc)
 }
 
 static struct cfq_queue *
-cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk,
+cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
              gfp_t gfp_mask)
 {
-       const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
        struct cfq_queue *cfqq, *new_cfqq = NULL;
-       unsigned short ioprio;
+       struct cfq_io_context *cic;
 
 retry:
-       ioprio = tsk->ioprio;
-       cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval);
+       cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+       /* cic always exists here */
+       cfqq = cic_to_cfqq(cic, is_sync);
 
        if (!cfqq) {
                if (new_cfqq) {
@@ -1369,20 +1385,20 @@ retry:
 
                memset(cfqq, 0, sizeof(*cfqq));
 
-               INIT_HLIST_NODE(&cfqq->cfq_hash);
-               INIT_LIST_HEAD(&cfqq->cfq_list);
+               RB_CLEAR_NODE(&cfqq->rb_node);
                INIT_LIST_HEAD(&cfqq->fifo);
 
-               cfqq->key = key;
-               hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
                atomic_set(&cfqq->ref, 0);
                cfqq->cfqd = cfqd;
 
-               if (key != CFQ_KEY_ASYNC)
+               if (is_sync) {
                        cfq_mark_cfqq_idle_window(cfqq);
+                       cfq_mark_cfqq_sync(cfqq);
+               }
 
                cfq_mark_cfqq_prio_changed(cfqq);
                cfq_mark_cfqq_queue_new(cfqq);
+
                cfq_init_prio_data(cfqq);
        }
 
@@ -1395,10 +1411,17 @@ out:
        return cfqq;
 }
 
+/*
+ * We drop cfq io contexts lazily, so we may find a dead one.
+ */
 static void
 cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic)
 {
        WARN_ON(!list_empty(&cic->queue_list));
+
+       if (ioc->ioc_data == cic)
+               ioc->ioc_data = NULL;
+
        rb_erase(&cic->rb_node, &ioc->cic_root);
        kmem_cache_free(cfq_ioc_pool, cic);
        elv_ioc_count_dec(ioc_count);
@@ -1411,6 +1434,16 @@ cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
        struct cfq_io_context *cic;
        void *k, *key = cfqd;
 
+       if (unlikely(!ioc))
+               return NULL;
+
+       /*
+        * we maintain a last-hit cache, to avoid browsing over the tree
+        */
+       cic = ioc->ioc_data;
+       if (cic && cic->key == cfqd)
+               return cic;
+
 restart:
        n = ioc->cic_root.rb_node;
        while (n) {
@@ -1426,8 +1459,10 @@ restart:
                        n = n->rb_left;
                else if (key > k)
                        n = n->rb_right;
-               else
+               else {
+                       ioc->ioc_data = cic;
                        return cic;
+               }
        }
 
        return NULL;
@@ -1524,7 +1559,8 @@ cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
 }
 
 static void
-cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq)
+cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
+                      struct request *rq)
 {
        sector_t sdist;
        u64 total;
@@ -1534,6 +1570,11 @@ cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq)
        else
                sdist = cic->last_request_pos - rq->sector;
 
+       if (!cic->seek_samples) {
+               cfqd->new_seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
+               cfqd->new_seek_mean = cfqd->new_seek_total / 256;
+       }
+
        /*
         * Don't allow the seek distance to get too large from the
         * odd fragment, pagein, etc
@@ -1558,7 +1599,12 @@ static void
 cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                       struct cfq_io_context *cic)
 {
-       int enable_idle = cfq_cfqq_idle_window(cfqq);
+       int enable_idle;
+
+       if (!cfq_cfqq_sync(cfqq))
+               return;
+
+       enable_idle = cfq_cfqq_idle_window(cfqq);
 
        if (!cic->ioc->task || !cfqd->cfq_slice_idle ||
            (cfqd->hw_tag && CIC_SEEKY(cic)))
@@ -1584,24 +1630,28 @@ static int
 cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
                   struct request *rq)
 {
-       struct cfq_queue *cfqq = cfqd->active_queue;
+       struct cfq_queue *cfqq;
 
-       if (cfq_class_idle(new_cfqq))
+       cfqq = cfqd->active_queue;
+       if (!cfqq)
                return 0;
 
-       if (!cfqq)
+       if (cfq_slice_used(cfqq))
+               return 1;
+
+       if (cfq_class_idle(new_cfqq))
                return 0;
 
        if (cfq_class_idle(cfqq))
                return 1;
-       if (!cfq_cfqq_wait_request(new_cfqq))
-               return 0;
+
        /*
         * if the new request is sync, but the currently running queue is
         * not, let the sync request have priority.
         */
        if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
                return 1;
+
        /*
         * So both queues are sync. Let the new request get disk time if
         * it's a metadata request and the current queue is doing regular IO.
@@ -1609,6 +1659,16 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
        if (rq_is_meta(rq) && !cfqq->meta_pending)
                return 1;
 
+       if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq))
+               return 0;
+
+       /*
+        * if this request is as-good as one we would expect from the
+        * current cfqq, let it preempt
+        */
+       if (cfq_rq_close(cfqd, rq))
+               return 1;
+
        return 0;
 }
 
@@ -1618,14 +1678,15 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
  */
 static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-       cfq_slice_expired(cfqd, 1, 1);
+       cfq_slice_expired(cfqd, 1);
 
        /*
         * Put the new queue at the front of the of the current list,
         * so we know that it will be selected next.
         */
        BUG_ON(!cfq_cfqq_on_rr(cfqq));
-       list_move(&cfqq->cfq_list, &cfqd->cur_rr);
+
+       cfq_service_tree_add(cfqd, cfqq, 1);
 
        cfqq->slice_end = 0;
        cfq_mark_cfqq_slice_new(cfqq);
@@ -1644,28 +1705,12 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        if (rq_is_meta(rq))
                cfqq->meta_pending++;
 
-       /*
-        * we never wait for an async request and we don't allow preemption
-        * of an async request. so just return early
-        */
-       if (!rq_is_sync(rq)) {
-               /*
-                * sync process issued an async request, if it's waiting
-                * then expire it and kick rq handling.
-                */
-               if (cic == cfqd->active_cic &&
-                   del_timer(&cfqd->idle_slice_timer)) {
-                       cfq_slice_expired(cfqd, 0, 0);
-                       blk_start_queueing(cfqd->queue);
-               }
-               return;
-       }
-
        cfq_update_io_thinktime(cfqd, cic);
-       cfq_update_io_seektime(cic, rq);
+       cfq_update_io_seektime(cfqd, cic, rq);
        cfq_update_idle_window(cfqd, cfqq, cic);
 
        cic->last_request_pos = rq->sector + rq->nr_sectors;
+       cfqq->last_request_pos = cic->last_request_pos;
 
        if (cfqq == cfqd->active_queue) {
                /*
@@ -1714,16 +1759,16 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
        now = jiffies;
 
        WARN_ON(!cfqd->rq_in_driver);
-       WARN_ON(!cfqq->on_dispatch[sync]);
+       WARN_ON(!cfqq->dispatched);
        cfqd->rq_in_driver--;
-       cfqq->on_dispatch[sync]--;
-       cfqq->service_last = now;
+       cfqq->dispatched--;
+
+       if (cfq_cfqq_sync(cfqq))
+               cfqd->sync_flight--;
 
        if (!cfq_class_idle(cfqq))
                cfqd->last_end_request = now;
 
-       cfq_resort_rr_list(cfqq, 0);
-
        if (sync)
                RQ_CIC(rq)->last_end_request = now;
 
@@ -1737,12 +1782,13 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
                        cfq_clear_cfqq_slice_new(cfqq);
                }
                if (cfq_slice_used(cfqq))
-                       cfq_slice_expired(cfqd, 0, 1);
-               else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) {
-                       if (!cfq_arm_slice_timer(cfqd))
-                               cfq_schedule_dispatch(cfqd);
-               }
+                       cfq_slice_expired(cfqd, 1);
+               else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list))
+                       cfq_arm_slice_timer(cfqd);
        }
+
+       if (!cfqd->rq_in_driver)
+               cfq_schedule_dispatch(cfqd);
 }
 
 /*
@@ -1751,9 +1797,6 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
  */
 static void cfq_prio_boost(struct cfq_queue *cfqq)
 {
-       const int ioprio_class = cfqq->ioprio_class;
-       const int ioprio = cfqq->ioprio;
-
        if (has_fs_excl()) {
                /*
                 * boost idle prio on transactions that would lock out other
@@ -1772,12 +1815,6 @@ static void cfq_prio_boost(struct cfq_queue *cfqq)
                if (cfqq->ioprio != cfqq->org_ioprio)
                        cfqq->ioprio = cfqq->org_ioprio;
        }
-
-       /*
-        * refile between round-robin lists if we moved the priority class
-        */
-       if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio))
-               cfq_resort_rr_list(cfqq, 0);
 }
 
 static inline int __cfq_may_queue(struct cfq_queue *cfqq)
@@ -1795,10 +1832,8 @@ static int cfq_may_queue(request_queue_t *q, int rw)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
        struct task_struct *tsk = current;
+       struct cfq_io_context *cic;
        struct cfq_queue *cfqq;
-       unsigned int key;
-
-       key = cfq_queue_pid(tsk, rw, rw & REQ_RW_SYNC);
 
        /*
         * don't force setup of a queue from here, as a call to may_queue
@@ -1806,7 +1841,11 @@ static int cfq_may_queue(request_queue_t *q, int rw)
         * so just lookup a possibly existing queue, or return 'may queue'
         * if that fails
         */
-       cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
+       cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+       if (!cic)
+               return ELV_MQUEUE_MAY;
+
+       cfqq = cic_to_cfqq(cic, rw & REQ_RW_SYNC);
        if (cfqq) {
                cfq_init_prio_data(cfqq);
                cfq_prio_boost(cfqq);
@@ -1850,7 +1889,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
        struct cfq_io_context *cic;
        const int rw = rq_data_dir(rq);
        const int is_sync = rq_is_sync(rq);
-       pid_t key = cfq_queue_pid(tsk, rw, is_sync);
        struct cfq_queue *cfqq;
        unsigned long flags;
 
@@ -1863,14 +1901,15 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
        if (!cic)
                goto queue_fail;
 
-       if (!cic->cfqq[is_sync]) {
-               cfqq = cfq_get_queue(cfqd, key, tsk, gfp_mask);
+       cfqq = cic_to_cfqq(cic, is_sync);
+       if (!cfqq) {
+               cfqq = cfq_get_queue(cfqd, is_sync, tsk, gfp_mask);
+
                if (!cfqq)
                        goto queue_fail;
 
-               cic->cfqq[is_sync] = cfqq;
-       } else
-               cfqq = cic->cfqq[is_sync];
+               cic_set_cfqq(cic, cfqq, is_sync);
+       }
 
        cfqq->allocated[rw]++;
        cfq_clear_cfqq_must_alloc(cfqq);
@@ -1940,7 +1979,7 @@ static void cfq_idle_slice_timer(unsigned long data)
                }
        }
 expire:
-       cfq_slice_expired(cfqd, 0, timed_out);
+       cfq_slice_expired(cfqd, timed_out);
 out_kick:
        cfq_schedule_dispatch(cfqd);
 out_cont:
@@ -1986,7 +2025,7 @@ static void cfq_exit_queue(elevator_t *e)
        spin_lock_irq(q->queue_lock);
 
        if (cfqd->active_queue)
-               __cfq_slice_expired(cfqd, cfqd->active_queue, 0, 0);
+               __cfq_slice_expired(cfqd, cfqd->active_queue, 0);
 
        while (!list_empty(&cfqd->cic_list)) {
                struct cfq_io_context *cic = list_entry(cfqd->cic_list.next,
@@ -2000,14 +2039,12 @@ static void cfq_exit_queue(elevator_t *e)
 
        cfq_shutdown_timer_wq(cfqd);
 
-       kfree(cfqd->cfq_hash);
        kfree(cfqd);
 }
 
 static void *cfq_init_queue(request_queue_t *q)
 {
        struct cfq_data *cfqd;
-       int i;
 
        cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node);
        if (!cfqd)
@@ -2015,21 +2052,9 @@ static void *cfq_init_queue(request_queue_t *q)
 
        memset(cfqd, 0, sizeof(*cfqd));
 
-       for (i = 0; i < CFQ_PRIO_LISTS; i++)
-               INIT_LIST_HEAD(&cfqd->rr_list[i]);
-
-       INIT_LIST_HEAD(&cfqd->busy_rr);
-       INIT_LIST_HEAD(&cfqd->cur_rr);
-       INIT_LIST_HEAD(&cfqd->idle_rr);
+       cfqd->service_tree = CFQ_RB_ROOT;
        INIT_LIST_HEAD(&cfqd->cic_list);
 
-       cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node);
-       if (!cfqd->cfq_hash)
-               goto out_free;
-
-       for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
-               INIT_HLIST_HEAD(&cfqd->cfq_hash[i]);
-
        cfqd->queue = q;
 
        init_timer(&cfqd->idle_slice_timer);
@@ -2053,9 +2078,6 @@ static void *cfq_init_queue(request_queue_t *q)
        cfqd->cfq_slice_idle = cfq_slice_idle;
 
        return cfqd;
-out_free:
-       kfree(cfqd);
-       return NULL;
 }
 
 static void cfq_slab_kill(void)
@@ -2087,7 +2109,6 @@ fail:
 /*
  * sysfs parts below -->
  */
-
 static ssize_t
 cfq_var_show(unsigned int var, char *page)
 {
index 96a00c822748cf8a673071a32806358963f5cdad..ce866eb75f6a997692cf4874dfe1ee8ceda216e8 100644 (file)
@@ -134,13 +134,13 @@ static struct elevator_type *elevator_get(const char *name)
 {
        struct elevator_type *e;
 
-       spin_lock_irq(&elv_list_lock);
+       spin_lock(&elv_list_lock);
 
        e = elevator_find(name);
        if (e && !try_module_get(e->elevator_owner))
                e = NULL;
 
-       spin_unlock_irq(&elv_list_lock);
+       spin_unlock(&elv_list_lock);
 
        return e;
 }
@@ -965,10 +965,11 @@ void elv_unregister_queue(struct request_queue *q)
 int elv_register(struct elevator_type *e)
 {
        char *def = "";
-       spin_lock_irq(&elv_list_lock);
+
+       spin_lock(&elv_list_lock);
        BUG_ON(elevator_find(e->elevator_name));
        list_add_tail(&e->list, &elv_list);
-       spin_unlock_irq(&elv_list_lock);
+       spin_unlock(&elv_list_lock);
 
        if (!strcmp(e->elevator_name, chosen_elevator) ||
                        (!*chosen_elevator &&
@@ -998,9 +999,9 @@ void elv_unregister(struct elevator_type *e)
                read_unlock(&tasklist_lock);
        }
 
-       spin_lock_irq(&elv_list_lock);
+       spin_lock(&elv_list_lock);
        list_del_init(&e->list);
-       spin_unlock_irq(&elv_list_lock);
+       spin_unlock(&elv_list_lock);
 }
 EXPORT_SYMBOL_GPL(elv_unregister);
 
@@ -1118,7 +1119,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
        struct list_head *entry;
        int len = 0;
 
-       spin_lock_irq(&elv_list_lock);
+       spin_lock(&elv_list_lock);
        list_for_each(entry, &elv_list) {
                struct elevator_type *__e;
 
@@ -1128,7 +1129,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
                else
                        len += sprintf(name+len, "%s ", __e->elevator_name);
        }
-       spin_unlock_irq(&elv_list_lock);
+       spin_unlock(&elv_list_lock);
 
        len += sprintf(len+name, "\n");
        return len;
index 3de06953ac33d24ce669c35f0e8ffdbb4bcb9661..123003a9047765e09abde8c223b89e9d9f0bd8d9 100644 (file)
@@ -3741,6 +3741,7 @@ static struct io_context *current_io_context(gfp_t gfp_flags, int node)
                ret->nr_batch_requests = 0; /* because this is 0 */
                ret->aic = NULL;
                ret->cic_root.rb_node = NULL;
+               ret->ioc_data = NULL;
                /* make sure set_task_ioprio() sees the settings above */
                smp_wmb();
                tsk->io_context = ret;
index 094397b4884968b5e90ee4d8f99fe16395aae178..9e917b8011b11e1b712bf769bf8c7bdab4a79a6e 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Michael MIC (IEEE 802.11i/TKIP) keyed digest
  *
- * Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004 Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -173,4 +173,4 @@ module_exit(michael_mic_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Michael MIC");
-MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>");
+MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");
index e2ce4a9c1c9259adf6d16da21b0a8b313f15b906..139f41f033d8bae09144493eb77c1ac2b09d3d41 100644 (file)
@@ -85,8 +85,8 @@ config ACPI_PROCFS
        depends on ACPI
        default y
        ---help---
-         Procfs interface for ACPI is made optional for back-compatible.
-         As the same functions are duplicated in sysfs interface
+         The Procfs interface for ACPI is made optional for backward compatibility.
+         As the same functions are duplicated in the sysfs interface
          and this proc interface will be removed some time later,
          it's marked as deprecated.
          ( /proc/acpi/debug_layer && debug_level are deprecated by
@@ -218,43 +218,6 @@ config ACPI_ASUS
          NOTE: This driver is deprecated and will probably be removed soon,
          use asus-laptop instead.
 
-config ACPI_IBM
-       tristate "IBM ThinkPad Laptop Extras"
-       depends on X86
-       select BACKLIGHT_CLASS_DEVICE
-       ---help---
-         This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
-         support for Fn-Fx key combinations, Bluetooth control, video
-         output switching, ThinkLight control, UltraBay eject and more.
-         For more information about this driver see <file:Documentation/ibm-acpi.txt>
-         and <http://ibm-acpi.sf.net/> .
-
-         If you have an IBM ThinkPad laptop, say Y or M here.
-
-config ACPI_IBM_DOCK
-       bool "Legacy Docking Station Support"
-       depends on ACPI_IBM
-       depends on ACPI_DOCK=n
-       default n
-       ---help---
-         Allows the ibm_acpi driver to handle docking station events.
-         This support is obsoleted by CONFIG_HOTPLUG_PCI_ACPI.  It will
-         allow locking and removing the laptop from the docking station,
-         but will not properly connect PCI devices.
-
-         If you are not sure, say N here.
-
-config ACPI_IBM_BAY
-       bool "Legacy Removable Bay Support"
-       depends on ACPI_IBM
-       default y
-       ---help---
-         Allows the ibm_acpi driver to handle removable bays.  It will allow
-         disabling the device in the bay, and also generate notifications when
-         the bay lever is ejected or inserted.
-
-         If you are not sure, say Y here.
-
 config ACPI_TOSHIBA
        tristate "Toshiba Laptop Extras"
        depends on X86
@@ -388,11 +351,10 @@ config ACPI_HOTPLUG_MEMORY
 
 config ACPI_SBS
        tristate "Smart Battery System (EXPERIMENTAL)"
-       depends on X86 && I2C
+       depends on X86
        depends on EXPERIMENTAL
        help
          This driver adds support for the Smart Battery System.
-         Depends on I2C (Device Drivers ---> I2C support)
          A "Smart Battery" is quite old and quite rare compared
          to today's ACPI "Control Method" battery.
 
index 5956e9f64a8bfd682754999267f99f80ba9a7558..d4336f1730e9a0324ff61cfed04bd7215e03a816 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Makefile for the Linux ACPI interpreter
-# 
+#
 
 export ACPI_CFLAGS
 
@@ -32,16 +32,17 @@ obj-y                               += osl.o utils.o \
 processor-objs += processor_core.o processor_throttling.o \
                                processor_idle.o processor_thermal.o
 ifdef CONFIG_CPU_FREQ
-processor-objs += processor_perflib.o                  
+processor-objs += processor_perflib.o
 endif
 
 obj-y                          += sleep/
 obj-y                          += bus.o glue.o
 obj-y                          += scan.o
+# Keep EC driver first. Initialization of others depend on it.
+obj-$(CONFIG_ACPI_EC)          += ec.o
 obj-$(CONFIG_ACPI_AC)          += ac.o
 obj-$(CONFIG_ACPI_BATTERY)     += battery.o
 obj-$(CONFIG_ACPI_BUTTON)      += button.o
-obj-$(CONFIG_ACPI_EC)          += ec.o
 obj-$(CONFIG_ACPI_FAN)         += fan.o
 obj-$(CONFIG_ACPI_DOCK)                += dock.o
 obj-$(CONFIG_ACPI_BAY)         += bay.o
@@ -55,8 +56,7 @@ obj-$(CONFIG_ACPI_SYSTEM)     += system.o event.o
 obj-$(CONFIG_ACPI_DEBUG)       += debug.o
 obj-$(CONFIG_ACPI_NUMA)                += numa.o
 obj-$(CONFIG_ACPI_ASUS)                += asus_acpi.o
-obj-$(CONFIG_ACPI_IBM)         += ibm_acpi.o
 obj-$(CONFIG_ACPI_TOSHIBA)     += toshiba_acpi.o
 obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)      += acpi_memhotplug.o
 obj-y                          += cm_sbs.o
-obj-$(CONFIG_ACPI_SBS)         += i2c_ec.o sbs.o
+obj-$(CONFIG_ACPI_SBS)         += sbs.o
index c26172671fd882a175eb04cba40d6a8d1db8c304..e65628a030852a736ab40a59407d1af14a883888 100644 (file)
@@ -44,11 +44,6 @@ MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
 MODULE_DESCRIPTION("Hotplug Mem Driver");
 MODULE_LICENSE("GPL");
 
-/* ACPI _STA method values */
-#define ACPI_MEMORY_STA_PRESENT                (0x00000001UL)
-#define ACPI_MEMORY_STA_ENABLED                (0x00000002UL)
-#define ACPI_MEMORY_STA_FUNCTIONAL     (0x00000008UL)
-
 /* Memory Device States */
 #define MEMORY_INVALID_STATE   0
 #define MEMORY_POWER_ON_STATE  1
@@ -204,9 +199,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
         * Check for device status. Device should be
         * present/enabled/functioning.
         */
-       if (!((current_status & ACPI_MEMORY_STA_PRESENT)
-             && (current_status & ACPI_MEMORY_STA_ENABLED)
-             && (current_status & ACPI_MEMORY_STA_FUNCTIONAL)))
+       if (!((current_status & ACPI_STA_DEVICE_PRESENT)
+             && (current_status & ACPI_STA_DEVICE_ENABLED)
+             && (current_status & ACPI_STA_DEVICE_FUNCTIONING)))
                return -ENODEV;
 
        return 0;
@@ -286,7 +281,7 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
                return -ENODEV;
 
        /* Check for device status.  Device should be disabled */
-       if (current_status & ACPI_MEMORY_STA_ENABLED)
+       if (current_status & ACPI_STA_DEVICE_ENABLED)
                return -EINVAL;
 
        return 0;
index dd49ea0d0ed3606a69dfc2a9580b64768ced7cb9..e5084ececb6ff7f004326a3fcdf24828c45e2f0a 100644 (file)
@@ -103,7 +103,9 @@ int acpi_bus_get_status(struct acpi_device *device)
        else if (device->parent)
                device->status = device->parent->status;
        else
-               STRUCT_TO_INT(device->status) = 0x0F;
+               STRUCT_TO_INT(device->status) =
+                   ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+                   ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING;
 
        if (device->status.functional && !device->status.present) {
                printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
index 0930d9413dfa31768e889e7150e9dd55a0691670..0dd3bf7c0ed1f7c281dc576ac50fa436e97f2118 100644 (file)
@@ -49,8 +49,6 @@ MODULE_AUTHOR("Anil S Keshavamurthy");
 MODULE_DESCRIPTION("ACPI container driver");
 MODULE_LICENSE("GPL");
 
-#define ACPI_STA_PRESENT               (0x00000001)
-
 static int acpi_container_add(struct acpi_device *device);
 static int acpi_container_remove(struct acpi_device *device, int type);
 
@@ -75,13 +73,13 @@ static int is_device_present(acpi_handle handle)
 
        status = acpi_get_handle(handle, "_STA", &temp);
        if (ACPI_FAILURE(status))
-               return 1;       /* _STA not found, assmue device present */
+               return 1;       /* _STA not found, assume device present */
 
        status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
        if (ACPI_FAILURE(status))
                return 0;       /* Firmware error */
 
-       return ((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
+       return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
 }
 
 /*******************************************************************/
index 54a697f9aa1873400cd2ad1237b786e4f3f9550e..4546bf873aea273c2a0993fb3fbb465d801543ed 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/notifier.h>
 #include <linux/platform_device.h>
 #include <linux/jiffies.h>
+#include <linux/stddef.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -667,6 +668,23 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
 }
 DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
 
+/*
+ * show_dock_uid - read method for "uid" file in sysfs
+ */
+static ssize_t show_dock_uid(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       unsigned long lbuf;
+       acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf);
+       if(ACPI_FAILURE(status)) {
+           return 0;
+       }
+       return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
+}
+DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
+
+
+
 /**
  * dock_add - add a new dock station
  * @handle: the dock station handle
@@ -715,6 +733,13 @@ static int dock_add(acpi_handle handle)
                kfree(dock_station);
                return ret;
        }
+       ret = device_create_file(&dock_device.dev, &dev_attr_uid);
+       if (ret) {
+               printk("Error %d adding sysfs file\n", ret);
+               platform_device_unregister(&dock_device);
+               kfree(dock_station);
+               return ret;
+       }
 
        /* Find dependent devices */
        acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
index a802962ff2b499fc2cc3489a5e28a02e58d2465d..e08cf98f504f12583174d23468a60bf4f9a28c14 100644 (file)
@@ -1,6 +1,8 @@
 /*
- *  acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 38 $)
+ *  ec.c - ACPI Embedded Controller Driver (v2.0)
  *
+ *  Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
+ *  Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
  *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -91,9 +93,9 @@ static struct acpi_driver acpi_ec_driver = {
 };
 
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
+/* External interfaces use first EC only, so remember */
 static struct acpi_ec {
        acpi_handle handle;
-       unsigned long uid;
        unsigned long gpe;
        unsigned long command_addr;
        unsigned long data_addr;
@@ -101,12 +103,8 @@ static struct acpi_ec {
        struct mutex lock;
        atomic_t query_pending;
        atomic_t event_count;
-       atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
        wait_queue_head_t wait;
-} *ec_ecdt;
-
-/* External interfaces use first EC only, so remember */
-static struct acpi_device *first_ec;
+} *boot_ec, *first_ec;
 
 /* --------------------------------------------------------------------------
                              Transaction Management
@@ -173,56 +171,6 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
        return -ETIME;
 }
 
-#ifdef ACPI_FUTURE_USAGE
-/*
- * Note: samsung nv5000 doesn't work with ec burst mode.
- * http://bugzilla.kernel.org/show_bug.cgi?id=4980
- */
-int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
-{
-       u8 tmp = 0;
-       u8 status = 0;
-
-       status = acpi_ec_read_status(ec);
-       if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
-               status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
-               if (status)
-                       goto end;
-               acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE);
-               status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
-               tmp = acpi_ec_read_data(ec);
-               if (tmp != 0x90) {      /* Burst ACK byte */
-                       return -EINVAL;
-               }
-       }
-
-       atomic_set(&ec->leaving_burst, 0);
-       return 0;
-      end:
-       ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
-       return -1;
-}
-
-int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
-{
-       u8 status = 0;
-
-       status = acpi_ec_read_status(ec);
-       if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) {
-               status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
-               if (status)
-                       goto end;
-               acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
-               acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
-       }
-       atomic_set(&ec->leaving_burst, 1);
-       return 0;
-      end:
-       ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
-       return -1;
-}
-#endif                         /* ACPI_FUTURE_USAGE */
-
 static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
                                        const u8 * wdata, unsigned wdata_len,
                                        u8 * rdata, unsigned rdata_len)
@@ -312,6 +260,21 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
        return status;
 }
 
+/*
+ * Note: samsung nv5000 doesn't work with ec burst mode.
+ * http://bugzilla.kernel.org/show_bug.cgi?id=4980
+ */
+int acpi_ec_burst_enable(struct acpi_ec *ec)
+{
+       u8 d;
+       return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1);
+}
+
+int acpi_ec_burst_disable(struct acpi_ec *ec)
+{
+       return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0);
+}
+
 static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
 {
        int result;
@@ -333,18 +296,33 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
 /*
  * Externally callable EC access functions. For now, assume 1 EC only
  */
+int ec_burst_enable(void)
+{
+       if (!first_ec)
+               return -ENODEV;
+       return acpi_ec_burst_enable(first_ec);
+}
+
+EXPORT_SYMBOL(ec_burst_enable);
+
+int ec_burst_disable(void)
+{
+       if (!first_ec)
+               return -ENODEV;
+       return acpi_ec_burst_disable(first_ec);
+}
+
+EXPORT_SYMBOL(ec_burst_disable);
+
 int ec_read(u8 addr, u8 * val)
 {
-       struct acpi_ec *ec;
        int err;
        u8 temp_data;
 
        if (!first_ec)
                return -ENODEV;
 
-       ec = acpi_driver_data(first_ec);
-
-       err = acpi_ec_read(ec, addr, &temp_data);
+       err = acpi_ec_read(first_ec, addr, &temp_data);
 
        if (!err) {
                *val = temp_data;
@@ -357,15 +335,12 @@ EXPORT_SYMBOL(ec_read);
 
 int ec_write(u8 addr, u8 val)
 {
-       struct acpi_ec *ec;
        int err;
 
        if (!first_ec)
                return -ENODEV;
 
-       ec = acpi_driver_data(first_ec);
-
-       err = acpi_ec_write(ec, addr, val);
+       err = acpi_ec_write(first_ec, addr, val);
 
        return err;
 }
@@ -376,14 +351,10 @@ int ec_transaction(u8 command,
                   const u8 * wdata, unsigned wdata_len,
                   u8 * rdata, unsigned rdata_len)
 {
-       struct acpi_ec *ec;
-
        if (!first_ec)
                return -ENODEV;
 
-       ec = acpi_driver_data(first_ec);
-
-       return acpi_ec_transaction(ec, command, wdata,
+       return acpi_ec_transaction(first_ec, command, wdata,
                                   wdata_len, rdata, rdata_len);
 }
 
@@ -420,7 +391,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
 
 static void acpi_ec_gpe_query(void *ec_cxt)
 {
-       struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
+       struct acpi_ec *ec = ec_cxt;
        u8 value = 0;
        char object_name[8];
 
@@ -438,8 +409,9 @@ static u32 acpi_ec_gpe_handler(void *data)
 {
        acpi_status status = AE_OK;
        u8 value;
-       struct acpi_ec *ec = (struct acpi_ec *)data;
+       struct acpi_ec *ec = data;
        atomic_inc(&ec->event_count);
+
        if (acpi_ec_mode == EC_INTR) {
                wake_up(&ec->wait);
        }
@@ -482,7 +454,7 @@ acpi_ec_space_handler(u32 function,
                      void *handler_context, void *region_context)
 {
        int result = 0;
-       struct acpi_ec *ec = NULL;
+       struct acpi_ec *ec = handler_context;
        u64 temp = *value;
        acpi_integer f_v = 0;
        int i = 0;
@@ -494,8 +466,6 @@ acpi_ec_space_handler(u32 function,
                return AE_BAD_PARAMETER;
        }
 
-       ec = (struct acpi_ec *)handler_context;
-
       next_byte:
        switch (function) {
        case ACPI_READ:
@@ -551,18 +521,16 @@ static struct proc_dir_entry *acpi_ec_dir;
 
 static int acpi_ec_read_info(struct seq_file *seq, void *offset)
 {
-       struct acpi_ec *ec = (struct acpi_ec *)seq->private;
+       struct acpi_ec *ec = seq->private;
 
        if (!ec)
                goto end;
 
-       seq_printf(seq, "gpe:                 0x%02x\n", (u32) ec->gpe);
-       seq_printf(seq, "ports:                   0x%02x, 0x%02x\n",
-                  (u32) ec->command_addr, (u32) ec->data_addr);
-       seq_printf(seq, "use global lock:         %s\n",
+       seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe);
+       seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n",
+                  (unsigned)ec->command_addr, (unsigned)ec->data_addr);
+       seq_printf(seq, "use global lock:\t%s\n",
                   ec->global_lock ? "yes" : "no");
-       acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
-
       end:
        return 0;
 }
@@ -619,154 +587,122 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
 /* --------------------------------------------------------------------------
                                Driver Interface
    -------------------------------------------------------------------------- */
+static acpi_status
+ec_parse_io_ports(struct acpi_resource *resource, void *context);
+
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
+
+static struct acpi_ec *make_acpi_ec(void)
+{
+       struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+       if (!ec)
+               return NULL;
+
+       atomic_set(&ec->query_pending, 1);
+       atomic_set(&ec->event_count, 1);
+       mutex_init(&ec->lock);
+       init_waitqueue_head(&ec->wait);
+
+       return ec;
+}
 
 static int acpi_ec_add(struct acpi_device *device)
 {
-       int result = 0;
        acpi_status status = AE_OK;
        struct acpi_ec *ec = NULL;
 
        if (!device)
                return -EINVAL;
 
-       ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
-       if (!ec)
-               return -ENOMEM;
-
-       ec->handle = device->handle;
-       ec->uid = -1;
-       mutex_init(&ec->lock);
-       atomic_set(&ec->query_pending, 0);
-       atomic_set(&ec->event_count, 1);
-       if (acpi_ec_mode == EC_INTR) {
-               atomic_set(&ec->leaving_burst, 1);
-               init_waitqueue_head(&ec->wait);
-       }
        strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_EC_CLASS);
-       acpi_driver_data(device) = ec;
-
-       /* Use the global lock for all EC transactions? */
-       acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock);
-
-       /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
-          http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
-       if (ec_ecdt) {
-               acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
-                                                 ACPI_ADR_SPACE_EC,
-                                                 &acpi_ec_space_handler);
 
-               acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
-                                       &acpi_ec_gpe_handler);
+       ec = make_acpi_ec();
+       if (!ec)
+               return -ENOMEM;
 
-               kfree(ec_ecdt);
+       status = ec_parse_device(device->handle, 0, ec, NULL);
+       if (status != AE_CTRL_TERMINATE) {
+               kfree(ec);
+               return -EINVAL;
        }
 
-       /* Get GPE bit assignment (EC events). */
-       /* TODO: Add support for _GPE returning a package */
-       status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Obtaining GPE bit assignment"));
-               result = -ENODEV;
-               goto end;
-       }
+       /* Check if we found the boot EC */
+       if (boot_ec) {
+               if (boot_ec->gpe == ec->gpe) {
+                       /* We might have incorrect info for GL at boot time */
+                       mutex_lock(&boot_ec->lock);
+                       boot_ec->global_lock = ec->global_lock;
+                       mutex_unlock(&boot_ec->lock);
+                       kfree(ec);
+                       ec = boot_ec;
+               }
+       } else
+               first_ec = ec;
+       ec->handle = device->handle;
+       acpi_driver_data(device) = ec;
 
-       result = acpi_ec_add_fs(device);
-       if (result)
-               goto end;
+       acpi_ec_add_fs(device);
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
                          acpi_device_name(device), acpi_device_bid(device),
                          (u32) ec->gpe));
 
-       if (!first_ec)
-               first_ec = device;
-
-      end:
-       if (result)
-               kfree(ec);
-
-       return result;
+       return 0;
 }
 
 static int acpi_ec_remove(struct acpi_device *device, int type)
 {
-       struct acpi_ec *ec = NULL;
+       struct acpi_ec *ec;
 
        if (!device)
                return -EINVAL;
 
        ec = acpi_driver_data(device);
-
        acpi_ec_remove_fs(device);
+       acpi_driver_data(device) = NULL;
+       if (ec == first_ec)
+               first_ec = NULL;
 
-       kfree(ec);
-
+       /* Don't touch boot EC */
+       if (boot_ec != ec)
+               kfree(ec);
        return 0;
 }
 
 static acpi_status
-acpi_ec_io_ports(struct acpi_resource *resource, void *context)
+ec_parse_io_ports(struct acpi_resource *resource, void *context)
 {
-       struct acpi_ec *ec = (struct acpi_ec *)context;
+       struct acpi_ec *ec = context;
 
-       if (resource->type != ACPI_RESOURCE_TYPE_IO) {
+       if (resource->type != ACPI_RESOURCE_TYPE_IO)
                return AE_OK;
-       }
 
        /*
         * The first address region returned is the data port, and
         * the second address region returned is the status/command
         * port.
         */
-       if (ec->data_addr == 0) {
+       if (ec->data_addr == 0)
                ec->data_addr = resource->data.io.minimum;
-       } else if (ec->command_addr == 0) {
+       else if (ec->command_addr == 0)
                ec->command_addr = resource->data.io.minimum;
-       } else {
+       else
                return AE_CTRL_TERMINATE;
-       }
 
        return AE_OK;
 }
 
-static int acpi_ec_start(struct acpi_device *device)
+static int ec_install_handlers(struct acpi_ec *ec)
 {
-       acpi_status status = AE_OK;
-       struct acpi_ec *ec = NULL;
-
-       if (!device)
-               return -EINVAL;
-
-       ec = acpi_driver_data(device);
-
-       if (!ec)
-               return -EINVAL;
-
-       /*
-        * Get I/O port addresses. Convert to GAS format.
-        */
-       status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
-                                    acpi_ec_io_ports, ec);
-       if (ACPI_FAILURE(status) || ec->command_addr == 0) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Error getting I/O port addresses"));
-               return -ENODEV;
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
-                         ec->gpe, ec->command_addr, ec->data_addr));
-
-       /*
-        * Install GPE handler
-        */
+       acpi_status status;
        status = acpi_install_gpe_handler(NULL, ec->gpe,
                                          ACPI_GPE_EDGE_TRIGGERED,
                                          &acpi_ec_gpe_handler, ec);
-       if (ACPI_FAILURE(status)) {
+       if (ACPI_FAILURE(status))
                return -ENODEV;
-       }
+
        acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
        acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
 
@@ -779,18 +715,49 @@ static int acpi_ec_start(struct acpi_device *device)
                return -ENODEV;
        }
 
-       return AE_OK;
+       /* EC is fully operational, allow queries */
+       atomic_set(&ec->query_pending, 0);
+
+       return 0;
+}
+
+static int acpi_ec_start(struct acpi_device *device)
+{
+       struct acpi_ec *ec;
+
+       if (!device)
+               return -EINVAL;
+
+       ec = acpi_driver_data(device);
+
+       if (!ec)
+               return -EINVAL;
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
+                         ec->gpe, ec->command_addr, ec->data_addr));
+
+       /* Boot EC is already working */
+       if (ec == boot_ec)
+               return 0;
+
+       return ec_install_handlers(ec);
 }
 
 static int acpi_ec_stop(struct acpi_device *device, int type)
 {
-       acpi_status status = AE_OK;
-       struct acpi_ec *ec = NULL;
+       acpi_status status;
+       struct acpi_ec *ec;
 
        if (!device)
                return -EINVAL;
 
        ec = acpi_driver_data(device);
+       if (!ec)
+               return -EINVAL;
+
+       /* Don't touch boot EC */
+       if (ec == boot_ec)
+               return 0;
 
        status = acpi_remove_address_space_handler(ec->handle,
                                                   ACPI_ADR_SPACE_EC,
@@ -805,164 +772,67 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
        return 0;
 }
 
-static acpi_status __init
-acpi_fake_ecdt_callback(acpi_handle handle,
-                       u32 Level, void *context, void **retval)
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
 {
        acpi_status status;
 
-       mutex_init(&ec_ecdt->lock);
-       atomic_set(&ec_ecdt->event_count, 1);
-       if (acpi_ec_mode == EC_INTR) {
-               init_waitqueue_head(&ec_ecdt->wait);
-       }
+       struct acpi_ec *ec = context;
        status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-                                    acpi_ec_io_ports, ec_ecdt);
+                                    ec_parse_io_ports, ec);
        if (ACPI_FAILURE(status))
                return status;
 
-       ec_ecdt->uid = -1;
-       acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
-
-       status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe);
+       /* Get GPE bit assignment (EC events). */
+       /* TODO: Add support for _GPE returning a package */
+       status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
        if (ACPI_FAILURE(status))
                return status;
-       ec_ecdt->global_lock = TRUE;
-       ec_ecdt->handle = handle;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
-                         ec_ecdt->gpe, ec_ecdt->command_addr,
-                         ec_ecdt->data_addr));
 
-       return AE_CTRL_TERMINATE;
-}
-
-/*
- * Some BIOS (such as some from Gateway laptops) access EC region very early
- * such as in BAT0._INI or EC._INI before an EC device is found and
- * do not provide an ECDT. According to ACPI spec, ECDT isn't mandatorily
- * required, but if EC regison is accessed early, it is required.
- * The routine tries to workaround the BIOS bug by pre-scan EC device
- * It assumes that _CRS, _HID, _GPE, _UID methods of EC don't touch any
- * op region (since _REG isn't invoked yet). The assumption is true for
- * all systems found.
- */
-static int __init acpi_ec_fake_ecdt(void)
-{
-       acpi_status status;
-       int ret = 0;
+       /* Use the global lock for all EC transactions? */
+       acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
+       ec->handle = handle;
 
-       ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
-       if (!ec_ecdt) {
-               ret = -ENOMEM;
-               goto error;
-       }
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
+                         ec->gpe, ec->command_addr, ec->data_addr));
 
-       status = acpi_get_devices(ACPI_EC_HID,
-                                 acpi_fake_ecdt_callback, NULL, NULL);
-       if (ACPI_FAILURE(status)) {
-               kfree(ec_ecdt);
-               ec_ecdt = NULL;
-               ret = -ENODEV;
-               ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
-               goto error;
-       }
-       return 0;
-      error:
-       return ret;
+       return AE_CTRL_TERMINATE;
 }
 
-static int __init acpi_ec_get_real_ecdt(void)
+int __init acpi_ec_ecdt_probe(void)
 {
+       int ret;
        acpi_status status;
        struct acpi_table_ecdt *ecdt_ptr;
 
-       status = acpi_get_table(ACPI_SIG_ECDT, 1,
-                               (struct acpi_table_header **)&ecdt_ptr);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
-
+       boot_ec = make_acpi_ec();
+       if (!boot_ec)
+               return -ENOMEM;
        /*
-        * Generate a temporary ec context to use until the namespace is scanned
+        * Generate a boot ec context
         */
-       ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
-       if (!ec_ecdt)
-               return -ENOMEM;
 
-       mutex_init(&ec_ecdt->lock);
-       atomic_set(&ec_ecdt->event_count, 1);
-       if (acpi_ec_mode == EC_INTR) {
-               init_waitqueue_head(&ec_ecdt->wait);
-       }
-       ec_ecdt->command_addr = ecdt_ptr->control.address;
-       ec_ecdt->data_addr = ecdt_ptr->data.address;
-       ec_ecdt->gpe = ecdt_ptr->gpe;
-       /* use the GL just to be safe */
-       ec_ecdt->global_lock = TRUE;
-       ec_ecdt->uid = ecdt_ptr->uid;
-
-       status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
-       if (ACPI_FAILURE(status)) {
+       status = acpi_get_table(ACPI_SIG_ECDT, 1,
+                               (struct acpi_table_header **)&ecdt_ptr);
+       if (ACPI_FAILURE(status))
                goto error;
-       }
-
-       return 0;
-      error:
-       ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
-       kfree(ec_ecdt);
-       ec_ecdt = NULL;
 
-       return -ENODEV;
-}
-
-static int __initdata acpi_fake_ecdt_enabled;
-int __init acpi_ec_ecdt_probe(void)
-{
-       acpi_status status;
-       int ret;
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
 
-       ret = acpi_ec_get_real_ecdt();
-       /* Try to make a fake ECDT */
-       if (ret && acpi_fake_ecdt_enabled) {
-               ret = acpi_ec_fake_ecdt();
-       }
+       boot_ec->command_addr = ecdt_ptr->control.address;
+       boot_ec->data_addr = ecdt_ptr->data.address;
+       boot_ec->gpe = ecdt_ptr->gpe;
+       boot_ec->handle = ACPI_ROOT_OBJECT;
 
-       if (ret)
+       ret = ec_install_handlers(boot_ec);
+       if (!ret) {
+               first_ec = boot_ec;
                return 0;
-
-       /*
-        * Install GPE handler
-        */
-       status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe,
-                                         ACPI_GPE_EDGE_TRIGGERED,
-                                         &acpi_ec_gpe_handler, ec_ecdt);
-       if (ACPI_FAILURE(status)) {
-               goto error;
        }
-       acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME);
-       acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR);
-
-       status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
-                                                   ACPI_ADR_SPACE_EC,
-                                                   &acpi_ec_space_handler,
-                                                   &acpi_ec_space_setup,
-                                                   ec_ecdt);
-       if (ACPI_FAILURE(status)) {
-               acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
-                                       &acpi_ec_gpe_handler);
-               goto error;
-       }
-
-       return 0;
-
       error:
-       ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
-       kfree(ec_ecdt);
-       ec_ecdt = NULL;
+       kfree(boot_ec);
+       boot_ec = NULL;
 
        return -ENODEV;
 }
@@ -1003,13 +873,6 @@ static void __exit acpi_ec_exit(void)
 }
 #endif                         /* 0 */
 
-static int __init acpi_fake_ecdt_setup(char *str)
-{
-       acpi_fake_ecdt_enabled = 1;
-       return 1;
-}
-
-__setup("acpi_fake_ecdt", acpi_fake_ecdt_setup);
 static int __init acpi_ec_set_intr_mode(char *str)
 {
        int intr;
@@ -1017,12 +880,8 @@ static int __init acpi_ec_set_intr_mode(char *str)
        if (!get_option(&str, &intr))
                return 0;
 
-       if (intr) {
-               acpi_ec_mode = EC_INTR;
-       } else {
-               acpi_ec_mode = EC_POLL;
-       }
-       acpi_ec_driver.ops.add = acpi_ec_add;
+       acpi_ec_mode = (intr) ? EC_INTR : EC_POLL;
+
        printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling");
 
        return 1;
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
deleted file mode 100644 (file)
index acab4a4..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * SMBus driver for ACPI Embedded Controller ($Revision: 1.3 $)
- *
- * Copyright (c) 2002, 2005 Ducrot Bruno
- * Copyright (c) 2005 Rich Townsend (tiny hacks & tweaks)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2.
- */
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/delay.h>
-
-#include "i2c_ec.h"
-
-#define        xudelay(t)      udelay(t)
-#define        xmsleep(t)      msleep(t)
-
-#define ACPI_EC_HC_COMPONENT   0x00080000
-#define ACPI_EC_HC_CLASS       "ec_hc_smbus"
-#define ACPI_EC_HC_HID         "ACPI0001"
-#define ACPI_EC_HC_DEVICE_NAME "EC HC smbus"
-
-#define _COMPONENT             ACPI_EC_HC_COMPONENT
-
-ACPI_MODULE_NAME("i2c_ec");
-
-static int acpi_ec_hc_add(struct acpi_device *device);
-static int acpi_ec_hc_remove(struct acpi_device *device, int type);
-
-static struct acpi_driver acpi_ec_hc_driver = {
-       .name = "i2c_ec",
-       .class = ACPI_EC_HC_CLASS,
-       .ids = ACPI_EC_HC_HID,
-       .ops = {
-               .add = acpi_ec_hc_add,
-               .remove = acpi_ec_hc_remove,
-               },
-};
-
-/* Various bit mask for EC_SC (R) */
-#define OBF            0x01
-#define IBF            0x02
-#define CMD            0x08
-#define BURST          0x10
-#define SCI_EVT                0x20
-#define SMI_EVT                0x40
-
-/* Commands for EC_SC (W) */
-#define RD_EC          0x80
-#define WR_EC          0x81
-#define BE_EC          0x82
-#define BD_EC          0x83
-#define QR_EC          0x84
-
-/*
- * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
- */
-
-#define ACPI_EC_SMB_PRTCL      0x00    /* protocol, PEC */
-#define ACPI_EC_SMB_STS                0x01    /* status */
-#define ACPI_EC_SMB_ADDR       0x02    /* address */
-#define ACPI_EC_SMB_CMD                0x03    /* command */
-#define ACPI_EC_SMB_DATA       0x04    /* 32 data registers */
-#define ACPI_EC_SMB_BCNT       0x24    /* number of data bytes */
-#define ACPI_EC_SMB_ALRM_A     0x25    /* alarm address */
-#define ACPI_EC_SMB_ALRM_D     0x26    /* 2 bytes alarm data */
-
-#define ACPI_EC_SMB_STS_DONE   0x80
-#define ACPI_EC_SMB_STS_ALRM   0x40
-#define ACPI_EC_SMB_STS_RES    0x20
-#define ACPI_EC_SMB_STS_STATUS 0x1f
-
-#define ACPI_EC_SMB_STATUS_OK          0x00
-#define ACPI_EC_SMB_STATUS_FAIL                0x07
-#define ACPI_EC_SMB_STATUS_DNAK                0x10
-#define ACPI_EC_SMB_STATUS_DERR                0x11
-#define ACPI_EC_SMB_STATUS_CMD_DENY    0x12
-#define ACPI_EC_SMB_STATUS_UNKNOWN     0x13
-#define ACPI_EC_SMB_STATUS_ACC_DENY    0x17
-#define ACPI_EC_SMB_STATUS_TIMEOUT     0x18
-#define ACPI_EC_SMB_STATUS_NOTSUP      0x19
-#define ACPI_EC_SMB_STATUS_BUSY                0x1A
-#define ACPI_EC_SMB_STATUS_PEC         0x1F
-
-#define ACPI_EC_SMB_PRTCL_WRITE                        0x00
-#define ACPI_EC_SMB_PRTCL_READ                 0x01
-#define ACPI_EC_SMB_PRTCL_QUICK                        0x02
-#define ACPI_EC_SMB_PRTCL_BYTE                 0x04
-#define ACPI_EC_SMB_PRTCL_BYTE_DATA            0x06
-#define ACPI_EC_SMB_PRTCL_WORD_DATA            0x08
-#define ACPI_EC_SMB_PRTCL_BLOCK_DATA           0x0a
-#define ACPI_EC_SMB_PRTCL_PROC_CALL            0x0c
-#define ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL      0x0d
-#define ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA       0x4a
-#define ACPI_EC_SMB_PRTCL_PEC                  0x80
-
-/* Length of pre/post transaction sleep (msec) */
-#define ACPI_EC_SMB_TRANSACTION_SLEEP          1
-#define ACPI_EC_SMB_ACCESS_SLEEP1              1
-#define ACPI_EC_SMB_ACCESS_SLEEP2              10
-
-static int acpi_ec_smb_read(struct acpi_ec_smbus *smbus, u8 address, u8 * data)
-{
-       u8 val;
-       int err;
-
-       err = ec_read(smbus->base + address, &val);
-       if (!err) {
-               *data = val;
-       }
-       xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
-       return (err);
-}
-
-static int acpi_ec_smb_write(struct acpi_ec_smbus *smbus, u8 address, u8 data)
-{
-       int err;
-
-       err = ec_write(smbus->base + address, data);
-       return (err);
-}
-
-static int
-acpi_ec_smb_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
-                  char read_write, u8 command, int size,
-                  union i2c_smbus_data *data)
-{
-       struct acpi_ec_smbus *smbus = adap->algo_data;
-       unsigned char protocol, len = 0, pec, temp[2] = { 0, 0 };
-       int i;
-
-       if (read_write == I2C_SMBUS_READ) {
-               protocol = ACPI_EC_SMB_PRTCL_READ;
-       } else {
-               protocol = ACPI_EC_SMB_PRTCL_WRITE;
-       }
-       pec = (flags & I2C_CLIENT_PEC) ? ACPI_EC_SMB_PRTCL_PEC : 0;
-
-       switch (size) {
-
-       case I2C_SMBUS_QUICK:
-               protocol |= ACPI_EC_SMB_PRTCL_QUICK;
-               read_write = I2C_SMBUS_WRITE;
-               break;
-
-       case I2C_SMBUS_BYTE:
-               if (read_write == I2C_SMBUS_WRITE) {
-                       acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
-               }
-               protocol |= ACPI_EC_SMB_PRTCL_BYTE;
-               break;
-
-       case I2C_SMBUS_BYTE_DATA:
-               acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-               if (read_write == I2C_SMBUS_WRITE) {
-                       acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
-               }
-               protocol |= ACPI_EC_SMB_PRTCL_BYTE_DATA;
-               break;
-
-       case I2C_SMBUS_WORD_DATA:
-               acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-               if (read_write == I2C_SMBUS_WRITE) {
-                       acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
-                       acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1,
-                                         data->word >> 8);
-               }
-               protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA | pec;
-               break;
-
-       case I2C_SMBUS_BLOCK_DATA:
-               acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-               if (read_write == I2C_SMBUS_WRITE) {
-                       len = min_t(u8, data->block[0], 32);
-                       acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
-                       for (i = 0; i < len; i++)
-                               acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
-                                                 data->block[i + 1]);
-               }
-               protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA | pec;
-               break;
-
-       case I2C_SMBUS_I2C_BLOCK_DATA:
-               len = min_t(u8, data->block[0], 32);
-               acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-               acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
-               if (read_write == I2C_SMBUS_WRITE) {
-                       for (i = 0; i < len; i++) {
-                               acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
-                                                 data->block[i + 1]);
-                       }
-               }
-               protocol |= ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA;
-               break;
-
-       case I2C_SMBUS_PROC_CALL:
-               acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-               acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
-               acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, data->word >> 8);
-               protocol = ACPI_EC_SMB_PRTCL_PROC_CALL | pec;
-               read_write = I2C_SMBUS_READ;
-               break;
-
-       case I2C_SMBUS_BLOCK_PROC_CALL:
-               protocol |= pec;
-               len = min_t(u8, data->block[0], 31);
-               acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-               acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
-               for (i = 0; i < len; i++)
-                       acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
-                                         data->block[i + 1]);
-               protocol = ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL | pec;
-               read_write = I2C_SMBUS_READ;
-               break;
-
-       default:
-               ACPI_DEBUG_PRINT((ACPI_DB_WARN, "EC SMBus adapter: "
-                                 "Unsupported transaction %d\n", size));
-               return (-1);
-       }
-
-       acpi_ec_smb_write(smbus, ACPI_EC_SMB_ADDR, addr << 1);
-       acpi_ec_smb_write(smbus, ACPI_EC_SMB_PRTCL, protocol);
-
-       acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
-
-       if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
-               xudelay(500);
-               acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
-       }
-       if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
-               xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
-               acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
-       }
-       if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
-           || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
-               return (-1);
-       }
-
-       if (read_write == I2C_SMBUS_WRITE) {
-               return (0);
-       }
-
-       switch (size) {
-
-       case I2C_SMBUS_BYTE:
-       case I2C_SMBUS_BYTE_DATA:
-               acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, &data->byte);
-               break;
-
-       case I2C_SMBUS_WORD_DATA:
-       case I2C_SMBUS_PROC_CALL:
-               acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, temp + 0);
-               acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + 1, temp + 1);
-               data->word = (temp[1] << 8) | temp[0];
-               break;
-
-       case I2C_SMBUS_BLOCK_DATA:
-       case I2C_SMBUS_BLOCK_PROC_CALL:
-               len = 0;
-               acpi_ec_smb_read(smbus, ACPI_EC_SMB_BCNT, &len);
-               len = min_t(u8, len, 32);
-       case I2C_SMBUS_I2C_BLOCK_DATA:
-               for (i = 0; i < len; i++)
-                       acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + i,
-                                        data->block + i + 1);
-               data->block[0] = len;
-               break;
-       }
-
-       return (0);
-}
-
-static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)
-{
-
-       return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-               I2C_FUNC_SMBUS_BLOCK_DATA |
-               I2C_FUNC_SMBUS_PROC_CALL |
-               I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
-               I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);
-}
-
-static const struct i2c_algorithm acpi_ec_smbus_algorithm = {
-       .smbus_xfer = acpi_ec_smb_access,
-       .functionality = acpi_ec_smb_func,
-};
-
-static int acpi_ec_hc_add(struct acpi_device *device)
-{
-       int status;
-       unsigned long val;
-       struct acpi_ec_hc *ec_hc;
-       struct acpi_ec_smbus *smbus;
-
-       if (!device) {
-               return -EINVAL;
-       }
-
-       ec_hc = kzalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
-       if (!ec_hc) {
-               return -ENOMEM;
-       }
-
-       smbus = kzalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
-       if (!smbus) {
-               kfree(ec_hc);
-               return -ENOMEM;
-       }
-
-       ec_hc->handle = device->handle;
-       strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);
-       strcpy(acpi_device_class(device), ACPI_EC_HC_CLASS);
-       acpi_driver_data(device) = ec_hc;
-
-       status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val);
-       if (ACPI_FAILURE(status)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n"));
-               kfree(ec_hc);
-               kfree(smbus);
-               return -EIO;
-       }
-
-       smbus->ec = acpi_driver_data(device->parent);
-       smbus->base = (val & 0xff00ull) >> 8;
-       smbus->alert = val & 0xffull;
-
-       smbus->adapter.owner = THIS_MODULE;
-       smbus->adapter.algo = &acpi_ec_smbus_algorithm;
-       smbus->adapter.algo_data = smbus;
-       smbus->adapter.dev.parent = &device->dev;
-
-       if (i2c_add_adapter(&smbus->adapter)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-                                 "EC SMBus adapter: Failed to register adapter\n"));
-               kfree(smbus);
-               kfree(ec_hc);
-               return -EIO;
-       }
-
-       ec_hc->smbus = smbus;
-
-       printk(KERN_INFO PREFIX "%s [%s]\n",
-              acpi_device_name(device), acpi_device_bid(device));
-
-       return AE_OK;
-}
-
-static int acpi_ec_hc_remove(struct acpi_device *device, int type)
-{
-       struct acpi_ec_hc *ec_hc;
-
-       if (!device) {
-               return -EINVAL;
-       }
-       ec_hc = acpi_driver_data(device);
-
-       i2c_del_adapter(&ec_hc->smbus->adapter);
-       kfree(ec_hc->smbus);
-       kfree(ec_hc);
-
-       return AE_OK;
-}
-
-static int __init acpi_ec_hc_init(void)
-{
-       int result;
-
-       result = acpi_bus_register_driver(&acpi_ec_hc_driver);
-       if (result < 0) {
-               return -ENODEV;
-       }
-       return 0;
-}
-
-static void __exit acpi_ec_hc_exit(void)
-{
-       acpi_bus_unregister_driver(&acpi_ec_hc_driver);
-}
-
-struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)
-{
-       return acpi_driver_data(device->parent);
-}
-
-EXPORT_SYMBOL(acpi_get_ec_hc);
-
-module_init(acpi_ec_hc_init);
-module_exit(acpi_ec_hc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ducrot Bruno");
-MODULE_DESCRIPTION("ACPI EC SMBus driver");
diff --git a/drivers/acpi/i2c_ec.h b/drivers/acpi/i2c_ec.h
deleted file mode 100644 (file)
index 7c53fb7..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $)
- *
- * Copyright (c) 2002, 2005 Ducrot Bruno
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2.
- */
-
-struct acpi_ec_smbus {
-       struct i2c_adapter adapter;
-       union acpi_ec *ec;
-       int base;
-       int alert;
-};
-
-struct acpi_ec_hc {
-       acpi_handle handle;
-       struct acpi_ec_smbus *smbus;
-};
-
-struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device);
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
deleted file mode 100644 (file)
index dc10966..0000000
+++ /dev/null
@@ -1,2798 +0,0 @@
-/*
- *  ibm_acpi.c - IBM ThinkPad ACPI Extras
- *
- *
- *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
- *  Copyright (C) 2006 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#define IBM_VERSION "0.13"
-
-/*
- *  Changelog:
- *
- *  2006-11-22 0.13    new maintainer
- *                     changelog now lives in git commit history, and will
- *                     not be updated further in-file.
- *  
- *  2005-08-17  0.12   fix compilation on 2.6.13-rc kernels
- *  2005-03-17 0.11    support for 600e, 770x
- *                         thanks to Jamie Lentin <lentinj@dial.pipex.com>
- *                     support for 770e, G41
- *                     G40 and G41 don't have a thinklight
- *                     temperatures no longer experimental
- *                     experimental brightness control
- *                     experimental volume control
- *                     experimental fan enable/disable
- *  2005-01-16 0.10    fix module loading on R30, R31 
- *  2005-01-16 0.9     support for 570, R30, R31
- *                     ultrabay support on A22p, A3x
- *                     limit arg for cmos, led, beep, drop experimental status
- *                     more capable led control on A21e, A22p, T20-22, X20
- *                     experimental temperatures and fan speed
- *                     experimental embedded controller register dump
- *                     mark more functions as __init, drop incorrect __exit
- *                     use MODULE_VERSION
- *                         thanks to Henrik Brix Andersen <brix@gentoo.org>
- *                     fix parameter passing on module loading
- *                         thanks to Rusty Russell <rusty@rustcorp.com.au>
- *                         thanks to Jim Radford <radford@blackbean.org>
- *  2004-11-08 0.8     fix init error case, don't return from a macro
- *                         thanks to Chris Wright <chrisw@osdl.org>
- *  2004-10-23 0.7     fix module loading on A21e, A22p, T20, T21, X20
- *                     fix led control on A21e
- *  2004-10-19 0.6     use acpi_bus_register_driver() to claim HKEY device
- *  2004-10-18 0.5     thinklight support on A21e, G40, R32, T20, T21, X20
- *                     proc file format changed
- *                     video_switch command
- *                     experimental cmos control
- *                     experimental led control
- *                     experimental acpi sounds
- *  2004-09-16 0.4     support for module parameters
- *                     hotkey mask can be prefixed by 0x
- *                     video output switching
- *                     video expansion control
- *                     ultrabay eject support
- *                     removed lcd brightness/on/off control, didn't work
- *  2004-08-17 0.3     support for R40
- *                     lcd off, brightness control
- *                     thinklight on/off
- *  2004-08-14 0.2     support for T series, X20
- *                     bluetooth enable/disable
- *                     hotkey events disabled by default
- *                     removed fan control, currently useless
- *  2004-08-09 0.1     initial release, support for X series
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/string.h>
-
-#include <linux/proc_fs.h>
-#include <linux/backlight.h>
-#include <linux/fb.h>
-#include <asm/uaccess.h>
-
-#include <linux/dmi.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-
-#include <acpi/acpi_drivers.h>
-#include <acpi/acnamesp.h>
-
-#define IBM_NAME "ibm"
-#define IBM_DESC "IBM ThinkPad ACPI Extras"
-#define IBM_FILE "ibm_acpi"
-#define IBM_URL "http://ibm-acpi.sf.net/"
-
-MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
-MODULE_DESCRIPTION(IBM_DESC);
-MODULE_VERSION(IBM_VERSION);
-MODULE_LICENSE("GPL");
-
-#define IBM_DIR IBM_NAME
-
-#define IBM_LOG IBM_FILE ": "
-#define IBM_ERR           KERN_ERR    IBM_LOG
-#define IBM_NOTICE KERN_NOTICE IBM_LOG
-#define IBM_INFO   KERN_INFO   IBM_LOG
-#define IBM_DEBUG  KERN_DEBUG  IBM_LOG
-
-#define IBM_MAX_ACPI_ARGS 3
-
-#define __unused __attribute__ ((unused))
-
-static int experimental;
-module_param(experimental, int, 0);
-
-static acpi_handle root_handle = NULL;
-
-#define IBM_HANDLE(object, parent, paths...)                   \
-       static acpi_handle  object##_handle;                    \
-       static acpi_handle *object##_parent = &parent##_handle; \
-       static char        *object##_path;                      \
-       static char        *object##_paths[] = { paths }
-
-IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",     /* 240, 240x */
-          "\\_SB.PCI.ISA.EC",  /* 570 */
-          "\\_SB.PCI0.ISA0.EC0",       /* 600e/x, 770e, 770x */
-          "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
-          "\\_SB.PCI0.AD4S.EC0",       /* i1400, R30 */
-          "\\_SB.PCI0.ICH3.EC0",       /* R31 */
-          "\\_SB.PCI0.LPC.EC", /* all others */
-    );
-
-IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",     /* 570 */
-          "\\_SB.PCI0.AGP0.VID0",      /* 600e/x, 770x */
-          "\\_SB.PCI0.VID0",   /* 770e */
-          "\\_SB.PCI0.VID",    /* A21e, G4x, R50e, X30, X40 */
-          "\\_SB.PCI0.AGP.VID",        /* all others */
-    );                         /* R30, R31 */
-
-IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
-
-IBM_HANDLE(cmos, root, "\\UCMS",       /* R50, R50e, R50p, R51, T4x, X31, X40 */
-          "\\CMOS",            /* A3x, G4x, R32, T23, T30, X22-24, X30 */
-          "\\CMS",             /* R40, R40e */
-    );                         /* all others */
-#ifdef CONFIG_ACPI_IBM_DOCK
-IBM_HANDLE(dock, root, "\\_SB.GDCK",   /* X30, X31, X40 */
-          "\\_SB.PCI0.DOCK",   /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
-          "\\_SB.PCI0.PCI1.DOCK",      /* all others */
-          "\\_SB.PCI.ISA.SLCE",        /* 570 */
-    );                         /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
-IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST",       /* 570 */
-          "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
-          "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ 
-          "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
-    );                         /* A21e, R30, R31 */
-
-IBM_HANDLE(bay_ej, bay, "_EJ3",        /* 600e/x, A2xm/p, A3x */
-          "_EJ0",              /* all others */
-    );                         /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
-
-IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV",    /* A3x, R32 */
-          "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
-    );                         /* all others */
-
-IBM_HANDLE(bay2_ej, bay2, "_EJ3",      /* 600e/x, 770e, A3x */
-          "_EJ0",              /* 770x */
-    );                         /* all others */
-#endif /* CONFIG_ACPI_IBM_BAY */
-
-/* don't list other alternatives as we install a notify handler on the 570 */
-IBM_HANDLE(pci, root, "\\_SB.PCI");    /* 570 */
-
-IBM_HANDLE(hkey, ec, "\\_SB.HKEY",     /* 600e/x, 770e, 770x */
-          "^HKEY",             /* R30, R31 */
-          "HKEY",              /* all others */
-    );                         /* 570 */
-
-IBM_HANDLE(lght, root, "\\LGHT");      /* A21e, A2xm/p, T20-22, X20-21 */
-IBM_HANDLE(ledb, ec, "LEDB");  /* G4x */
-
-IBM_HANDLE(led, ec, "SLED",    /* 570 */
-          "SYSL",              /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
-          "LED",               /* all others */
-    );                         /* R30, R31 */
-
-IBM_HANDLE(beep, ec, "BEEP");  /* all except R30, R31 */
-IBM_HANDLE(ecrd, ec, "ECRD");  /* 570 */
-IBM_HANDLE(ecwr, ec, "ECWR");  /* 570 */
-IBM_HANDLE(fans, ec, "FANS");  /* X31, X40, X41 */
-
-IBM_HANDLE(gfan, ec, "GFAN",   /* 570 */
-          "\\FSPD",            /* 600e/x, 770e, 770x */
-    );                         /* all others */
-
-IBM_HANDLE(sfan, ec, "SFAN",   /* 570 */
-          "JFNS",              /* 770x-JL */
-    );                         /* all others */
-
-#define IBM_HKEY_HID   "IBM0068"
-#define IBM_PCI_HID    "PNP0A03"
-
-enum thermal_access_mode {
-       IBMACPI_THERMAL_NONE = 0,       /* No thermal support */
-       IBMACPI_THERMAL_ACPI_TMP07,     /* Use ACPI TMP0-7 */
-       IBMACPI_THERMAL_ACPI_UPDT,      /* Use ACPI TMP0-7 with UPDT */
-       IBMACPI_THERMAL_TPEC_8,         /* Use ACPI EC regs, 8 sensors */
-       IBMACPI_THERMAL_TPEC_16,        /* Use ACPI EC regs, 16 sensors */
-};
-
-#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
-struct ibm_thermal_sensors_struct {
-       s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
-};
-
-/*
- * FAN ACCESS MODES
- *
- * IBMACPI_FAN_RD_ACPI_GFAN:
- *     ACPI GFAN method: returns fan level
- *
- *     see IBMACPI_FAN_WR_ACPI_SFAN
- *     EC 0x2f not available if GFAN exists
- *
- * IBMACPI_FAN_WR_ACPI_SFAN:
- *     ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
- *
- *     EC 0x2f might be available *for reading*, but never for writing.
- *
- * IBMACPI_FAN_WR_TPEC:
- *     ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
- *     on almost all ThinkPads
- *
- *     Fan speed changes of any sort (including those caused by the
- *     disengaged mode) are usually done slowly by the firmware as the
- *     maximum ammount of fan duty cycle change per second seems to be
- *     limited.
- *
- *     Reading is not available if GFAN exists.
- *     Writing is not available if SFAN exists.
- *
- *     Bits
- *      7      automatic mode engaged;
- *             (default operation mode of the ThinkPad)
- *             fan level is ignored in this mode.
- *      6      disengage mode (takes precedence over bit 7);
- *             not available on all thinkpads.  May disable
- *             the tachometer, and speeds up fan to 100% duty-cycle,
- *             which speeds it up far above the standard RPM
- *             levels.  It is not impossible that it could cause
- *             hardware damage.
- *     5-3     unused in some models.  Extra bits for fan level
- *             in others, but still useless as all values above
- *             7 map to the same speed as level 7 in these models.
- *     2-0     fan level (0..7 usually)
- *                     0x00 = stop
- *                     0x07 = max (set when temperatures critical)
- *             Some ThinkPads may have other levels, see
- *             IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
- *
- *     FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
- *     boot. Apparently the EC does not intialize it, so unless ACPI DSDT
- *     does so, its initial value is meaningless (0x07).
- *
- *     For firmware bugs, refer to:
- *     http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
- *
- *     ----
- *
- *     ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
- *     Main fan tachometer reading (in RPM)
- *
- *     This register is present on all ThinkPads with a new-style EC, and
- *     it is known not to be present on the A21m/e, and T22, as there is
- *     something else in offset 0x84 according to the ACPI DSDT.  Other
- *     ThinkPads from this same time period (and earlier) probably lack the
- *     tachometer as well.
- *
- *     Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
- *     was never fixed by IBM to report the EC firmware version string
- *     probably support the tachometer (like the early X models), so
- *     detecting it is quite hard.  We need more data to know for sure.
- *
- *     FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
- *     might result.
- *
- *     FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
- *     register is not invalidated in ThinkPads that disable tachometer
- *     readings.  Thus, the tachometer readings go stale.
- *
- *     For firmware bugs, refer to:
- *     http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
- *
- * IBMACPI_FAN_WR_ACPI_FANS:
- *     ThinkPad X31, X40, X41.  Not available in the X60.
- *
- *     FANS ACPI handle: takes three arguments: low speed, medium speed,
- *     high speed.  ACPI DSDT seems to map these three speeds to levels
- *     as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
- *     (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
- *
- *     The speeds are stored on handles
- *     (FANA:FAN9), (FANC:FANB), (FANE:FAND).
- *
- *     There are three default speed sets, acessible as handles:
- *     FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
- *
- *     ACPI DSDT switches which set is in use depending on various
- *     factors.
- *
- *     IBMACPI_FAN_WR_TPEC is also available and should be used to
- *     command the fan.  The X31/X40/X41 seems to have 8 fan levels,
- *     but the ACPI tables just mention level 7.
- */
-
-enum fan_status_access_mode {
-       IBMACPI_FAN_NONE = 0,           /* No fan status or control */
-       IBMACPI_FAN_RD_ACPI_GFAN,       /* Use ACPI GFAN */
-       IBMACPI_FAN_RD_TPEC,            /* Use ACPI EC regs 0x2f, 0x84-0x85 */
-};
-
-enum fan_control_access_mode {
-       IBMACPI_FAN_WR_NONE = 0,        /* No fan control */
-       IBMACPI_FAN_WR_ACPI_SFAN,       /* Use ACPI SFAN */
-       IBMACPI_FAN_WR_TPEC,            /* Use ACPI EC reg 0x2f */
-       IBMACPI_FAN_WR_ACPI_FANS,       /* Use ACPI FANS and EC reg 0x2f */
-};
-
-enum fan_control_commands {
-       IBMACPI_FAN_CMD_SPEED   = 0x0001,       /* speed command */
-       IBMACPI_FAN_CMD_LEVEL   = 0x0002,       /* level command  */
-       IBMACPI_FAN_CMD_ENABLE  = 0x0004,       /* enable/disable cmd,
-                                                * and also watchdog cmd */
-};
-
-enum {                                 /* Fan control constants */
-       fan_status_offset = 0x2f,       /* EC register 0x2f */
-       fan_rpm_offset = 0x84,          /* EC register 0x84: LSB, 0x85 MSB (RPM)
-                                        * 0x84 must be read before 0x85 */
-
-       IBMACPI_FAN_EC_DISENGAGED       = 0x40, /* EC mode: tachometer
-                                                * disengaged */
-       IBMACPI_FAN_EC_AUTO             = 0x80, /* EC mode: auto fan
-                                                * control */
-};
-
-static char *ibm_thinkpad_ec_found = NULL;
-
-struct ibm_struct {
-       char *name;
-       char param[32];
-
-       char *hid;
-       struct acpi_driver *driver;
-
-       int (*init) (void);
-       int (*read) (char *);
-       int (*write) (char *);
-       void (*exit) (void);
-
-       void (*notify) (struct ibm_struct *, u32);
-       acpi_handle *handle;
-       int type;
-       struct acpi_device *device;
-
-       int driver_registered;
-       int proc_created;
-       int init_called;
-       int notify_installed;
-
-       int experimental;
-};
-
-static struct proc_dir_entry *proc_dir = NULL;
-
-static struct backlight_device *ibm_backlight_device = NULL;
-
-#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
-#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
-#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
-
-static int acpi_evalf(acpi_handle handle,
-                     void *res, char *method, char *fmt, ...)
-{
-       char *fmt0 = fmt;
-       struct acpi_object_list params;
-       union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
-       struct acpi_buffer result, *resultp;
-       union acpi_object out_obj;
-       acpi_status status;
-       va_list ap;
-       char res_type;
-       int success;
-       int quiet;
-
-       if (!*fmt) {
-               printk(IBM_ERR "acpi_evalf() called with empty format\n");
-               return 0;
-       }
-
-       if (*fmt == 'q') {
-               quiet = 1;
-               fmt++;
-       } else
-               quiet = 0;
-
-       res_type = *(fmt++);
-
-       params.count = 0;
-       params.pointer = &in_objs[0];
-
-       va_start(ap, fmt);
-       while (*fmt) {
-               char c = *(fmt++);
-               switch (c) {
-               case 'd':       /* int */
-                       in_objs[params.count].integer.value = va_arg(ap, int);
-                       in_objs[params.count++].type = ACPI_TYPE_INTEGER;
-                       break;
-                       /* add more types as needed */
-               default:
-                       printk(IBM_ERR "acpi_evalf() called "
-                              "with invalid format character '%c'\n", c);
-                       return 0;
-               }
-       }
-       va_end(ap);
-
-       if (res_type != 'v') {
-               result.length = sizeof(out_obj);
-               result.pointer = &out_obj;
-               resultp = &result;
-       } else
-               resultp = NULL;
-
-       status = acpi_evaluate_object(handle, method, &params, resultp);
-
-       switch (res_type) {
-       case 'd':               /* int */
-               if (res)
-                       *(int *)res = out_obj.integer.value;
-               success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
-               break;
-       case 'v':               /* void */
-               success = status == AE_OK;
-               break;
-               /* add more types as needed */
-       default:
-               printk(IBM_ERR "acpi_evalf() called "
-                      "with invalid format character '%c'\n", res_type);
-               return 0;
-       }
-
-       if (!success && !quiet)
-               printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
-                      method, fmt0, status);
-
-       return success;
-}
-
-static void __unused acpi_print_int(acpi_handle handle, char *method)
-{
-       int i;
-
-       if (acpi_evalf(handle, &i, method, "d"))
-               printk(IBM_INFO "%s = 0x%x\n", method, i);
-       else
-               printk(IBM_ERR "error calling %s\n", method);
-}
-
-static char *next_cmd(char **cmds)
-{
-       char *start = *cmds;
-       char *end;
-
-       while ((end = strchr(start, ',')) && end == start)
-               start = end + 1;
-
-       if (!end)
-               return NULL;
-
-       *end = 0;
-       *cmds = end + 1;
-       return start;
-}
-
-static int ibm_acpi_driver_init(void)
-{
-       printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
-       printk(IBM_INFO "%s\n", IBM_URL);
-
-       if (ibm_thinkpad_ec_found)
-               printk(IBM_INFO "ThinkPad EC firmware %s\n",
-                      ibm_thinkpad_ec_found);
-
-       return 0;
-}
-
-static int driver_read(char *p)
-{
-       int len = 0;
-
-       len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
-       len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
-
-       return len;
-}
-
-static int hotkey_supported;
-static int hotkey_mask_supported;
-static int hotkey_orig_status;
-static int hotkey_orig_mask;
-
-static int hotkey_get(int *status, int *mask)
-{
-       if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
-               return 0;
-
-       if (hotkey_mask_supported)
-               if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
-                       return 0;
-
-       return 1;
-}
-
-static int hotkey_set(int status, int mask)
-{
-       int i;
-
-       if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
-               return 0;
-
-       if (hotkey_mask_supported)
-               for (i = 0; i < 32; i++) {
-                       int bit = ((1 << i) & mask) != 0;
-                       if (!acpi_evalf(hkey_handle,
-                                       NULL, "MHKM", "vdd", i + 1, bit))
-                               return 0;
-               }
-
-       return 1;
-}
-
-static int hotkey_init(void)
-{
-       /* hotkey not supported on 570 */
-       hotkey_supported = hkey_handle != NULL;
-
-       if (hotkey_supported) {
-               /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
-                  A30, R30, R31, T20-22, X20-21, X22-24 */
-               hotkey_mask_supported =
-                   acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
-
-               if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask))
-                       return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int hotkey_read(char *p)
-{
-       int status, mask;
-       int len = 0;
-
-       if (!hotkey_supported) {
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-               return len;
-       }
-
-       if (!hotkey_get(&status, &mask))
-               return -EIO;
-
-       len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
-       if (hotkey_mask_supported) {
-               len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
-               len += sprintf(p + len,
-                              "commands:\tenable, disable, reset, <mask>\n");
-       } else {
-               len += sprintf(p + len, "mask:\t\tnot supported\n");
-               len += sprintf(p + len, "commands:\tenable, disable, reset\n");
-       }
-
-       return len;
-}
-
-static int hotkey_write(char *buf)
-{
-       int status, mask;
-       char *cmd;
-       int do_cmd = 0;
-
-       if (!hotkey_supported)
-               return -ENODEV;
-
-       if (!hotkey_get(&status, &mask))
-               return -EIO;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (strlencmp(cmd, "enable") == 0) {
-                       status = 1;
-               } else if (strlencmp(cmd, "disable") == 0) {
-                       status = 0;
-               } else if (strlencmp(cmd, "reset") == 0) {
-                       status = hotkey_orig_status;
-                       mask = hotkey_orig_mask;
-               } else if (sscanf(cmd, "0x%x", &mask) == 1) {
-                       /* mask set */
-               } else if (sscanf(cmd, "%x", &mask) == 1) {
-                       /* mask set */
-               } else
-                       return -EINVAL;
-               do_cmd = 1;
-       }
-
-       if (do_cmd && !hotkey_set(status, mask))
-               return -EIO;
-
-       return 0;
-}
-
-static void hotkey_exit(void)
-{
-       if (hotkey_supported)
-               hotkey_set(hotkey_orig_status, hotkey_orig_mask);
-}
-
-static void hotkey_notify(struct ibm_struct *ibm, u32 event)
-{
-       int hkey;
-
-       if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
-               acpi_bus_generate_event(ibm->device, event, hkey);
-       else {
-               printk(IBM_ERR "unknown hotkey event %d\n", event);
-               acpi_bus_generate_event(ibm->device, event, 0);
-       }
-}
-
-static int bluetooth_supported;
-
-static int bluetooth_init(void)
-{
-       /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
-          G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
-       bluetooth_supported = hkey_handle &&
-           acpi_evalf(hkey_handle, NULL, "GBDC", "qv");
-
-       return 0;
-}
-
-static int bluetooth_status(void)
-{
-       int status;
-
-       if (!bluetooth_supported ||
-           !acpi_evalf(hkey_handle, &status, "GBDC", "d"))
-               status = 0;
-
-       return status;
-}
-
-static int bluetooth_read(char *p)
-{
-       int len = 0;
-       int status = bluetooth_status();
-
-       if (!bluetooth_supported)
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-       else if (!(status & 1))
-               len += sprintf(p + len, "status:\t\tnot installed\n");
-       else {
-               len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
-               len += sprintf(p + len, "commands:\tenable, disable\n");
-       }
-
-       return len;
-}
-
-static int bluetooth_write(char *buf)
-{
-       int status = bluetooth_status();
-       char *cmd;
-       int do_cmd = 0;
-
-       if (!bluetooth_supported)
-               return -ENODEV;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (strlencmp(cmd, "enable") == 0) {
-                       status |= 2;
-               } else if (strlencmp(cmd, "disable") == 0) {
-                       status &= ~2;
-               } else
-                       return -EINVAL;
-               do_cmd = 1;
-       }
-
-       if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
-               return -EIO;
-
-       return 0;
-}
-
-static int wan_supported;
-
-static int wan_init(void)
-{
-       wan_supported = hkey_handle &&
-           acpi_evalf(hkey_handle, NULL, "GWAN", "qv");
-
-       return 0;
-}
-
-static int wan_status(void)
-{
-       int status;
-
-       if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
-               status = 0;
-
-       return status;
-}
-
-static int wan_read(char *p)
-{
-       int len = 0;
-       int status = wan_status();
-
-       if (!wan_supported)
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-       else if (!(status & 1))
-               len += sprintf(p + len, "status:\t\tnot installed\n");
-       else {
-               len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
-               len += sprintf(p + len, "commands:\tenable, disable\n");
-       }
-
-       return len;
-}
-
-static int wan_write(char *buf)
-{
-       int status = wan_status();
-       char *cmd;
-       int do_cmd = 0;
-
-       if (!wan_supported)
-               return -ENODEV;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (strlencmp(cmd, "enable") == 0) {
-                       status |= 2;
-               } else if (strlencmp(cmd, "disable") == 0) {
-                       status &= ~2;
-               } else
-                       return -EINVAL;
-               do_cmd = 1;
-       }
-
-       if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
-               return -EIO;
-
-       return 0;
-}
-
-enum video_access_mode {
-       IBMACPI_VIDEO_NONE = 0,
-       IBMACPI_VIDEO_570,      /* 570 */
-       IBMACPI_VIDEO_770,      /* 600e/x, 770e, 770x */
-       IBMACPI_VIDEO_NEW,      /* all others */
-};
-
-static enum video_access_mode video_supported;
-static int video_orig_autosw;
-
-static int video_init(void)
-{
-       int ivga;
-
-       if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
-               /* G41, assume IVGA doesn't change */
-               vid_handle = vid2_handle;
-
-       if (!vid_handle)
-               /* video switching not supported on R30, R31 */
-               video_supported = IBMACPI_VIDEO_NONE;
-       else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
-               /* 570 */
-               video_supported = IBMACPI_VIDEO_570;
-       else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
-               /* 600e/x, 770e, 770x */
-               video_supported = IBMACPI_VIDEO_770;
-       else
-               /* all others */
-               video_supported = IBMACPI_VIDEO_NEW;
-
-       return 0;
-}
-
-static int video_status(void)
-{
-       int status = 0;
-       int i;
-
-       if (video_supported == IBMACPI_VIDEO_570) {
-               if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
-                       status = i & 3;
-       } else if (video_supported == IBMACPI_VIDEO_770) {
-               if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
-                       status |= 0x01 * i;
-               if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
-                       status |= 0x02 * i;
-       } else if (video_supported == IBMACPI_VIDEO_NEW) {
-               acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
-               if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
-                       status |= 0x02 * i;
-
-               acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0);
-               if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
-                       status |= 0x01 * i;
-               if (acpi_evalf(NULL, &i, "\\VCDD", "d"))
-                       status |= 0x08 * i;
-       }
-
-       return status;
-}
-
-static int video_autosw(void)
-{
-       int autosw = 0;
-
-       if (video_supported == IBMACPI_VIDEO_570)
-               acpi_evalf(vid_handle, &autosw, "SWIT", "d");
-       else if (video_supported == IBMACPI_VIDEO_770 ||
-                video_supported == IBMACPI_VIDEO_NEW)
-               acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
-
-       return autosw & 1;
-}
-
-static int video_read(char *p)
-{
-       int status = video_status();
-       int autosw = video_autosw();
-       int len = 0;
-
-       if (!video_supported) {
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-               return len;
-       }
-
-       len += sprintf(p + len, "status:\t\tsupported\n");
-       len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
-       len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
-       if (video_supported == IBMACPI_VIDEO_NEW)
-               len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
-       len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
-       len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
-       len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
-       if (video_supported == IBMACPI_VIDEO_NEW)
-               len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
-       len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
-       len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
-
-       return len;
-}
-
-static int video_switch(void)
-{
-       int autosw = video_autosw();
-       int ret;
-
-       if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
-               return -EIO;
-       ret = video_supported == IBMACPI_VIDEO_570 ?
-           acpi_evalf(ec_handle, NULL, "_Q16", "v") :
-           acpi_evalf(vid_handle, NULL, "VSWT", "v");
-       acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
-
-       return ret;
-}
-
-static int video_expand(void)
-{
-       if (video_supported == IBMACPI_VIDEO_570)
-               return acpi_evalf(ec_handle, NULL, "_Q17", "v");
-       else if (video_supported == IBMACPI_VIDEO_770)
-               return acpi_evalf(vid_handle, NULL, "VEXP", "v");
-       else
-               return acpi_evalf(NULL, NULL, "\\VEXP", "v");
-}
-
-static int video_switch2(int status)
-{
-       int ret;
-
-       if (video_supported == IBMACPI_VIDEO_570) {
-               ret = acpi_evalf(NULL, NULL,
-                                "\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
-       } else if (video_supported == IBMACPI_VIDEO_770) {
-               int autosw = video_autosw();
-               if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
-                       return -EIO;
-
-               ret = acpi_evalf(vid_handle, NULL,
-                                "ASWT", "vdd", status * 0x100, 0);
-
-               acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
-       } else {
-               ret = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
-                   acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
-       }
-
-       return ret;
-}
-
-static int video_write(char *buf)
-{
-       char *cmd;
-       int enable, disable, status;
-
-       if (!video_supported)
-               return -ENODEV;
-
-       enable = disable = 0;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (strlencmp(cmd, "lcd_enable") == 0) {
-                       enable |= 0x01;
-               } else if (strlencmp(cmd, "lcd_disable") == 0) {
-                       disable |= 0x01;
-               } else if (strlencmp(cmd, "crt_enable") == 0) {
-                       enable |= 0x02;
-               } else if (strlencmp(cmd, "crt_disable") == 0) {
-                       disable |= 0x02;
-               } else if (video_supported == IBMACPI_VIDEO_NEW &&
-                          strlencmp(cmd, "dvi_enable") == 0) {
-                       enable |= 0x08;
-               } else if (video_supported == IBMACPI_VIDEO_NEW &&
-                          strlencmp(cmd, "dvi_disable") == 0) {
-                       disable |= 0x08;
-               } else if (strlencmp(cmd, "auto_enable") == 0) {
-                       if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
-                               return -EIO;
-               } else if (strlencmp(cmd, "auto_disable") == 0) {
-                       if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0))
-                               return -EIO;
-               } else if (strlencmp(cmd, "video_switch") == 0) {
-                       if (!video_switch())
-                               return -EIO;
-               } else if (strlencmp(cmd, "expand_toggle") == 0) {
-                       if (!video_expand())
-                               return -EIO;
-               } else
-                       return -EINVAL;
-       }
-
-       if (enable || disable) {
-               status = (video_status() & 0x0f & ~disable) | enable;
-               if (!video_switch2(status))
-                       return -EIO;
-       }
-
-       return 0;
-}
-
-static void video_exit(void)
-{
-       acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw);
-}
-
-static int light_supported;
-static int light_status_supported;
-
-static int light_init(void)
-{
-       /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
-       light_supported = (cmos_handle || lght_handle) && !ledb_handle;
-
-       if (light_supported)
-               /* light status not supported on
-                  570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
-               light_status_supported = acpi_evalf(ec_handle, NULL,
-                                                   "KBLT", "qv");
-
-       return 0;
-}
-
-static int light_read(char *p)
-{
-       int len = 0;
-       int status = 0;
-
-       if (!light_supported) {
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-       } else if (!light_status_supported) {
-               len += sprintf(p + len, "status:\t\tunknown\n");
-               len += sprintf(p + len, "commands:\ton, off\n");
-       } else {
-               if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
-                       return -EIO;
-               len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
-               len += sprintf(p + len, "commands:\ton, off\n");
-       }
-
-       return len;
-}
-
-static int light_write(char *buf)
-{
-       int cmos_cmd, lght_cmd;
-       char *cmd;
-       int success;
-
-       if (!light_supported)
-               return -ENODEV;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (strlencmp(cmd, "on") == 0) {
-                       cmos_cmd = 0x0c;
-                       lght_cmd = 1;
-               } else if (strlencmp(cmd, "off") == 0) {
-                       cmos_cmd = 0x0d;
-                       lght_cmd = 0;
-               } else
-                       return -EINVAL;
-
-               success = cmos_handle ?
-                   acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
-                   acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
-               if (!success)
-                       return -EIO;
-       }
-
-       return 0;
-}
-
-#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY)
-static int _sta(acpi_handle handle)
-{
-       int status;
-
-       if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
-               status = 0;
-
-       return status;
-}
-#endif
-
-#ifdef CONFIG_ACPI_IBM_DOCK
-#define dock_docked() (_sta(dock_handle) & 1)
-
-static int dock_read(char *p)
-{
-       int len = 0;
-       int docked = dock_docked();
-
-       if (!dock_handle)
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-       else if (!docked)
-               len += sprintf(p + len, "status:\t\tundocked\n");
-       else {
-               len += sprintf(p + len, "status:\t\tdocked\n");
-               len += sprintf(p + len, "commands:\tdock, undock\n");
-       }
-
-       return len;
-}
-
-static int dock_write(char *buf)
-{
-       char *cmd;
-
-       if (!dock_docked())
-               return -ENODEV;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (strlencmp(cmd, "undock") == 0) {
-                       if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
-                           !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
-                               return -EIO;
-               } else if (strlencmp(cmd, "dock") == 0) {
-                       if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
-                               return -EIO;
-               } else
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void dock_notify(struct ibm_struct *ibm, u32 event)
-{
-       int docked = dock_docked();
-       int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID);
-
-       if (event == 1 && !pci) /* 570 */
-               acpi_bus_generate_event(ibm->device, event, 1); /* button */
-       else if (event == 1 && pci)     /* 570 */
-               acpi_bus_generate_event(ibm->device, event, 3); /* dock */
-       else if (event == 3 && docked)
-               acpi_bus_generate_event(ibm->device, event, 1); /* button */
-       else if (event == 3 && !docked)
-               acpi_bus_generate_event(ibm->device, event, 2); /* undock */
-       else if (event == 0 && docked)
-               acpi_bus_generate_event(ibm->device, event, 3); /* dock */
-       else {
-               printk(IBM_ERR "unknown dock event %d, status %d\n",
-                      event, _sta(dock_handle));
-               acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
-       }
-}
-#endif
-
-#ifdef CONFIG_ACPI_IBM_BAY
-static int bay_status_supported;
-static int bay_status2_supported;
-static int bay_eject_supported;
-static int bay_eject2_supported;
-
-static int bay_init(void)
-{
-       bay_status_supported = bay_handle &&
-           acpi_evalf(bay_handle, NULL, "_STA", "qv");
-       bay_status2_supported = bay2_handle &&
-           acpi_evalf(bay2_handle, NULL, "_STA", "qv");
-
-       bay_eject_supported = bay_handle && bay_ej_handle &&
-           (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
-       bay_eject2_supported = bay2_handle && bay2_ej_handle &&
-           (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
-
-       return 0;
-}
-
-#define bay_occupied(b) (_sta(b##_handle) & 1)
-
-static int bay_read(char *p)
-{
-       int len = 0;
-       int occupied = bay_occupied(bay);
-       int occupied2 = bay_occupied(bay2);
-       int eject, eject2;
-
-       len += sprintf(p + len, "status:\t\t%s\n", bay_status_supported ?
-                      (occupied ? "occupied" : "unoccupied") :
-                      "not supported");
-       if (bay_status2_supported)
-               len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
-                              "occupied" : "unoccupied");
-
-       eject = bay_eject_supported && occupied;
-       eject2 = bay_eject2_supported && occupied2;
-
-       if (eject && eject2)
-               len += sprintf(p + len, "commands:\teject, eject2\n");
-       else if (eject)
-               len += sprintf(p + len, "commands:\teject\n");
-       else if (eject2)
-               len += sprintf(p + len, "commands:\teject2\n");
-
-       return len;
-}
-
-static int bay_write(char *buf)
-{
-       char *cmd;
-
-       if (!bay_eject_supported && !bay_eject2_supported)
-               return -ENODEV;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (bay_eject_supported && strlencmp(cmd, "eject") == 0) {
-                       if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
-                               return -EIO;
-               } else if (bay_eject2_supported &&
-                          strlencmp(cmd, "eject2") == 0) {
-                       if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
-                               return -EIO;
-               } else
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void bay_notify(struct ibm_struct *ibm, u32 event)
-{
-       acpi_bus_generate_event(ibm->device, event, 0);
-}
-#endif /* CONFIG_ACPI_IBM_BAY */
-
-static int cmos_read(char *p)
-{
-       int len = 0;
-
-       /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
-          R30, R31, T20-22, X20-21 */
-       if (!cmos_handle)
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-       else {
-               len += sprintf(p + len, "status:\t\tsupported\n");
-               len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
-       }
-
-       return len;
-}
-
-static int cmos_eval(int cmos_cmd)
-{
-       if (cmos_handle)
-               return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
-       else
-               return 1;
-}
-
-static int cmos_write(char *buf)
-{
-       char *cmd;
-       int cmos_cmd;
-
-       if (!cmos_handle)
-               return -EINVAL;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
-                   cmos_cmd >= 0 && cmos_cmd <= 21) {
-                       /* cmos_cmd set */
-               } else
-                       return -EINVAL;
-
-               if (!cmos_eval(cmos_cmd))
-                       return -EIO;
-       }
-
-       return 0;
-}
-
-enum led_access_mode {
-       IBMACPI_LED_NONE = 0,
-       IBMACPI_LED_570,        /* 570 */
-       IBMACPI_LED_OLD,        /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
-       IBMACPI_LED_NEW,        /* all others */
-};
-static enum led_access_mode led_supported;
-
-static int led_init(void)
-{
-       if (!led_handle)
-               /* led not supported on R30, R31 */
-               led_supported = IBMACPI_LED_NONE;
-       else if (strlencmp(led_path, "SLED") == 0)
-               /* 570 */
-               led_supported = IBMACPI_LED_570;
-       else if (strlencmp(led_path, "SYSL") == 0)
-               /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
-               led_supported = IBMACPI_LED_OLD;
-       else
-               /* all others */
-               led_supported = IBMACPI_LED_NEW;
-
-       return 0;
-}
-
-#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
-
-static int led_read(char *p)
-{
-       int len = 0;
-
-       if (!led_supported) {
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-               return len;
-       }
-       len += sprintf(p + len, "status:\t\tsupported\n");
-
-       if (led_supported == IBMACPI_LED_570) {
-               /* 570 */
-               int i, status;
-               for (i = 0; i < 8; i++) {
-                       if (!acpi_evalf(ec_handle,
-                                       &status, "GLED", "dd", 1 << i))
-                               return -EIO;
-                       len += sprintf(p + len, "%d:\t\t%s\n",
-                                      i, led_status(status));
-               }
-       }
-
-       len += sprintf(p + len, "commands:\t"
-                      "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
-
-       return len;
-}
-
-/* off, on, blink */
-static const int led_sled_arg1[] = { 0, 1, 3 };
-static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
-static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
-static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
-
-#define EC_HLCL 0x0c
-#define EC_HLBL 0x0d
-#define EC_HLMS 0x0e
-
-static int led_write(char *buf)
-{
-       char *cmd;
-       int led, ind, ret;
-
-       if (!led_supported)
-               return -ENODEV;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
-                       return -EINVAL;
-
-               if (strstr(cmd, "off")) {
-                       ind = 0;
-               } else if (strstr(cmd, "on")) {
-                       ind = 1;
-               } else if (strstr(cmd, "blink")) {
-                       ind = 2;
-               } else
-                       return -EINVAL;
-
-               if (led_supported == IBMACPI_LED_570) {
-                       /* 570 */
-                       led = 1 << led;
-                       if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
-                                       led, led_sled_arg1[ind]))
-                               return -EIO;
-               } else if (led_supported == IBMACPI_LED_OLD) {
-                       /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
-                       led = 1 << led;
-                       ret = ec_write(EC_HLMS, led);
-                       if (ret >= 0)
-                               ret =
-                                   ec_write(EC_HLBL, led * led_exp_hlbl[ind]);
-                       if (ret >= 0)
-                               ret =
-                                   ec_write(EC_HLCL, led * led_exp_hlcl[ind]);
-                       if (ret < 0)
-                               return ret;
-               } else {
-                       /* all others */
-                       if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
-                                       led, led_led_arg1[ind]))
-                               return -EIO;
-               }
-       }
-
-       return 0;
-}
-
-static int beep_read(char *p)
-{
-       int len = 0;
-
-       if (!beep_handle)
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-       else {
-               len += sprintf(p + len, "status:\t\tsupported\n");
-               len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
-       }
-
-       return len;
-}
-
-static int beep_write(char *buf)
-{
-       char *cmd;
-       int beep_cmd;
-
-       if (!beep_handle)
-               return -ENODEV;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
-                   beep_cmd >= 0 && beep_cmd <= 17) {
-                       /* beep_cmd set */
-               } else
-                       return -EINVAL;
-               if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
-                       return -EIO;
-       }
-
-       return 0;
-}
-
-static int acpi_ec_read(int i, u8 * p)
-{
-       int v;
-
-       if (ecrd_handle) {
-               if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
-                       return 0;
-               *p = v;
-       } else {
-               if (ec_read(i, p) < 0)
-                       return 0;
-       }
-
-       return 1;
-}
-
-static int acpi_ec_write(int i, u8 v)
-{
-       if (ecwr_handle) {
-               if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
-                       return 0;
-       } else {
-               if (ec_write(i, v) < 0)
-                       return 0;
-       }
-
-       return 1;
-}
-
-static enum thermal_access_mode thermal_read_mode;
-
-static int thermal_init(void)
-{
-       u8 t, ta1, ta2;
-       int i;
-       int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
-
-       if (ibm_thinkpad_ec_found && experimental) {
-               /*
-                * Direct EC access mode: sensors at registers
-                * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
-                * non-implemented, thermal sensors return 0x80 when
-                * not available
-                */
-
-               ta1 = ta2 = 0;
-               for (i = 0; i < 8; i++) {
-                       if (likely(acpi_ec_read(0x78 + i, &t))) {
-                               ta1 |= t;
-                       } else {
-                               ta1 = 0;
-                               break;
-                       }
-                       if (likely(acpi_ec_read(0xC0 + i, &t))) {
-                               ta2 |= t;
-                       } else {
-                               ta1 = 0;
-                               break;
-                       }
-               }
-               if (ta1 == 0) {
-                       /* This is sheer paranoia, but we handle it anyway */
-                       if (acpi_tmp7) {
-                               printk(IBM_ERR
-                                      "ThinkPad ACPI EC access misbehaving, "
-                                      "falling back to ACPI TMPx access mode\n");
-                               thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
-                       } else {
-                               printk(IBM_ERR
-                                      "ThinkPad ACPI EC access misbehaving, "
-                                      "disabling thermal sensors access\n");
-                               thermal_read_mode = IBMACPI_THERMAL_NONE;
-                       }
-               } else {
-                       thermal_read_mode =
-                           (ta2 != 0) ?
-                           IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
-               }
-       } else if (acpi_tmp7) {
-               if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
-                       /* 600e/x, 770e, 770x */
-                       thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
-               } else {
-                       /* Standard ACPI TMPx access, max 8 sensors */
-                       thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
-               }
-       } else {
-               /* temperatures not supported on 570, G4x, R30, R31, R32 */
-               thermal_read_mode = IBMACPI_THERMAL_NONE;
-       }
-
-       return 0;
-}
-
-static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
-{
-       int i, t;
-       s8 tmp;
-       char tmpi[] = "TMPi";
-
-       if (!s)
-               return -EINVAL;
-
-       switch (thermal_read_mode) {
-#if IBMACPI_MAX_THERMAL_SENSORS >= 16
-       case IBMACPI_THERMAL_TPEC_16:
-               for (i = 0; i < 8; i++) {
-                       if (!acpi_ec_read(0xC0 + i, &tmp))
-                               return -EIO;
-                       s->temp[i + 8] = tmp * 1000;
-               }
-               /* fallthrough */
-#endif
-       case IBMACPI_THERMAL_TPEC_8:
-               for (i = 0; i < 8; i++) {
-                       if (!acpi_ec_read(0x78 + i, &tmp))
-                               return -EIO;
-                       s->temp[i] = tmp * 1000;
-               }
-               return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
-
-       case IBMACPI_THERMAL_ACPI_UPDT:
-               if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
-                       return -EIO;
-               for (i = 0; i < 8; i++) {
-                       tmpi[3] = '0' + i;
-                       if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
-                               return -EIO;
-                       s->temp[i] = (t - 2732) * 100;
-               }
-               return 8;
-
-       case IBMACPI_THERMAL_ACPI_TMP07:
-               for (i = 0; i < 8; i++) {
-                       tmpi[3] = '0' + i;
-                       if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
-                               return -EIO;
-                       s->temp[i] = t * 1000;
-               }
-               return 8;
-
-       case IBMACPI_THERMAL_NONE:
-       default:
-               return 0;
-       }
-}
-
-static int thermal_read(char *p)
-{
-       int len = 0;
-       int n, i;
-       struct ibm_thermal_sensors_struct t;
-
-       n = thermal_get_sensors(&t);
-       if (unlikely(n < 0))
-               return n;
-
-       len += sprintf(p + len, "temperatures:\t");
-
-       if (n > 0) {
-               for (i = 0; i < (n - 1); i++)
-                       len += sprintf(p + len, "%d ", t.temp[i] / 1000);
-               len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
-       } else
-               len += sprintf(p + len, "not supported\n");
-
-       return len;
-}
-
-static u8 ecdump_regs[256];
-
-static int ecdump_read(char *p)
-{
-       int len = 0;
-       int i, j;
-       u8 v;
-
-       len += sprintf(p + len, "EC      "
-                      " +00 +01 +02 +03 +04 +05 +06 +07"
-                      " +08 +09 +0a +0b +0c +0d +0e +0f\n");
-       for (i = 0; i < 256; i += 16) {
-               len += sprintf(p + len, "EC 0x%02x:", i);
-               for (j = 0; j < 16; j++) {
-                       if (!acpi_ec_read(i + j, &v))
-                               break;
-                       if (v != ecdump_regs[i + j])
-                               len += sprintf(p + len, " *%02x", v);
-                       else
-                               len += sprintf(p + len, "  %02x", v);
-                       ecdump_regs[i + j] = v;
-               }
-               len += sprintf(p + len, "\n");
-               if (j != 16)
-                       break;
-       }
-
-       /* These are way too dangerous to advertise openly... */
-#if 0
-       len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
-                      " (<offset> is 00-ff, <value> is 00-ff)\n");
-       len += sprintf(p + len, "commands:\t0x<offset> <value>  "
-                      " (<offset> is 00-ff, <value> is 0-255)\n");
-#endif
-       return len;
-}
-
-static int ecdump_write(char *buf)
-{
-       char *cmd;
-       int i, v;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
-                       /* i and v set */
-               } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
-                       /* i and v set */
-               } else
-                       return -EINVAL;
-               if (i >= 0 && i < 256 && v >= 0 && v < 256) {
-                       if (!acpi_ec_write(i, v))
-                               return -EIO;
-               } else
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int brightness_offset = 0x31;
-
-static int brightness_get(struct backlight_device *bd)
-{
-       u8 level;
-       if (!acpi_ec_read(brightness_offset, &level))
-               return -EIO;
-
-       level &= 0x7;
-
-       return level;
-}
-
-static int brightness_read(char *p)
-{
-       int len = 0;
-       int level;
-
-       if ((level = brightness_get(NULL)) < 0) {
-               len += sprintf(p + len, "level:\t\tunreadable\n");
-       } else {
-               len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
-               len += sprintf(p + len, "commands:\tup, down\n");
-               len += sprintf(p + len, "commands:\tlevel <level>"
-                              " (<level> is 0-7)\n");
-       }
-
-       return len;
-}
-
-#define BRIGHTNESS_UP  4
-#define BRIGHTNESS_DOWN        5
-
-static int brightness_set(int value)
-{
-       int cmos_cmd, inc, i;
-       int current_value = brightness_get(NULL);
-
-       value &= 7;
-
-       cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
-       inc = value > current_value ? 1 : -1;
-       for (i = current_value; i != value; i += inc) {
-               if (!cmos_eval(cmos_cmd))
-                       return -EIO;
-               if (!acpi_ec_write(brightness_offset, i + inc))
-                       return -EIO;
-       }
-
-       return 0;
-}
-
-static int brightness_write(char *buf)
-{
-       int level;
-       int new_level;
-       char *cmd;
-
-       while ((cmd = next_cmd(&buf))) {
-               if ((level = brightness_get(NULL)) < 0)
-                       return level;
-               level &= 7;
-
-               if (strlencmp(cmd, "up") == 0) {
-                       new_level = level == 7 ? 7 : level + 1;
-               } else if (strlencmp(cmd, "down") == 0) {
-                       new_level = level == 0 ? 0 : level - 1;
-               } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
-                          new_level >= 0 && new_level <= 7) {
-                       /* new_level set */
-               } else
-                       return -EINVAL;
-
-               brightness_set(new_level);
-       }
-
-       return 0;
-}
-
-static int brightness_update_status(struct backlight_device *bd)
-{
-       return brightness_set(
-               (bd->props.fb_blank == FB_BLANK_UNBLANK &&
-                bd->props.power == FB_BLANK_UNBLANK) ?
-                               bd->props.brightness : 0);
-}
-
-static struct backlight_ops ibm_backlight_data = {
-        .get_brightness = brightness_get,
-        .update_status  = brightness_update_status,
-};
-
-static int brightness_init(void)
-{
-       int b;
-
-       b = brightness_get(NULL);
-       if (b < 0)
-               return b;
-
-       ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
-                                                        &ibm_backlight_data);
-       if (IS_ERR(ibm_backlight_device)) {
-               printk(IBM_ERR "Could not register backlight device\n");
-               return PTR_ERR(ibm_backlight_device);
-       }
-
-       ibm_backlight_device->props.max_brightness = 7;
-       ibm_backlight_device->props.brightness = b;
-       backlight_update_status(ibm_backlight_device);
-
-       return 0;
-}
-
-static void brightness_exit(void)
-{
-       if (ibm_backlight_device) {
-               backlight_device_unregister(ibm_backlight_device);
-               ibm_backlight_device = NULL;
-       }
-}
-
-static int volume_offset = 0x30;
-
-static int volume_read(char *p)
-{
-       int len = 0;
-       u8 level;
-
-       if (!acpi_ec_read(volume_offset, &level)) {
-               len += sprintf(p + len, "level:\t\tunreadable\n");
-       } else {
-               len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
-               len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
-               len += sprintf(p + len, "commands:\tup, down, mute\n");
-               len += sprintf(p + len, "commands:\tlevel <level>"
-                              " (<level> is 0-15)\n");
-       }
-
-       return len;
-}
-
-#define VOLUME_DOWN    0
-#define VOLUME_UP      1
-#define VOLUME_MUTE    2
-
-static int volume_write(char *buf)
-{
-       int cmos_cmd, inc, i;
-       u8 level, mute;
-       int new_level, new_mute;
-       char *cmd;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (!acpi_ec_read(volume_offset, &level))
-                       return -EIO;
-               new_mute = mute = level & 0x40;
-               new_level = level = level & 0xf;
-
-               if (strlencmp(cmd, "up") == 0) {
-                       if (mute)
-                               new_mute = 0;
-                       else
-                               new_level = level == 15 ? 15 : level + 1;
-               } else if (strlencmp(cmd, "down") == 0) {
-                       if (mute)
-                               new_mute = 0;
-                       else
-                               new_level = level == 0 ? 0 : level - 1;
-               } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
-                          new_level >= 0 && new_level <= 15) {
-                       /* new_level set */
-               } else if (strlencmp(cmd, "mute") == 0) {
-                       new_mute = 0x40;
-               } else
-                       return -EINVAL;
-
-               if (new_level != level) {       /* mute doesn't change */
-                       cmos_cmd = new_level > level ? VOLUME_UP : VOLUME_DOWN;
-                       inc = new_level > level ? 1 : -1;
-
-                       if (mute && (!cmos_eval(cmos_cmd) ||
-                                    !acpi_ec_write(volume_offset, level)))
-                               return -EIO;
-
-                       for (i = level; i != new_level; i += inc)
-                               if (!cmos_eval(cmos_cmd) ||
-                                   !acpi_ec_write(volume_offset, i + inc))
-                                       return -EIO;
-
-                       if (mute && (!cmos_eval(VOLUME_MUTE) ||
-                                    !acpi_ec_write(volume_offset,
-                                                   new_level + mute)))
-                               return -EIO;
-               }
-
-               if (new_mute != mute) { /* level doesn't change */
-                       cmos_cmd = new_mute ? VOLUME_MUTE : VOLUME_UP;
-
-                       if (!cmos_eval(cmos_cmd) ||
-                           !acpi_ec_write(volume_offset, level + new_mute))
-                               return -EIO;
-               }
-       }
-
-       return 0;
-}
-
-static enum fan_status_access_mode fan_status_access_mode;
-static enum fan_control_access_mode fan_control_access_mode;
-static enum fan_control_commands fan_control_commands;
-
-static int fan_control_status_known;
-static u8 fan_control_initial_status;
-
-static void fan_watchdog_fire(struct work_struct *ignored);
-static int fan_watchdog_maxinterval;
-static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
-
-static int fan_init(void)
-{
-       fan_status_access_mode = IBMACPI_FAN_NONE;
-       fan_control_access_mode = IBMACPI_FAN_WR_NONE;
-       fan_control_commands = 0;
-       fan_control_status_known = 1;
-       fan_watchdog_maxinterval = 0;
-
-       if (gfan_handle) {
-               /* 570, 600e/x, 770e, 770x */
-               fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN;
-       } else {
-               /* all other ThinkPads: note that even old-style
-                * ThinkPad ECs supports the fan control register */
-               if (likely(acpi_ec_read(fan_status_offset,
-                                       &fan_control_initial_status))) {
-                       fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
-
-                       /* In some ThinkPads, neither the EC nor the ACPI
-                        * DSDT initialize the fan status, and it ends up
-                        * being set to 0x07 when it *could* be either
-                        * 0x07 or 0x80.
-                        *
-                        * Enable for TP-1Y (T43), TP-78 (R51e),
-                        * TP-76 (R52), TP-70 (T43, R52), which are known
-                        * to be buggy. */
-                       if (fan_control_initial_status == 0x07 &&
-                           ibm_thinkpad_ec_found &&
-                           ((ibm_thinkpad_ec_found[0] == '1' &&
-                             ibm_thinkpad_ec_found[1] == 'Y') ||
-                            (ibm_thinkpad_ec_found[0] == '7' &&
-                             (ibm_thinkpad_ec_found[1] == '6' ||
-                              ibm_thinkpad_ec_found[1] == '8' ||
-                              ibm_thinkpad_ec_found[1] == '0'))
-                           )) {
-                               printk(IBM_NOTICE
-                                      "fan_init: initial fan status is "
-                                      "unknown, assuming it is in auto "
-                                      "mode\n");
-                               fan_control_status_known = 0;
-                       }
-               } else {
-                       printk(IBM_ERR
-                              "ThinkPad ACPI EC access misbehaving, "
-                              "fan status and control unavailable\n");
-                       return 0;
-               }
-       }
-
-       if (sfan_handle) {
-               /* 570, 770x-JL */
-               fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
-               fan_control_commands |=
-                   IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE;
-       } else {
-               if (!gfan_handle) {
-                       /* gfan without sfan means no fan control */
-                       /* all other models implement TP EC 0x2f control */
-
-                       if (fans_handle) {
-                               /* X31, X40, X41 */
-                               fan_control_access_mode =
-                                   IBMACPI_FAN_WR_ACPI_FANS;
-                               fan_control_commands |=
-                                   IBMACPI_FAN_CMD_SPEED |
-                                   IBMACPI_FAN_CMD_LEVEL |
-                                   IBMACPI_FAN_CMD_ENABLE;
-                       } else {
-                               fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
-                               fan_control_commands |=
-                                   IBMACPI_FAN_CMD_LEVEL |
-                                   IBMACPI_FAN_CMD_ENABLE;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int fan_get_status(u8 *status)
-{
-       u8 s;
-
-       /* TODO:
-        * Add IBMACPI_FAN_RD_ACPI_FANS ? */
-
-       switch (fan_status_access_mode) {
-       case IBMACPI_FAN_RD_ACPI_GFAN:
-               /* 570, 600e/x, 770e, 770x */
-
-               if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
-                       return -EIO;
-
-               if (likely(status))
-                       *status = s & 0x07;
-
-               break;
-
-       case IBMACPI_FAN_RD_TPEC:
-               /* all except 570, 600e/x, 770e, 770x */
-               if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
-                       return -EIO;
-
-               if (likely(status))
-                       *status = s;
-
-               break;
-
-       default:
-               return -ENXIO;
-       }
-
-       return 0;
-}
-
-static int fan_get_speed(unsigned int *speed)
-{
-       u8 hi, lo;
-
-       switch (fan_status_access_mode) {
-       case IBMACPI_FAN_RD_TPEC:
-               /* all except 570, 600e/x, 770e, 770x */
-               if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
-                            !acpi_ec_read(fan_rpm_offset + 1, &hi)))
-                       return -EIO;
-
-               if (likely(speed))
-                       *speed = (hi << 8) | lo;
-
-               break;
-
-       default:
-               return -ENXIO;
-       }
-
-       return 0;
-}
-
-static void fan_exit(void)
-{
-       cancel_delayed_work(&fan_watchdog_task);
-       flush_scheduled_work();
-}
-
-static void fan_watchdog_reset(void)
-{
-       static int fan_watchdog_active = 0;
-
-       if (fan_watchdog_active)
-               cancel_delayed_work(&fan_watchdog_task);
-
-       if (fan_watchdog_maxinterval > 0) {
-               fan_watchdog_active = 1;
-               if (!schedule_delayed_work(&fan_watchdog_task,
-                               msecs_to_jiffies(fan_watchdog_maxinterval
-                                                * 1000))) {
-                       printk(IBM_ERR "failed to schedule the fan watchdog, "
-                              "watchdog will not trigger\n");
-               }
-       } else
-               fan_watchdog_active = 0;
-}
-
-static int fan_read(char *p)
-{
-       int len = 0;
-       int rc;
-       u8 status;
-       unsigned int speed = 0;
-
-       switch (fan_status_access_mode) {
-       case IBMACPI_FAN_RD_ACPI_GFAN:
-               /* 570, 600e/x, 770e, 770x */
-               if ((rc = fan_get_status(&status)) < 0)
-                       return rc;
-
-               len += sprintf(p + len, "status:\t\t%s\n"
-                              "level:\t\t%d\n",
-                              (status != 0) ? "enabled" : "disabled", status);
-               break;
-
-       case IBMACPI_FAN_RD_TPEC:
-               /* all except 570, 600e/x, 770e, 770x */
-               if ((rc = fan_get_status(&status)) < 0)
-                       return rc;
-
-               if (unlikely(!fan_control_status_known)) {
-                       if (status != fan_control_initial_status)
-                               fan_control_status_known = 1;
-                       else
-                               /* Return most likely status. In fact, it
-                                * might be the only possible status */
-                               status = IBMACPI_FAN_EC_AUTO;
-               }
-
-               len += sprintf(p + len, "status:\t\t%s\n",
-                              (status != 0) ? "enabled" : "disabled");
-
-               /* No ThinkPad boots on disengaged mode, we can safely
-                * assume the tachometer is online if fan control status
-                * was unknown */
-               if ((rc = fan_get_speed(&speed)) < 0)
-                       return rc;
-
-               len += sprintf(p + len, "speed:\t\t%d\n", speed);
-
-               if (status & IBMACPI_FAN_EC_DISENGAGED)
-                       /* Disengaged mode takes precedence */
-                       len += sprintf(p + len, "level:\t\tdisengaged\n");
-               else if (status & IBMACPI_FAN_EC_AUTO)
-                       len += sprintf(p + len, "level:\t\tauto\n");
-               else
-                       len += sprintf(p + len, "level:\t\t%d\n", status);
-               break;
-
-       case IBMACPI_FAN_NONE:
-       default:
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-       }
-
-       if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
-               len += sprintf(p + len, "commands:\tlevel <level>");
-
-               switch (fan_control_access_mode) {
-               case IBMACPI_FAN_WR_ACPI_SFAN:
-                       len += sprintf(p + len, " (<level> is 0-7)\n");
-                       break;
-
-               default:
-                       len += sprintf(p + len, " (<level> is 0-7, "
-                                      "auto, disengaged)\n");
-                       break;
-               }
-       }
-
-       if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
-               len += sprintf(p + len, "commands:\tenable, disable\n"
-                              "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
-                              "1-120 (seconds))\n");
-
-       if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
-               len += sprintf(p + len, "commands:\tspeed <speed>"
-                              " (<speed> is 0-65535)\n");
-
-       return len;
-}
-
-static int fan_set_level(int level)
-{
-       switch (fan_control_access_mode) {
-       case IBMACPI_FAN_WR_ACPI_SFAN:
-               if (level >= 0 && level <= 7) {
-                       if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
-                               return -EIO;
-               } else
-                       return -EINVAL;
-               break;
-
-       case IBMACPI_FAN_WR_ACPI_FANS:
-       case IBMACPI_FAN_WR_TPEC:
-               if ((level != IBMACPI_FAN_EC_AUTO) &&
-                   (level != IBMACPI_FAN_EC_DISENGAGED) &&
-                   ((level < 0) || (level > 7)))
-                       return -EINVAL;
-
-               if (!acpi_ec_write(fan_status_offset, level))
-                       return -EIO;
-               else
-                       fan_control_status_known = 1;
-               break;
-
-       default:
-               return -ENXIO;
-       }
-       return 0;
-}
-
-static int fan_set_enable(void)
-{
-       u8 s;
-       int rc;
-
-       switch (fan_control_access_mode) {
-       case IBMACPI_FAN_WR_ACPI_FANS:
-       case IBMACPI_FAN_WR_TPEC:
-               if ((rc = fan_get_status(&s)) < 0)
-                       return rc;
-
-               /* Don't go out of emergency fan mode */
-               if (s != 7)
-                       s = IBMACPI_FAN_EC_AUTO;
-
-               if (!acpi_ec_write(fan_status_offset, s))
-                       return -EIO;
-               else
-                       fan_control_status_known = 1;
-               break;
-
-       case IBMACPI_FAN_WR_ACPI_SFAN:
-               if ((rc = fan_get_status(&s)) < 0)
-                       return rc;
-
-               s &= 0x07;
-
-               /* Set fan to at least level 4 */
-               if (s < 4)
-                       s = 4;
-
-               if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
-                       return -EIO;
-               break;
-
-       default:
-               return -ENXIO;
-       }
-       return 0;
-}
-
-static int fan_set_disable(void)
-{
-       switch (fan_control_access_mode) {
-       case IBMACPI_FAN_WR_ACPI_FANS:
-       case IBMACPI_FAN_WR_TPEC:
-               if (!acpi_ec_write(fan_status_offset, 0x00))
-                       return -EIO;
-               else
-                       fan_control_status_known = 1;
-               break;
-
-       case IBMACPI_FAN_WR_ACPI_SFAN:
-               if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
-                       return -EIO;
-               break;
-
-       default:
-               return -ENXIO;
-       }
-       return 0;
-}
-
-static int fan_set_speed(int speed)
-{
-       switch (fan_control_access_mode) {
-       case IBMACPI_FAN_WR_ACPI_FANS:
-               if (speed >= 0 && speed <= 65535) {
-                       if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
-                                       speed, speed, speed))
-                               return -EIO;
-               } else
-                       return -EINVAL;
-               break;
-
-       default:
-               return -ENXIO;
-       }
-       return 0;
-}
-
-static int fan_write_cmd_level(const char *cmd, int *rc)
-{
-       int level;
-
-       if (strlencmp(cmd, "level auto") == 0)
-               level = IBMACPI_FAN_EC_AUTO;
-       else if (strlencmp(cmd, "level disengaged") == 0)
-               level = IBMACPI_FAN_EC_DISENGAGED;
-       else if (sscanf(cmd, "level %d", &level) != 1)
-               return 0;
-
-       if ((*rc = fan_set_level(level)) == -ENXIO)
-               printk(IBM_ERR "level command accepted for unsupported "
-                      "access mode %d", fan_control_access_mode);
-
-       return 1;
-}
-
-static int fan_write_cmd_enable(const char *cmd, int *rc)
-{
-       if (strlencmp(cmd, "enable") != 0)
-               return 0;
-
-       if ((*rc = fan_set_enable()) == -ENXIO)
-               printk(IBM_ERR "enable command accepted for unsupported "
-                      "access mode %d", fan_control_access_mode);
-
-       return 1;
-}
-
-static int fan_write_cmd_disable(const char *cmd, int *rc)
-{
-       if (strlencmp(cmd, "disable") != 0)
-               return 0;
-
-       if ((*rc = fan_set_disable()) == -ENXIO)
-               printk(IBM_ERR "disable command accepted for unsupported "
-                      "access mode %d", fan_control_access_mode);
-
-       return 1;
-}
-
-static int fan_write_cmd_speed(const char *cmd, int *rc)
-{
-       int speed;
-
-       /* TODO:
-        * Support speed <low> <medium> <high> ? */
-
-       if (sscanf(cmd, "speed %d", &speed) != 1)
-               return 0;
-
-       if ((*rc = fan_set_speed(speed)) == -ENXIO)
-               printk(IBM_ERR "speed command accepted for unsupported "
-                      "access mode %d", fan_control_access_mode);
-
-       return 1;
-}
-
-static int fan_write_cmd_watchdog(const char *cmd, int *rc)
-{
-       int interval;
-
-       if (sscanf(cmd, "watchdog %d", &interval) != 1)
-               return 0;
-
-       if (interval < 0 || interval > 120)
-               *rc = -EINVAL;
-       else
-               fan_watchdog_maxinterval = interval;
-
-       return 1;
-}
-
-static int fan_write(char *buf)
-{
-       char *cmd;
-       int rc = 0;
-
-       while (!rc && (cmd = next_cmd(&buf))) {
-               if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) &&
-                     fan_write_cmd_level(cmd, &rc)) &&
-                   !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) &&
-                     (fan_write_cmd_enable(cmd, &rc) ||
-                      fan_write_cmd_disable(cmd, &rc) ||
-                      fan_write_cmd_watchdog(cmd, &rc))) &&
-                   !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) &&
-                     fan_write_cmd_speed(cmd, &rc))
-                   )
-                       rc = -EINVAL;
-               else if (!rc)
-                       fan_watchdog_reset();
-       }
-
-       return rc;
-}
-
-static void fan_watchdog_fire(struct work_struct *ignored)
-{
-       printk(IBM_NOTICE "fan watchdog: enabling fan\n");
-       if (fan_set_enable()) {
-               printk(IBM_ERR "fan watchdog: error while enabling fan\n");
-               /* reschedule for later */
-               fan_watchdog_reset();
-       }
-}
-
-static struct ibm_struct ibms[] = {
-       {
-        .name = "driver",
-        .init = ibm_acpi_driver_init,
-        .read = driver_read,
-        },
-       {
-        .name = "hotkey",
-        .hid = IBM_HKEY_HID,
-        .init = hotkey_init,
-        .read = hotkey_read,
-        .write = hotkey_write,
-        .exit = hotkey_exit,
-        .notify = hotkey_notify,
-        .handle = &hkey_handle,
-        .type = ACPI_DEVICE_NOTIFY,
-        },
-       {
-        .name = "bluetooth",
-        .init = bluetooth_init,
-        .read = bluetooth_read,
-        .write = bluetooth_write,
-        },
-       {
-        .name = "wan",
-        .init = wan_init,
-        .read = wan_read,
-        .write = wan_write,
-        .experimental = 1,
-        },
-       {
-        .name = "video",
-        .init = video_init,
-        .read = video_read,
-        .write = video_write,
-        .exit = video_exit,
-        },
-       {
-        .name = "light",
-        .init = light_init,
-        .read = light_read,
-        .write = light_write,
-        },
-#ifdef CONFIG_ACPI_IBM_DOCK
-       {
-        .name = "dock",
-        .read = dock_read,
-        .write = dock_write,
-        .notify = dock_notify,
-        .handle = &dock_handle,
-        .type = ACPI_SYSTEM_NOTIFY,
-        },
-       {
-        .name = "dock",
-        .hid = IBM_PCI_HID,
-        .notify = dock_notify,
-        .handle = &pci_handle,
-        .type = ACPI_SYSTEM_NOTIFY,
-        },
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
-       {
-        .name = "bay",
-        .init = bay_init,
-        .read = bay_read,
-        .write = bay_write,
-        .notify = bay_notify,
-        .handle = &bay_handle,
-        .type = ACPI_SYSTEM_NOTIFY,
-        },
-#endif /* CONFIG_ACPI_IBM_BAY */
-       {
-        .name = "cmos",
-        .read = cmos_read,
-        .write = cmos_write,
-        },
-       {
-        .name = "led",
-        .init = led_init,
-        .read = led_read,
-        .write = led_write,
-        },
-       {
-        .name = "beep",
-        .read = beep_read,
-        .write = beep_write,
-        },
-       {
-        .name = "thermal",
-        .init = thermal_init,
-        .read = thermal_read,
-        },
-       {
-        .name = "ecdump",
-        .read = ecdump_read,
-        .write = ecdump_write,
-        .experimental = 1,
-        },
-       {
-        .name = "brightness",
-        .read = brightness_read,
-        .write = brightness_write,
-        .init = brightness_init,
-        .exit = brightness_exit,
-        },
-       {
-        .name = "volume",
-        .read = volume_read,
-        .write = volume_write,
-        },
-       {
-        .name = "fan",
-        .read = fan_read,
-        .write = fan_write,
-        .init = fan_init,
-        .exit = fan_exit,
-        .experimental = 1,
-        },
-};
-
-static int dispatch_read(char *page, char **start, off_t off, int count,
-                        int *eof, void *data)
-{
-       struct ibm_struct *ibm = data;
-       int len;
-
-       if (!ibm || !ibm->read)
-               return -EINVAL;
-
-       len = ibm->read(page);
-       if (len < 0)
-               return len;
-
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       len -= off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
-
-       return len;
-}
-
-static int dispatch_write(struct file *file, const char __user * userbuf,
-                         unsigned long count, void *data)
-{
-       struct ibm_struct *ibm = data;
-       char *kernbuf;
-       int ret;
-
-       if (!ibm || !ibm->write)
-               return -EINVAL;
-
-       kernbuf = kmalloc(count + 2, GFP_KERNEL);
-       if (!kernbuf)
-               return -ENOMEM;
-
-       if (copy_from_user(kernbuf, userbuf, count)) {
-               kfree(kernbuf);
-               return -EFAULT;
-       }
-
-       kernbuf[count] = 0;
-       strcat(kernbuf, ",");
-       ret = ibm->write(kernbuf);
-       if (ret == 0)
-               ret = count;
-
-       kfree(kernbuf);
-
-       return ret;
-}
-
-static void dispatch_notify(acpi_handle handle, u32 event, void *data)
-{
-       struct ibm_struct *ibm = data;
-
-       if (!ibm || !ibm->notify)
-               return;
-
-       ibm->notify(ibm, event);
-}
-
-static int __init setup_notify(struct ibm_struct *ibm)
-{
-       acpi_status status;
-       int ret;
-
-       if (!*ibm->handle)
-               return 0;
-
-       ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
-       if (ret < 0) {
-               printk(IBM_ERR "%s device not present\n", ibm->name);
-               return -ENODEV;
-       }
-
-       acpi_driver_data(ibm->device) = ibm;
-       sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
-
-       status = acpi_install_notify_handler(*ibm->handle, ibm->type,
-                                            dispatch_notify, ibm);
-       if (ACPI_FAILURE(status)) {
-               if (status == AE_ALREADY_EXISTS) {
-                       printk(IBM_NOTICE "another device driver is already handling %s events\n",
-                               ibm->name);
-               } else {
-                       printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
-                               ibm->name, status);
-               }
-               return -ENODEV;
-       }
-       ibm->notify_installed = 1;
-       return 0;
-}
-
-static int __init ibm_device_add(struct acpi_device *device)
-{
-       return 0;
-}
-
-static int __init register_driver(struct ibm_struct *ibm)
-{
-       int ret;
-
-       ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
-       if (!ibm->driver) {
-               printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
-               return -1;
-       }
-
-       sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
-       ibm->driver->ids = ibm->hid;
-       ibm->driver->ops.add = &ibm_device_add;
-
-       ret = acpi_bus_register_driver(ibm->driver);
-       if (ret < 0) {
-               printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
-                      ibm->hid, ret);
-               kfree(ibm->driver);
-       }
-
-       return ret;
-}
-
-static void ibm_exit(struct ibm_struct *ibm);
-
-static int __init ibm_init(struct ibm_struct *ibm)
-{
-       int ret;
-       struct proc_dir_entry *entry;
-
-       if (ibm->experimental && !experimental)
-               return 0;
-
-       if (ibm->hid) {
-               ret = register_driver(ibm);
-               if (ret < 0)
-                       return ret;
-               ibm->driver_registered = 1;
-       }
-
-       if (ibm->init) {
-               ret = ibm->init();
-               if (ret != 0)
-                       return ret;
-               ibm->init_called = 1;
-       }
-
-       if (ibm->read) {
-               entry = create_proc_entry(ibm->name,
-                                         S_IFREG | S_IRUGO | S_IWUSR,
-                                         proc_dir);
-               if (!entry) {
-                       printk(IBM_ERR "unable to create proc entry %s\n",
-                              ibm->name);
-                       return -ENODEV;
-               }
-               entry->owner = THIS_MODULE;
-               entry->data = ibm;
-               entry->read_proc = &dispatch_read;
-               if (ibm->write)
-                       entry->write_proc = &dispatch_write;
-               ibm->proc_created = 1;
-       }
-
-       if (ibm->notify) {
-               ret = setup_notify(ibm);
-               if (ret == -ENODEV) {
-                       printk(IBM_NOTICE "disabling subdriver %s\n",
-                               ibm->name);
-                       ibm_exit(ibm);
-                       return 0;
-               }
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static void ibm_exit(struct ibm_struct *ibm)
-{
-       if (ibm->notify_installed)
-               acpi_remove_notify_handler(*ibm->handle, ibm->type,
-                                          dispatch_notify);
-
-       if (ibm->proc_created)
-               remove_proc_entry(ibm->name, proc_dir);
-
-       if (ibm->init_called && ibm->exit)
-               ibm->exit();
-
-       if (ibm->driver_registered) {
-               acpi_bus_unregister_driver(ibm->driver);
-               kfree(ibm->driver);
-       }
-}
-
-static void __init ibm_handle_init(char *name,
-                                  acpi_handle * handle, acpi_handle parent,
-                                  char **paths, int num_paths, char **path)
-{
-       int i;
-       acpi_status status;
-
-       for (i = 0; i < num_paths; i++) {
-               status = acpi_get_handle(parent, paths[i], handle);
-               if (ACPI_SUCCESS(status)) {
-                       *path = paths[i];
-                       return;
-               }
-       }
-
-       *handle = NULL;
-}
-
-#define IBM_HANDLE_INIT(object)                                                \
-       ibm_handle_init(#object, &object##_handle, *object##_parent,    \
-               object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
-
-static int __init set_ibm_param(const char *val, struct kernel_param *kp)
-{
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(ibms); i++)
-               if (strcmp(ibms[i].name, kp->name) == 0 && ibms[i].write) {
-                       if (strlen(val) > sizeof(ibms[i].param) - 2)
-                               return -ENOSPC;
-                       strcpy(ibms[i].param, val);
-                       strcat(ibms[i].param, ",");
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-#define IBM_PARAM(feature) \
-       module_param_call(feature, set_ibm_param, NULL, NULL, 0)
-
-IBM_PARAM(hotkey);
-IBM_PARAM(bluetooth);
-IBM_PARAM(video);
-IBM_PARAM(light);
-#ifdef CONFIG_ACPI_IBM_DOCK
-IBM_PARAM(dock);
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
-IBM_PARAM(bay);
-#endif /* CONFIG_ACPI_IBM_BAY */
-IBM_PARAM(cmos);
-IBM_PARAM(led);
-IBM_PARAM(beep);
-IBM_PARAM(ecdump);
-IBM_PARAM(brightness);
-IBM_PARAM(volume);
-IBM_PARAM(fan);
-
-static void acpi_ibm_exit(void)
-{
-       int i;
-
-       for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
-               ibm_exit(&ibms[i]);
-
-       if (proc_dir)
-               remove_proc_entry(IBM_DIR, acpi_root_dir);
-
-       if (ibm_thinkpad_ec_found)
-               kfree(ibm_thinkpad_ec_found);
-}
-
-static char* __init check_dmi_for_ec(void)
-{
-       struct dmi_device *dev = NULL;
-       char ec_fw_string[18];
-
-       /*
-        * ThinkPad T23 or newer, A31 or newer, R50e or newer,
-        * X32 or newer, all Z series;  Some models must have an
-        * up-to-date BIOS or they will not be detected.
-        *
-        * See http://thinkwiki.org/wiki/List_of_DMI_IDs
-        */
-       while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
-               if (sscanf(dev->name,
-                          "IBM ThinkPad Embedded Controller -[%17c",
-                          ec_fw_string) == 1) {
-                       ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
-                       ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
-                       return kstrdup(ec_fw_string, GFP_KERNEL);
-               }
-       }
-       return NULL;
-}
-
-static int __init acpi_ibm_init(void)
-{
-       int ret, i;
-
-       if (acpi_disabled)
-               return -ENODEV;
-
-       /* ec is required because many other handles are relative to it */
-       IBM_HANDLE_INIT(ec);
-       if (!ec_handle) {
-               printk(IBM_ERR "ec object not found\n");
-               return -ENODEV;
-       }
-
-       /* Models with newer firmware report the EC in DMI */
-       ibm_thinkpad_ec_found = check_dmi_for_ec();
-
-       /* these handles are not required */
-       IBM_HANDLE_INIT(vid);
-       IBM_HANDLE_INIT(vid2);
-       IBM_HANDLE_INIT(ledb);
-       IBM_HANDLE_INIT(led);
-       IBM_HANDLE_INIT(hkey);
-       IBM_HANDLE_INIT(lght);
-       IBM_HANDLE_INIT(cmos);
-#ifdef CONFIG_ACPI_IBM_DOCK
-       IBM_HANDLE_INIT(dock);
-#endif
-       IBM_HANDLE_INIT(pci);
-#ifdef CONFIG_ACPI_IBM_BAY
-       IBM_HANDLE_INIT(bay);
-       if (bay_handle)
-               IBM_HANDLE_INIT(bay_ej);
-       IBM_HANDLE_INIT(bay2);
-       if (bay2_handle)
-               IBM_HANDLE_INIT(bay2_ej);
-#endif /* CONFIG_ACPI_IBM_BAY */
-       IBM_HANDLE_INIT(beep);
-       IBM_HANDLE_INIT(ecrd);
-       IBM_HANDLE_INIT(ecwr);
-       IBM_HANDLE_INIT(fans);
-       IBM_HANDLE_INIT(gfan);
-       IBM_HANDLE_INIT(sfan);
-
-       proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir);
-       if (!proc_dir) {
-               printk(IBM_ERR "unable to create proc dir %s", IBM_DIR);
-               acpi_ibm_exit();
-               return -ENODEV;
-       }
-       proc_dir->owner = THIS_MODULE;
-
-       for (i = 0; i < ARRAY_SIZE(ibms); i++) {
-               ret = ibm_init(&ibms[i]);
-               if (ret >= 0 && *ibms[i].param)
-                       ret = ibms[i].write(ibms[i].param);
-               if (ret < 0) {
-                       acpi_ibm_exit();
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-module_init(acpi_ibm_init);
-module_exit(acpi_ibm_exit);
index 99d1516d1e7023c067b8485272440dab43111485..f7de02a6f497a5d61752dff2a413a7c7b4c9f43a 100644 (file)
@@ -70,8 +70,6 @@
 #define ACPI_PROCESSOR_LIMIT_USER      0
 #define ACPI_PROCESSOR_LIMIT_THERMAL   1
 
-#define ACPI_STA_PRESENT 0x00000001
-
 #define _COMPONENT             ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_core");
 
@@ -779,7 +777,7 @@ static int is_processor_present(acpi_handle handle)
 
 
        status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-       if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
+       if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) {
                ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
                return 0;
        }
index cdf78943af4db915f1a54da4285cbca2cc1c42ac..ae0654cd11eaa58bcf3fff763e2cd3d341004a44 100644 (file)
 #include <asm/apic.h>
 #endif
 
-/*
- * Include the apic definitions for x86 to have the APIC timer related defines
- * available also for UP (on SMP it gets magically included via linux/smp.h).
- */
-#ifdef CONFIG_X86
-#include <asm/apic.h>
-#endif
-
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
index 59640d9a0acceefe1ee8a4e6d9495edb4f5c5431..c1bae106833cef03d6f7faee83e5d42c9fda36a9 100644 (file)
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
 #include <linux/acpi.h>
-#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
 #include <linux/delay.h>
 
-#include "i2c_ec.h"
-
-#define        DEF_CAPACITY_UNIT       3
-#define        MAH_CAPACITY_UNIT       1
-#define        MWH_CAPACITY_UNIT       2
-#define        CAPACITY_UNIT           DEF_CAPACITY_UNIT
-
-#define        REQUEST_UPDATE_MODE     1
-#define        QUEUE_UPDATE_MODE       2
-
-#define        DATA_TYPE_COMMON        0
-#define        DATA_TYPE_INFO          1
-#define        DATA_TYPE_STATE         2
-#define        DATA_TYPE_ALARM         3
-#define        DATA_TYPE_AC_STATE      4
-
-extern struct proc_dir_entry *acpi_lock_ac_dir(void);
-extern struct proc_dir_entry *acpi_lock_battery_dir(void);
-extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
-extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
-
 #define ACPI_SBS_COMPONENT             0x00080000
 #define ACPI_SBS_CLASS                 "sbs"
 #define ACPI_AC_CLASS                  "ac_adapter"
@@ -74,39 +54,75 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
 
 #define _COMPONENT                     ACPI_SBS_COMPONENT
 
-#define        MAX_SBS_BAT                     4
-#define        MAX_SMBUS_ERR                   1
-
 ACPI_MODULE_NAME("sbs");
 
 MODULE_AUTHOR("Rich Townsend");
 MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
 MODULE_LICENSE("GPL");
 
-static struct semaphore sbs_sem;
+#define        xmsleep(t)      msleep(t)
+
+#define ACPI_EC_SMB_PRTCL      0x00    /* protocol, PEC */
+
+#define ACPI_EC_SMB_STS                0x01    /* status */
+#define ACPI_EC_SMB_ADDR       0x02    /* address */
+#define ACPI_EC_SMB_CMD                0x03    /* command */
+#define ACPI_EC_SMB_DATA       0x04    /* 32 data registers */
+#define ACPI_EC_SMB_BCNT       0x24    /* number of data bytes */
 
-#define        UPDATE_MODE             QUEUE_UPDATE_MODE
-/* REQUEST_UPDATE_MODE  QUEUE_UPDATE_MODE */
-#define        UPDATE_INFO_MODE        0
-#define        UPDATE_TIME             60
-#define        UPDATE_TIME2            0
+#define ACPI_EC_SMB_STS_DONE   0x80
+#define ACPI_EC_SMB_STS_STATUS 0x1f
 
-static int capacity_mode = CAPACITY_UNIT;
-static int update_mode = UPDATE_MODE;
-static int update_info_mode = UPDATE_INFO_MODE;
-static int update_time = UPDATE_TIME;
-static int update_time2 = UPDATE_TIME2;
+#define ACPI_EC_SMB_PRTCL_WRITE                0x00
+#define ACPI_EC_SMB_PRTCL_READ         0x01
+#define ACPI_EC_SMB_PRTCL_WORD_DATA    0x08
+#define ACPI_EC_SMB_PRTCL_BLOCK_DATA   0x0a
 
-module_param(capacity_mode, int, 0);
-module_param(update_mode, int, 0);
-module_param(update_info_mode, int, 0);
-module_param(update_time, int, 0);
-module_param(update_time2, int, 0);
+#define ACPI_EC_SMB_TRANSACTION_SLEEP  1
+#define ACPI_EC_SMB_ACCESS_SLEEP1      1
+#define ACPI_EC_SMB_ACCESS_SLEEP2      10
+
+#define        DEF_CAPACITY_UNIT       3
+#define        MAH_CAPACITY_UNIT       1
+#define        MWH_CAPACITY_UNIT       2
+#define        CAPACITY_UNIT           DEF_CAPACITY_UNIT
+
+#define        REQUEST_UPDATE_MODE     1
+#define        QUEUE_UPDATE_MODE       2
+
+#define        DATA_TYPE_COMMON        0
+#define        DATA_TYPE_INFO          1
+#define        DATA_TYPE_STATE         2
+#define        DATA_TYPE_ALARM         3
+#define        DATA_TYPE_AC_STATE      4
+
+extern struct proc_dir_entry *acpi_lock_ac_dir(void);
+extern struct proc_dir_entry *acpi_lock_battery_dir(void);
+extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
+extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
+
+#define        MAX_SBS_BAT                     4
+#define ACPI_SBS_BLOCK_MAX             32
+
+#define ACPI_SBS_SMBUS_READ            1
+#define ACPI_SBS_SMBUS_WRITE           2
+
+#define ACPI_SBS_WORD_DATA             1
+#define ACPI_SBS_BLOCK_DATA            2
+
+#define        UPDATE_DELAY    10
+
+/* 0 - every time, > 0 - by update_time */
+static unsigned int update_time = 120;
+
+static unsigned int capacity_mode = CAPACITY_UNIT;
+
+module_param(update_time, uint, 0644);
+module_param(capacity_mode, uint, 0444);
 
 static int acpi_sbs_add(struct acpi_device *device);
 static int acpi_sbs_remove(struct acpi_device *device, int type);
-static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus);
-static void acpi_sbs_update_queue(void *data);
+static int acpi_sbs_resume(struct acpi_device *device);
 
 static struct acpi_driver acpi_sbs_driver = {
        .name = "sbs",
@@ -115,9 +131,14 @@ static struct acpi_driver acpi_sbs_driver = {
        .ops = {
                .add = acpi_sbs_add,
                .remove = acpi_sbs_remove,
+               .resume = acpi_sbs_resume,
                },
 };
 
+struct acpi_ac {
+       int ac_present;
+};
+
 struct acpi_battery_info {
        int capacity_mode;
        s16 full_charge_capacity;
@@ -126,18 +147,16 @@ struct acpi_battery_info {
        int vscale;
        int ipscale;
        s16 serial_number;
-       char manufacturer_name[I2C_SMBUS_BLOCK_MAX + 3];
-       char device_name[I2C_SMBUS_BLOCK_MAX + 3];
-       char device_chemistry[I2C_SMBUS_BLOCK_MAX + 3];
+       char manufacturer_name[ACPI_SBS_BLOCK_MAX + 3];
+       char device_name[ACPI_SBS_BLOCK_MAX + 3];
+       char device_chemistry[ACPI_SBS_BLOCK_MAX + 3];
 };
 
 struct acpi_battery_state {
        s16 voltage;
        s16 amperage;
        s16 remaining_capacity;
-       s16 average_time_to_empty;
-       s16 average_time_to_full;
-       s16 battery_status;
+       s16 battery_state;
 };
 
 struct acpi_battery_alarm {
@@ -146,9 +165,9 @@ struct acpi_battery_alarm {
 
 struct acpi_battery {
        int alive;
-       int battery_present;
        int id;
        int init_state;
+       int battery_present;
        struct acpi_sbs *sbs;
        struct acpi_battery_info info;
        struct acpi_battery_state state;
@@ -158,186 +177,251 @@ struct acpi_battery {
 
 struct acpi_sbs {
        acpi_handle handle;
+       int base;
        struct acpi_device *device;
        struct acpi_ec_smbus *smbus;
+       struct mutex mutex;
        int sbsm_present;
        int sbsm_batteries_supported;
-       int ac_present;
        struct proc_dir_entry *ac_entry;
+       struct acpi_ac ac;
        struct acpi_battery battery[MAX_SBS_BAT];
-       int update_info_mode;
        int zombie;
-       int update_time;
-       int update_time2;
        struct timer_list update_timer;
+       int run_cnt;
+       int update_proc_flg;
 };
 
-static void acpi_update_delay(struct acpi_sbs *sbs);
-static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type);
+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type);
+static void acpi_sbs_update_time(void *data);
+
+union sbs_rw_data {
+       u16 word;
+       u8 block[ACPI_SBS_BLOCK_MAX + 2];
+};
+
+static int acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
+                             char read_write, u8 command, int size,
+                             union sbs_rw_data *data);
 
 /* --------------------------------------------------------------------------
                                SMBus Communication
    -------------------------------------------------------------------------- */
 
-static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus)
+static int acpi_ec_sbs_read(struct acpi_sbs *sbs, u8 address, u8 * data)
 {
-       union i2c_smbus_data data;
-       int result = 0;
-       char *err_str;
-       int err_number;
+       u8 val;
+       int err;
 
-       data.word = 0;
+       err = ec_read(sbs->base + address, &val);
+       if (!err) {
+               *data = val;
+       }
+       xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
+       return (err);
+}
 
-       result = smbus->adapter.algo->
-           smbus_xfer(&smbus->adapter,
-                      ACPI_SB_SMBUS_ADDR,
-                      0, I2C_SMBUS_READ, 0x16, I2C_SMBUS_BLOCK_DATA, &data);
+static int acpi_ec_sbs_write(struct acpi_sbs *sbs, u8 address, u8 data)
+{
+       int err;
 
-       err_number = (data.word & 0x000f);
+       err = ec_write(sbs->base + address, data);
+       return (err);
+}
 
-       switch (data.word & 0x000f) {
-       case 0x0000:
-               err_str = "unexpected bus error";
-               break;
-       case 0x0001:
-               err_str = "busy";
-               break;
-       case 0x0002:
-               err_str = "reserved command";
-               break;
-       case 0x0003:
-               err_str = "unsupported command";
-               break;
-       case 0x0004:
-               err_str = "access denied";
+static int
+acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
+                  char read_write, u8 command, int size,
+                  union sbs_rw_data *data)
+{
+       unsigned char protocol, len = 0, temp[2] = { 0, 0 };
+       int i;
+
+       if (read_write == ACPI_SBS_SMBUS_READ) {
+               protocol = ACPI_EC_SMB_PRTCL_READ;
+       } else {
+               protocol = ACPI_EC_SMB_PRTCL_WRITE;
+       }
+
+       switch (size) {
+
+       case ACPI_SBS_WORD_DATA:
+               acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
+               if (read_write == ACPI_SBS_SMBUS_WRITE) {
+                       acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA, data->word);
+                       acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + 1,
+                                         data->word >> 8);
+               }
+               protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA;
                break;
-       case 0x0005:
-               err_str = "overflow/underflow";
+       case ACPI_SBS_BLOCK_DATA:
+               acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
+               if (read_write == ACPI_SBS_SMBUS_WRITE) {
+                       len = min_t(u8, data->block[0], 32);
+                       acpi_ec_sbs_write(sbs, ACPI_EC_SMB_BCNT, len);
+                       for (i = 0; i < len; i++)
+                               acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + i,
+                                                 data->block[i + 1]);
+               }
+               protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA;
                break;
-       case 0x0006:
-               err_str = "bad size";
+       default:
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "unsupported transaction %d", size));
+               return (-1);
+       }
+
+       acpi_ec_sbs_write(sbs, ACPI_EC_SMB_ADDR, addr << 1);
+       acpi_ec_sbs_write(sbs, ACPI_EC_SMB_PRTCL, protocol);
+
+       acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+
+       if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+               xmsleep(ACPI_EC_SMB_ACCESS_SLEEP1);
+               acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+       }
+       if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+               xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
+               acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+       }
+       if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
+           || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "transaction %d error", size));
+               return (-1);
+       }
+
+       if (read_write == ACPI_SBS_SMBUS_WRITE) {
+               return (0);
+       }
+
+       switch (size) {
+
+       case ACPI_SBS_WORD_DATA:
+               acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA, temp);
+               acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + 1, temp + 1);
+               data->word = (temp[1] << 8) | temp[0];
                break;
-       case 0x0007:
-               err_str = "unknown error";
+
+       case ACPI_SBS_BLOCK_DATA:
+               len = 0;
+               acpi_ec_sbs_read(sbs, ACPI_EC_SMB_BCNT, &len);
+               len = min_t(u8, len, 32);
+               for (i = 0; i < len; i++)
+                       acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + i,
+                                        data->block + i + 1);
+               data->block[0] = len;
                break;
        default:
-               err_str = "unrecognized error";
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "unsupported transaction %d", size));
+               return (-1);
        }
-       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                         "%s: ret %i, err %i\n", err_str, result, err_number));
+
+       return (0);
 }
 
 static int
-acpi_sbs_smbus_read_word(struct acpi_ec_smbus *smbus, int addr, int func,
-                        u16 * word,
-                        void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_read_word(struct acpi_sbs *sbs, int addr, int func, u16 * word)
 {
-       union i2c_smbus_data data;
+       union sbs_rw_data data;
        int result = 0;
-       int i;
 
-       if (err_handler == NULL) {
-               err_handler = acpi_battery_smbus_err_handler;
-       }
-
-       for (i = 0; i < MAX_SMBUS_ERR; i++) {
-               result =
-                   smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
-                                                   I2C_SMBUS_READ, func,
-                                                   I2C_SMBUS_WORD_DATA, &data);
-               if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
-                                         i));
-                       if (err_handler) {
-                               err_handler(smbus);
-                       }
-               } else {
-                       *word = data.word;
-                       break;
-               }
+       result = acpi_ec_sbs_access(sbs, addr,
+                                   ACPI_SBS_SMBUS_READ, func,
+                                   ACPI_SBS_WORD_DATA, &data);
+       if (result) {
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_ec_sbs_access() failed"));
+       } else {
+               *word = data.word;
        }
 
        return result;
 }
 
 static int
-acpi_sbs_smbus_read_str(struct acpi_ec_smbus *smbus, int addr, int func,
-                       char *str,
-                       void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_read_str(struct acpi_sbs *sbs, int addr, int func, char *str)
 {
-       union i2c_smbus_data data;
+       union sbs_rw_data data;
        int result = 0;
-       int i;
-
-       if (err_handler == NULL) {
-               err_handler = acpi_battery_smbus_err_handler;
-       }
 
-       for (i = 0; i < MAX_SMBUS_ERR; i++) {
-               result =
-                   smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
-                                                   I2C_SMBUS_READ, func,
-                                                   I2C_SMBUS_BLOCK_DATA,
-                                                   &data);
-               if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
-                                         i));
-                       if (err_handler) {
-                               err_handler(smbus);
-                       }
-               } else {
-                       strncpy(str, (const char *)data.block + 1,
-                               data.block[0]);
-                       str[data.block[0]] = 0;
-                       break;
-               }
+       result = acpi_ec_sbs_access(sbs, addr,
+                                   ACPI_SBS_SMBUS_READ, func,
+                                   ACPI_SBS_BLOCK_DATA, &data);
+       if (result) {
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_ec_sbs_access() failed"));
+       } else {
+               strncpy(str, (const char *)data.block + 1, data.block[0]);
+               str[data.block[0]] = 0;
        }
 
        return result;
 }
 
 static int
-acpi_sbs_smbus_write_word(struct acpi_ec_smbus *smbus, int addr, int func,
-                         int word,
-                         void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_write_word(struct acpi_sbs *sbs, int addr, int func, int word)
 {
-       union i2c_smbus_data data;
+       union sbs_rw_data data;
        int result = 0;
-       int i;
-
-       if (err_handler == NULL) {
-               err_handler = acpi_battery_smbus_err_handler;
-       }
 
        data.word = word;
 
-       for (i = 0; i < MAX_SMBUS_ERR; i++) {
-               result =
-                   smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
-                                                   I2C_SMBUS_WRITE, func,
-                                                   I2C_SMBUS_WORD_DATA, &data);
-               if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "try %i: smbus->adapter.algo"
-                                         "->smbus_xfer() failed\n", i));
-                       if (err_handler) {
-                               err_handler(smbus);
-                       }
-               } else {
-                       break;
-               }
+       result = acpi_ec_sbs_access(sbs, addr,
+                                   ACPI_SBS_SMBUS_WRITE, func,
+                                   ACPI_SBS_WORD_DATA, &data);
+       if (result) {
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_ec_sbs_access() failed"));
        }
 
        return result;
 }
 
+static int sbs_zombie(struct acpi_sbs *sbs)
+{
+       return (sbs->zombie);
+}
+
+static int sbs_mutex_lock(struct acpi_sbs *sbs)
+{
+       if (sbs_zombie(sbs)) {
+               return -ENODEV;
+       }
+       mutex_lock(&sbs->mutex);
+       return 0;
+}
+
+static void sbs_mutex_unlock(struct acpi_sbs *sbs)
+{
+       mutex_unlock(&sbs->mutex);
+}
+
 /* --------------------------------------------------------------------------
                             Smart Battery System Management
    -------------------------------------------------------------------------- */
 
-/* Smart Battery */
+static int acpi_check_update_proc(struct acpi_sbs *sbs)
+{
+       acpi_status status = AE_OK;
+
+       if (update_time == 0) {
+               sbs->update_proc_flg = 0;
+               return 0;
+       }
+       if (sbs->update_proc_flg == 0) {
+               status = acpi_os_execute(OSL_GPE_HANDLER,
+                                        acpi_sbs_update_time, sbs);
+               if (status != AE_OK) {
+                       ACPI_EXCEPTION((AE_INFO, status,
+                                       "acpi_os_execute() failed"));
+                       return 1;
+               }
+               sbs->update_proc_flg = 1;
+       }
+       return 0;
+}
 
 static int acpi_sbs_generate_event(struct acpi_device *device,
                                   int event, int state, char *bid, char *class)
@@ -366,12 +450,11 @@ static int acpi_battery_get_present(struct acpi_battery *battery)
        int result = 0;
        int is_present = 0;
 
-       result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
-                                         ACPI_SBSM_SMBUS_ADDR, 0x01,
-                                         &state, NULL);
+       result = acpi_sbs_read_word(battery->sbs,
+                                   ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
        }
        if (!result) {
                is_present = (state & 0x000f) & (1 << battery->id);
@@ -381,45 +464,33 @@ static int acpi_battery_get_present(struct acpi_battery *battery)
        return result;
 }
 
-static int acpi_battery_is_present(struct acpi_battery *battery)
-{
-       return (battery->battery_present);
-}
-
-static int acpi_ac_is_present(struct acpi_sbs *sbs)
-{
-       return (sbs->ac_present);
-}
-
 static int acpi_battery_select(struct acpi_battery *battery)
 {
-       struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+       struct acpi_sbs *sbs = battery->sbs;
        int result = 0;
        s16 state;
        int foo;
 
-       if (battery->sbs->sbsm_present) {
+       if (sbs->sbsm_present) {
 
                /* Take special care not to knobble other nibbles of
                 * state (aka selector_state), since
                 * it causes charging to halt on SBSELs */
 
                result =
-                   acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
-                                            &state, NULL);
+                   acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbs_smbus_read_word() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbs_read_word() failed"));
                        goto end;
                }
 
                foo = (state & 0x0fff) | (1 << (battery->id + 12));
                result =
-                   acpi_sbs_smbus_write_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
-                                             foo, NULL);
+                   acpi_sbs_write_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, foo);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbs_smbus_write_word() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbs_write_word() failed"));
                        goto end;
                }
        }
@@ -430,15 +501,14 @@ static int acpi_battery_select(struct acpi_battery *battery)
 
 static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
 {
-       struct acpi_ec_smbus *smbus = sbs->smbus;
        int result = 0;
        s16 battery_system_info;
 
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x04,
-                                         &battery_system_info, NULL);
+       result = acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x04,
+                                   &battery_system_info);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
@@ -451,53 +521,50 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
 
 static int acpi_battery_get_info(struct acpi_battery *battery)
 {
-       struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+       struct acpi_sbs *sbs = battery->sbs;
        int result = 0;
        s16 battery_mode;
        s16 specification_info;
 
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
-                                         &battery_mode,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
+                                   &battery_mode);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
        battery->info.capacity_mode = (battery_mode & 0x8000) >> 15;
 
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x10,
-                                         &battery->info.full_charge_capacity,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x10,
+                                   &battery->info.full_charge_capacity);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x18,
-                                         &battery->info.design_capacity,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x18,
+                                   &battery->info.design_capacity);
 
        if (result) {
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x19,
-                                         &battery->info.design_voltage,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x19,
+                                   &battery->info.design_voltage);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1a,
-                                         &specification_info,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1a,
+                                   &specification_info);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
@@ -529,37 +596,35 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
                battery->info.ipscale = 1;
        }
 
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1c,
-                                         &battery->info.serial_number,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1c,
+                                   &battery->info.serial_number);
        if (result) {
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
-       result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x20,
-                                        battery->info.manufacturer_name,
-                                        &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x20,
+                                  battery->info.manufacturer_name);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_str() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_str() failed"));
                goto end;
        }
 
-       result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x21,
-                                        battery->info.device_name,
-                                        &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x21,
+                                  battery->info.device_name);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_str() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_str() failed"));
                goto end;
        }
 
-       result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x22,
-                                        battery->info.device_chemistry,
-                                        &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x22,
+                                  battery->info.device_chemistry);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_str() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_str() failed"));
                goto end;
        }
 
@@ -567,103 +632,60 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
        return result;
 }
 
-static void acpi_update_delay(struct acpi_sbs *sbs)
-{
-       if (sbs->zombie) {
-               return;
-       }
-       if (sbs->update_time2 > 0) {
-               msleep(sbs->update_time2 * 1000);
-       }
-}
-
 static int acpi_battery_get_state(struct acpi_battery *battery)
 {
-       struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+       struct acpi_sbs *sbs = battery->sbs;
        int result = 0;
 
-       acpi_update_delay(battery->sbs);
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x09,
-                                         &battery->state.voltage,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x09,
+                                   &battery->state.voltage);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
-       acpi_update_delay(battery->sbs);
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0a,
-                                         &battery->state.amperage,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0a,
+                                   &battery->state.amperage);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
-       acpi_update_delay(battery->sbs);
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0f,
-                                         &battery->state.remaining_capacity,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0f,
+                                   &battery->state.remaining_capacity);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
-       acpi_update_delay(battery->sbs);
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x12,
-                                         &battery->state.average_time_to_empty,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x16,
+                                   &battery->state.battery_state);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
-       acpi_update_delay(battery->sbs);
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x13,
-                                         &battery->state.average_time_to_full,
-                                         &acpi_battery_smbus_err_handler);
-       if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
-               goto end;
-       }
-
-       acpi_update_delay(battery->sbs);
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x16,
-                                         &battery->state.battery_status,
-                                         &acpi_battery_smbus_err_handler);
-       if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
-               goto end;
-       }
-
-       acpi_update_delay(battery->sbs);
-
       end:
        return result;
 }
 
 static int acpi_battery_get_alarm(struct acpi_battery *battery)
 {
-       struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+       struct acpi_sbs *sbs = battery->sbs;
        int result = 0;
 
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
-                                         &battery->alarm.remaining_capacity,
-                                         &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
+                                   &battery->alarm.remaining_capacity);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
-       acpi_update_delay(battery->sbs);
-
       end:
 
        return result;
@@ -672,15 +694,15 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery)
 static int acpi_battery_set_alarm(struct acpi_battery *battery,
                                  unsigned long alarm)
 {
-       struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+       struct acpi_sbs *sbs = battery->sbs;
        int result = 0;
        s16 battery_mode;
        int foo;
 
        result = acpi_battery_select(battery);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_battery_select() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_battery_select() failed"));
                goto end;
        }
 
@@ -688,33 +710,29 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,
 
        if (alarm > 0) {
                result =
-                   acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
-                                            &battery_mode,
-                                            &acpi_battery_smbus_err_handler);
+                   acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
+                                      &battery_mode);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbs_smbus_read_word() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbs_read_word() failed"));
                        goto end;
                }
 
                result =
-                   acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
-                                             battery_mode & 0xbfff,
-                                             &acpi_battery_smbus_err_handler);
+                   acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
+                                       battery_mode & 0xbfff);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbs_smbus_write_word() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbs_write_word() failed"));
                        goto end;
                }
        }
 
        foo = alarm / (battery->info.capacity_mode ? 10 : 1);
-       result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
-                                          foo,
-                                          &acpi_battery_smbus_err_handler);
+       result = acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, foo);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_write_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_write_word() failed"));
                goto end;
        }
 
@@ -725,6 +743,7 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,
 
 static int acpi_battery_set_mode(struct acpi_battery *battery)
 {
+       struct acpi_sbs *sbs = battery->sbs;
        int result = 0;
        s16 battery_mode;
 
@@ -732,12 +751,11 @@ static int acpi_battery_set_mode(struct acpi_battery *battery)
                goto end;
        }
 
-       result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
-                                         ACPI_SB_SMBUS_ADDR, 0x03,
-                                         &battery_mode, NULL);
+       result = acpi_sbs_read_word(sbs,
+                                   ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
@@ -746,21 +764,19 @@ static int acpi_battery_set_mode(struct acpi_battery *battery)
        } else {
                battery_mode |= 0x8000;
        }
-       result = acpi_sbs_smbus_write_word(battery->sbs->smbus,
-                                          ACPI_SB_SMBUS_ADDR, 0x03,
-                                          battery_mode, NULL);
+       result = acpi_sbs_write_word(sbs,
+                                    ACPI_SB_SMBUS_ADDR, 0x03, battery_mode);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_write_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_write_word() failed"));
                goto end;
        }
 
-       result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
-                                         ACPI_SB_SMBUS_ADDR, 0x03,
-                                         &battery_mode, NULL);
+       result = acpi_sbs_read_word(sbs,
+                                   ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
@@ -774,36 +790,36 @@ static int acpi_battery_init(struct acpi_battery *battery)
 
        result = acpi_battery_select(battery);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_battery_init() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_battery_select() failed"));
                goto end;
        }
 
        result = acpi_battery_set_mode(battery);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_battery_set_mode() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_battery_set_mode() failed"));
                goto end;
        }
 
        result = acpi_battery_get_info(battery);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_battery_get_info() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_battery_get_info() failed"));
                goto end;
        }
 
        result = acpi_battery_get_state(battery);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_battery_get_state() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_battery_get_state() failed"));
                goto end;
        }
 
        result = acpi_battery_get_alarm(battery);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_battery_get_alarm() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_battery_get_alarm() failed"));
                goto end;
        }
 
@@ -813,20 +829,19 @@ static int acpi_battery_init(struct acpi_battery *battery)
 
 static int acpi_ac_get_present(struct acpi_sbs *sbs)
 {
-       struct acpi_ec_smbus *smbus = sbs->smbus;
        int result = 0;
        s16 charger_status;
 
-       result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x13,
-                                         &charger_status, NULL);
+       result = acpi_sbs_read_word(sbs, ACPI_SBC_SMBUS_ADDR, 0x13,
+                                   &charger_status);
 
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_smbus_read_word() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_read_word() failed"));
                goto end;
        }
 
-       sbs->ac_present = (charger_status & 0x8000) >> 15;
+       sbs->ac.ac_present = (charger_status & 0x8000) >> 15;
 
       end:
 
@@ -852,8 +867,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
        if (!*dir) {
                *dir = proc_mkdir(dir_name, parent_dir);
                if (!*dir) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "proc_mkdir() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "proc_mkdir() failed"));
                        return -ENODEV;
                }
                (*dir)->owner = THIS_MODULE;
@@ -863,8 +878,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
        if (info_fops) {
                entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
                if (!entry) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "create_proc_entry() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "create_proc_entry() failed"));
                } else {
                        entry->proc_fops = info_fops;
                        entry->data = data;
@@ -876,8 +891,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
        if (state_fops) {
                entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
                if (!entry) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "create_proc_entry() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "create_proc_entry() failed"));
                } else {
                        entry->proc_fops = state_fops;
                        entry->data = data;
@@ -889,8 +904,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
        if (alarm_fops) {
                entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
                if (!entry) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "create_proc_entry() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "create_proc_entry() failed"));
                } else {
                        entry->proc_fops = alarm_fops;
                        entry->data = data;
@@ -923,24 +938,27 @@ static struct proc_dir_entry *acpi_battery_dir = NULL;
 static int acpi_battery_read_info(struct seq_file *seq, void *offset)
 {
        struct acpi_battery *battery = seq->private;
+       struct acpi_sbs *sbs = battery->sbs;
        int cscale;
        int result = 0;
 
-       if (battery->sbs->zombie) {
+       if (sbs_mutex_lock(sbs)) {
                return -ENODEV;
        }
 
-       down(&sbs_sem);
+       result = acpi_check_update_proc(sbs);
+       if (result)
+               goto end;
 
-       if (update_mode == REQUEST_UPDATE_MODE) {
-               result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_INFO);
+       if (update_time == 0) {
+               result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_INFO);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbs_update_run() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbs_update_run() failed"));
                }
        }
 
-       if (acpi_battery_is_present(battery)) {
+       if (battery->battery_present) {
                seq_printf(seq, "present:                 yes\n");
        } else {
                seq_printf(seq, "present:                 no\n");
@@ -952,13 +970,13 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
        } else {
                cscale = battery->info.ipscale;
        }
-       seq_printf(seq, "design capacity:         %i%s",
+       seq_printf(seq, "design capacity:         %i%s\n",
                   battery->info.design_capacity * cscale,
-                  battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+                  battery->info.capacity_mode ? "0 mWh" : " mAh");
 
-       seq_printf(seq, "last full capacity:      %i%s",
+       seq_printf(seq, "last full capacity:      %i%s\n",
                   battery->info.full_charge_capacity * cscale,
-                  battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+                  battery->info.capacity_mode ? "0 mWh" : " mAh");
 
        seq_printf(seq, "battery technology:      rechargeable\n");
 
@@ -984,7 +1002,7 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
 
       end:
 
-       up(&sbs_sem);
+       sbs_mutex_unlock(sbs);
 
        return result;
 }
@@ -996,26 +1014,29 @@ static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
 
 static int acpi_battery_read_state(struct seq_file *seq, void *offset)
 {
-       struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+       struct acpi_battery *battery = seq->private;
+       struct acpi_sbs *sbs = battery->sbs;
        int result = 0;
        int cscale;
        int foo;
 
-       if (battery->sbs->zombie) {
+       if (sbs_mutex_lock(sbs)) {
                return -ENODEV;
        }
 
-       down(&sbs_sem);
+       result = acpi_check_update_proc(sbs);
+       if (result)
+               goto end;
 
-       if (update_mode == REQUEST_UPDATE_MODE) {
-               result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_STATE);
+       if (update_time == 0) {
+               result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_STATE);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbs_update_run() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbs_update_run() failed"));
                }
        }
 
-       if (acpi_battery_is_present(battery)) {
+       if (battery->battery_present) {
                seq_printf(seq, "present:                 yes\n");
        } else {
                seq_printf(seq, "present:                 no\n");
@@ -1028,7 +1049,7 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
                cscale = battery->info.ipscale;
        }
 
-       if (battery->state.battery_status & 0x0010) {
+       if (battery->state.battery_state & 0x0010) {
                seq_printf(seq, "capacity state:          critical\n");
        } else {
                seq_printf(seq, "capacity state:          ok\n");
@@ -1052,16 +1073,16 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
                           battery->info.capacity_mode ? "mW" : "mA");
        }
 
-       seq_printf(seq, "remaining capacity:      %i%s",
+       seq_printf(seq, "remaining capacity:      %i%s\n",
                   battery->state.remaining_capacity * cscale,
-                  battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+                  battery->info.capacity_mode ? "0 mWh" : " mAh");
 
        seq_printf(seq, "present voltage:         %i mV\n",
                   battery->state.voltage * battery->info.vscale);
 
       end:
 
-       up(&sbs_sem);
+       sbs_mutex_unlock(sbs);
 
        return result;
 }
@@ -1074,24 +1095,27 @@ static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
 static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
 {
        struct acpi_battery *battery = seq->private;
+       struct acpi_sbs *sbs = battery->sbs;
        int result = 0;
        int cscale;
 
-       if (battery->sbs->zombie) {
+       if (sbs_mutex_lock(sbs)) {
                return -ENODEV;
        }
 
-       down(&sbs_sem);
+       result = acpi_check_update_proc(sbs);
+       if (result)
+               goto end;
 
-       if (update_mode == REQUEST_UPDATE_MODE) {
-               result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_ALARM);
+       if (update_time == 0) {
+               result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_ALARM);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbs_update_run() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbs_update_run() failed"));
                }
        }
 
-       if (!acpi_battery_is_present(battery)) {
+       if (!battery->battery_present) {
                seq_printf(seq, "present:                 no\n");
                goto end;
        }
@@ -1104,16 +1128,16 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
 
        seq_printf(seq, "alarm:                   ");
        if (battery->alarm.remaining_capacity) {
-               seq_printf(seq, "%i%s",
+               seq_printf(seq, "%i%s\n",
                           battery->alarm.remaining_capacity * cscale,
-                          battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+                          battery->info.capacity_mode ? "0 mWh" : " mAh");
        } else {
                seq_printf(seq, "disabled\n");
        }
 
       end:
 
-       up(&sbs_sem);
+       sbs_mutex_unlock(sbs);
 
        return result;
 }
@@ -1124,16 +1148,19 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer,
 {
        struct seq_file *seq = file->private_data;
        struct acpi_battery *battery = seq->private;
+       struct acpi_sbs *sbs = battery->sbs;
        char alarm_string[12] = { '\0' };
        int result, old_alarm, new_alarm;
 
-       if (battery->sbs->zombie) {
+       if (sbs_mutex_lock(sbs)) {
                return -ENODEV;
        }
 
-       down(&sbs_sem);
+       result = acpi_check_update_proc(sbs);
+       if (result)
+               goto end;
 
-       if (!acpi_battery_is_present(battery)) {
+       if (!battery->battery_present) {
                result = -ENODEV;
                goto end;
        }
@@ -1155,21 +1182,21 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer,
 
        result = acpi_battery_set_alarm(battery, new_alarm);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_battery_set_alarm() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_battery_set_alarm() failed"));
                acpi_battery_set_alarm(battery, old_alarm);
                goto end;
        }
        result = acpi_battery_get_alarm(battery);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_battery_get_alarm() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_battery_get_alarm() failed"));
                acpi_battery_set_alarm(battery, old_alarm);
                goto end;
        }
 
       end:
-       up(&sbs_sem);
+       sbs_mutex_unlock(sbs);
 
        if (result) {
                return result;
@@ -1217,24 +1244,22 @@ static int acpi_ac_read_state(struct seq_file *seq, void *offset)
        struct acpi_sbs *sbs = seq->private;
        int result;
 
-       if (sbs->zombie) {
+       if (sbs_mutex_lock(sbs)) {
                return -ENODEV;
        }
 
-       down(&sbs_sem);
-
-       if (update_mode == REQUEST_UPDATE_MODE) {
-               result = acpi_sbs_update_run(sbs, DATA_TYPE_AC_STATE);
+       if (update_time == 0) {
+               result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_AC_STATE);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbs_update_run() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbs_update_run() failed"));
                }
        }
 
        seq_printf(seq, "state:                   %s\n",
-                  sbs->ac_present ? "on-line" : "off-line");
+                  sbs->ac.ac_present ? "on-line" : "off-line");
 
-       up(&sbs_sem);
+       sbs_mutex_unlock(sbs);
 
        return 0;
 }
@@ -1275,25 +1300,25 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
 
        result = acpi_battery_select(battery);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_battery_select() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_battery_select() failed"));
                goto end;
        }
 
        result = acpi_battery_get_present(battery);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_battery_get_present() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_battery_get_present() failed"));
                goto end;
        }
 
-       is_present = acpi_battery_is_present(battery);
+       is_present = battery->battery_present;
 
        if (is_present) {
                result = acpi_battery_init(battery);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_battery_init() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_battery_init() failed"));
                        goto end;
                }
                battery->init_state = 1;
@@ -1308,12 +1333,16 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
                                         &acpi_battery_state_fops,
                                         &acpi_battery_alarm_fops, battery);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_generic_add_fs() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_generic_add_fs() failed"));
                goto end;
        }
        battery->alive = 1;
 
+       printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
+              ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), dir_name,
+              sbs->battery->battery_present ? "present" : "absent");
+
       end:
        return result;
 }
@@ -1333,8 +1362,8 @@ static int acpi_ac_add(struct acpi_sbs *sbs)
 
        result = acpi_ac_get_present(sbs);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_ac_get_present() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_ac_get_present() failed"));
                goto end;
        }
 
@@ -1343,11 +1372,15 @@ static int acpi_ac_add(struct acpi_sbs *sbs)
                                         ACPI_AC_DIR_NAME,
                                         NULL, &acpi_ac_state_fops, NULL, sbs);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_generic_add_fs() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_generic_add_fs() failed"));
                goto end;
        }
 
+       printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
+              ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
+              ACPI_AC_DIR_NAME, sbs->ac.ac_present ? "on-line" : "off-line");
+
       end:
 
        return result;
@@ -1361,45 +1394,85 @@ static void acpi_ac_remove(struct acpi_sbs *sbs)
        }
 }
 
-static void acpi_sbs_update_queue_run(unsigned long data)
+static void acpi_sbs_update_time_run(unsigned long data)
 {
-       acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_queue, (void *)data);
+       acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_time, (void *)data);
 }
 
-static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type)
 {
        struct acpi_battery *battery;
-       int result = 0;
-       int old_ac_present;
-       int old_battery_present;
-       int new_ac_present;
-       int new_battery_present;
-       int id;
+       int result = 0, cnt;
+       int old_ac_present = -1;
+       int old_battery_present = -1;
+       int new_ac_present = -1;
+       int new_battery_present = -1;
+       int id_min = 0, id_max = MAX_SBS_BAT - 1;
        char dir_name[32];
-       int do_battery_init, do_ac_init;
-       s16 old_remaining_capacity;
+       int do_battery_init = 0, do_ac_init = 0;
+       int old_remaining_capacity = 0;
+       int update_ac = 1, update_battery = 1;
+       int up_tm = update_time;
 
-       if (sbs->zombie) {
+       if (sbs_zombie(sbs)) {
                goto end;
        }
 
-       old_ac_present = acpi_ac_is_present(sbs);
+       if (id >= 0) {
+               id_min = id_max = id;
+       }
+
+       if (data_type == DATA_TYPE_COMMON && up_tm > 0) {
+               cnt = up_tm / (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm);
+               if (sbs->run_cnt % cnt != 0) {
+                       update_battery = 0;
+               }
+       }
+
+       sbs->run_cnt++;
+
+       if (!update_ac && !update_battery) {
+               goto end;
+       }
+
+       old_ac_present = sbs->ac.ac_present;
 
        result = acpi_ac_get_present(sbs);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_ac_get_present() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_ac_get_present() failed"));
        }
 
-       new_ac_present = acpi_ac_is_present(sbs);
+       new_ac_present = sbs->ac.ac_present;
 
        do_ac_init = (old_ac_present != new_ac_present);
+       if (sbs->run_cnt == 1 && data_type == DATA_TYPE_COMMON) {
+               do_ac_init = 1;
+       }
 
-       if (data_type == DATA_TYPE_AC_STATE) {
+       if (do_ac_init) {
+               result = acpi_sbs_generate_event(sbs->device,
+                                                ACPI_SBS_AC_NOTIFY_STATUS,
+                                                new_ac_present,
+                                                ACPI_AC_DIR_NAME,
+                                                ACPI_AC_CLASS);
+               if (result) {
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbs_generate_event() failed"));
+               }
+       }
+
+       if (data_type == DATA_TYPE_COMMON) {
+               if (!do_ac_init && !update_battery) {
+                       goto end;
+               }
+       }
+
+       if (data_type == DATA_TYPE_AC_STATE && !do_ac_init) {
                goto end;
        }
 
-       for (id = 0; id < MAX_SBS_BAT; id++) {
+       for (id = id_min; id <= id_max; id++) {
                battery = &sbs->battery[id];
                if (battery->alive == 0) {
                        continue;
@@ -1407,94 +1480,92 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
 
                old_remaining_capacity = battery->state.remaining_capacity;
 
-               old_battery_present = acpi_battery_is_present(battery);
+               old_battery_present = battery->battery_present;
 
                result = acpi_battery_select(battery);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_battery_select() failed\n"));
-               }
-               if (sbs->zombie) {
-                       goto end;
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_battery_select() failed"));
                }
 
                result = acpi_battery_get_present(battery);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_battery_get_present() failed\n"));
-               }
-               if (sbs->zombie) {
-                       goto end;
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_battery_get_present() failed"));
                }
 
-               new_battery_present = acpi_battery_is_present(battery);
+               new_battery_present = battery->battery_present;
 
                do_battery_init = ((old_battery_present != new_battery_present)
                                   && new_battery_present);
-
-               if (sbs->zombie) {
+               if (!new_battery_present)
+                       goto event;
+               if (do_ac_init || do_battery_init) {
+                       result = acpi_battery_init(battery);
+                       if (result) {
+                               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                               "acpi_battery_init() "
+                                               "failed"));
+                       }
+               }
+               if (sbs_zombie(sbs)) {
                        goto end;
                }
-               if (do_ac_init || do_battery_init ||
-                   update_info_mode || sbs->update_info_mode) {
-                       if (sbs->update_info_mode) {
-                               sbs->update_info_mode = 0;
-                       } else {
-                               sbs->update_info_mode = 1;
-                       }
-                       result = acpi_battery_init(battery);
+
+               if ((data_type == DATA_TYPE_COMMON
+                    || data_type == DATA_TYPE_INFO)
+                   && new_battery_present) {
+                       result = acpi_battery_get_info(battery);
                        if (result) {
-                               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                                 "acpi_battery_init() "
-                                                 "failed\n"));
+                               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                               "acpi_battery_get_info() failed"));
                        }
                }
                if (data_type == DATA_TYPE_INFO) {
                        continue;
                }
-
-               if (sbs->zombie) {
+               if (sbs_zombie(sbs)) {
                        goto end;
                }
-               if (new_battery_present) {
-                       result = acpi_battery_get_alarm(battery);
-                       if (result) {
-                               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                                 "acpi_battery_get_alarm() "
-                                                 "failed\n"));
-                       }
-                       if (data_type == DATA_TYPE_ALARM) {
-                               continue;
-                       }
 
+               if ((data_type == DATA_TYPE_COMMON
+                    || data_type == DATA_TYPE_STATE)
+                   && new_battery_present) {
                        result = acpi_battery_get_state(battery);
                        if (result) {
-                               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                                 "acpi_battery_get_state() "
-                                                 "failed\n"));
+                               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                               "acpi_battery_get_state() failed"));
                        }
                }
-               if (sbs->zombie) {
-                       goto end;
+               if (data_type == DATA_TYPE_STATE) {
+                       goto event;
                }
-               if (data_type != DATA_TYPE_COMMON) {
-                       continue;
+               if (sbs_zombie(sbs)) {
+                       goto end;
                }
 
-               if (old_battery_present != new_battery_present) {
-                       sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
-                       result = acpi_sbs_generate_event(sbs->device,
-                                                        ACPI_SBS_BATTERY_NOTIFY_STATUS,
-                                                        new_battery_present,
-                                                        dir_name,
-                                                        ACPI_BATTERY_CLASS);
+               if ((data_type == DATA_TYPE_COMMON
+                    || data_type == DATA_TYPE_ALARM)
+                   && new_battery_present) {
+                       result = acpi_battery_get_alarm(battery);
                        if (result) {
-                               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                                 "acpi_sbs_generate_event() "
-                                                 "failed\n"));
+                               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                               "acpi_battery_get_alarm() "
+                                               "failed"));
                        }
                }
-               if (old_remaining_capacity != battery->state.remaining_capacity) {
+               if (data_type == DATA_TYPE_ALARM) {
+                       continue;
+               }
+               if (sbs_zombie(sbs)) {
+                       goto end;
+               }
+
+             event:
+
+               if (old_battery_present != new_battery_present || do_ac_init ||
+                   old_remaining_capacity !=
+                   battery->state.remaining_capacity) {
                        sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
                        result = acpi_sbs_generate_event(sbs->device,
                                                         ACPI_SBS_BATTERY_NOTIFY_STATUS,
@@ -1502,138 +1573,120 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
                                                         dir_name,
                                                         ACPI_BATTERY_CLASS);
                        if (result) {
-                               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                                 "acpi_sbs_generate_event() failed\n"));
+                               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                               "acpi_sbs_generate_event() "
+                                               "failed"));
                        }
                }
-
-       }
-       if (sbs->zombie) {
-               goto end;
-       }
-       if (data_type != DATA_TYPE_COMMON) {
-               goto end;
-       }
-
-       if (old_ac_present != new_ac_present) {
-               result = acpi_sbs_generate_event(sbs->device,
-                                                ACPI_SBS_AC_NOTIFY_STATUS,
-                                                new_ac_present,
-                                                ACPI_AC_DIR_NAME,
-                                                ACPI_AC_CLASS);
-               if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbs_generate_event() failed\n"));
-               }
        }
 
       end:
+
        return result;
 }
 
-static void acpi_sbs_update_queue(void *data)
+static void acpi_sbs_update_time(void *data)
 {
        struct acpi_sbs *sbs = data;
        unsigned long delay = -1;
        int result;
+       unsigned int up_tm = update_time;
 
-       if (sbs->zombie) {
-               goto end;
-       }
+       if (sbs_mutex_lock(sbs))
+               return;
 
-       result = acpi_sbs_update_run(sbs, DATA_TYPE_COMMON);
+       result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_COMMON);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_sbs_update_run() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_sbs_update_run() failed"));
        }
 
-       if (sbs->zombie) {
+       if (sbs_zombie(sbs)) {
                goto end;
        }
 
-       if (update_mode == REQUEST_UPDATE_MODE) {
-               goto end;
+       if (!up_tm) {
+               if (timer_pending(&sbs->update_timer))
+                       del_timer(&sbs->update_timer);
+       } else {
+               delay = (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm);
+               delay = jiffies + HZ * delay;
+               if (timer_pending(&sbs->update_timer)) {
+                       mod_timer(&sbs->update_timer, delay);
+               } else {
+                       sbs->update_timer.data = (unsigned long)data;
+                       sbs->update_timer.function = acpi_sbs_update_time_run;
+                       sbs->update_timer.expires = delay;
+                       add_timer(&sbs->update_timer);
+               }
        }
 
-       delay = jiffies + HZ * update_time;
-       sbs->update_timer.data = (unsigned long)data;
-       sbs->update_timer.function = acpi_sbs_update_queue_run;
-       sbs->update_timer.expires = delay;
-       add_timer(&sbs->update_timer);
       end:
-       ;
+
+       sbs_mutex_unlock(sbs);
 }
 
 static int acpi_sbs_add(struct acpi_device *device)
 {
        struct acpi_sbs *sbs = NULL;
-       struct acpi_ec_hc *ec_hc = NULL;
-       int result, remove_result = 0;
+       int result = 0, remove_result = 0;
        unsigned long sbs_obj;
-       int id, cnt;
+       int id;
        acpi_status status = AE_OK;
+       unsigned long val;
+
+       status =
+           acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
+               return -EIO;
+       }
 
        sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
        if (!sbs) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));
-               return -ENOMEM;
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR, "kzalloc() failed"));
+               result = -ENOMEM;
+               goto end;
        }
 
-       cnt = 0;
-       while (cnt < 10) {
-               cnt++;
-               ec_hc = acpi_get_ec_hc(device);
-               if (ec_hc) {
-                       break;
-               }
-               msleep(1000);
-       }
+       mutex_init(&sbs->mutex);
 
-       if (!ec_hc) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_get_ec_hc() failed: "
-                                 "NO driver found for EC HC SMBus\n"));
-               result = -ENODEV;
-               goto end;
-       }
+       sbs_mutex_lock(sbs);
 
+       sbs->base = (val & 0xff00ull) >> 8;
        sbs->device = device;
-       sbs->smbus = ec_hc->smbus;
 
        strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
        acpi_driver_data(device) = sbs;
 
-       sbs->update_time = 0;
-       sbs->update_time2 = 0;
-
        result = acpi_ac_add(sbs);
        if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_ac_add() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
                goto end;
        }
-       result = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
-       if (ACPI_FAILURE(result)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_evaluate_integer() failed\n"));
+       status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
+       if (status) {
+               ACPI_EXCEPTION((AE_INFO, status,
+                               "acpi_evaluate_integer() failed"));
                result = -EIO;
                goto end;
        }
-
        if (sbs_obj > 0) {
                result = acpi_sbsm_get_info(sbs);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbsm_get_info() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbsm_get_info() failed"));
                        goto end;
                }
                sbs->sbsm_present = 1;
        }
+
        if (sbs->sbsm_present == 0) {
                result = acpi_battery_add(sbs, 0);
                if (result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_battery_add() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_battery_add() failed"));
                        goto end;
                }
        } else {
@@ -1641,9 +1694,8 @@ static int acpi_sbs_add(struct acpi_device *device)
                        if ((sbs->sbsm_batteries_supported & (1 << id))) {
                                result = acpi_battery_add(sbs, id);
                                if (result) {
-                                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                                         "acpi_battery_add() "
-                                                         "failed\n"));
+                                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                                       "acpi_battery_add() failed"));
                                        goto end;
                                }
                        }
@@ -1653,33 +1705,26 @@ static int acpi_sbs_add(struct acpi_device *device)
        sbs->handle = device->handle;
 
        init_timer(&sbs->update_timer);
-       if (update_mode == QUEUE_UPDATE_MODE) {
-               status = acpi_os_execute(OSL_GPE_HANDLER,
-                                        acpi_sbs_update_queue, sbs);
-               if (status != AE_OK) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_os_execute() failed\n"));
-               }
-       }
-       sbs->update_time = update_time;
-       sbs->update_time2 = update_time2;
-
-       printk(KERN_INFO PREFIX "%s [%s]\n",
-              acpi_device_name(device), acpi_device_bid(device));
+       result = acpi_check_update_proc(sbs);
+       if (result)
+               goto end;
 
       end:
+
+       sbs_mutex_unlock(sbs);
+
        if (result) {
                remove_result = acpi_sbs_remove(device, 0);
                if (remove_result) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                         "acpi_sbs_remove() failed\n"));
+                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                                       "acpi_sbs_remove() failed"));
                }
        }
 
        return result;
 }
 
-int acpi_sbs_remove(struct acpi_device *device, int type)
+static int acpi_sbs_remove(struct acpi_device *device, int type)
 {
        struct acpi_sbs *sbs;
        int id;
@@ -1688,15 +1733,14 @@ int acpi_sbs_remove(struct acpi_device *device, int type)
                return -EINVAL;
        }
 
-       sbs = (struct acpi_sbs *)acpi_driver_data(device);
-
+       sbs = acpi_driver_data(device);
        if (!sbs) {
                return -EINVAL;
        }
 
+       sbs_mutex_lock(sbs);
+
        sbs->zombie = 1;
-       sbs->update_time = 0;
-       sbs->update_time2 = 0;
        del_timer_sync(&sbs->update_timer);
        acpi_os_wait_events_complete(NULL);
        del_timer_sync(&sbs->update_timer);
@@ -1707,11 +1751,41 @@ int acpi_sbs_remove(struct acpi_device *device, int type)
 
        acpi_ac_remove(sbs);
 
+       sbs_mutex_unlock(sbs);
+
+       mutex_destroy(&sbs->mutex);
+
        kfree(sbs);
 
        return 0;
 }
 
+static void acpi_sbs_rmdirs(void)
+{
+       if (acpi_ac_dir) {
+               acpi_unlock_ac_dir(acpi_ac_dir);
+               acpi_ac_dir = NULL;
+       }
+       if (acpi_battery_dir) {
+               acpi_unlock_battery_dir(acpi_battery_dir);
+               acpi_battery_dir = NULL;
+       }
+}
+
+static int acpi_sbs_resume(struct acpi_device *device)
+{
+       struct acpi_sbs *sbs;
+
+       if (!device)
+               return -EINVAL;
+
+       sbs = device->driver_data;
+
+       sbs->run_cnt = 0;
+
+       return 0;
+}
+
 static int __init acpi_sbs_init(void)
 {
        int result = 0;
@@ -1719,35 +1793,34 @@ static int __init acpi_sbs_init(void)
        if (acpi_disabled)
                return -ENODEV;
 
-       init_MUTEX(&sbs_sem);
-
        if (capacity_mode != DEF_CAPACITY_UNIT
            && capacity_mode != MAH_CAPACITY_UNIT
            && capacity_mode != MWH_CAPACITY_UNIT) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_sbs_init: "
-                                 "invalid capacity_mode = %d\n",
-                                 capacity_mode));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "invalid capacity_mode = %d", capacity_mode));
                return -EINVAL;
        }
 
        acpi_ac_dir = acpi_lock_ac_dir();
        if (!acpi_ac_dir) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_lock_ac_dir() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_lock_ac_dir() failed"));
                return -ENODEV;
        }
 
        acpi_battery_dir = acpi_lock_battery_dir();
        if (!acpi_battery_dir) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_lock_battery_dir() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_lock_battery_dir() failed"));
+               acpi_sbs_rmdirs();
                return -ENODEV;
        }
 
        result = acpi_bus_register_driver(&acpi_sbs_driver);
        if (result < 0) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "acpi_bus_register_driver() failed\n"));
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+                               "acpi_bus_register_driver() failed"));
+               acpi_sbs_rmdirs();
                return -ENODEV;
        }
 
@@ -1756,13 +1829,9 @@ static int __init acpi_sbs_init(void)
 
 static void __exit acpi_sbs_exit(void)
 {
-
        acpi_bus_unregister_driver(&acpi_sbs_driver);
 
-       acpi_unlock_ac_dir(acpi_ac_dir);
-       acpi_ac_dir = NULL;
-       acpi_unlock_battery_dir(acpi_battery_dir);
-       acpi_battery_dir = NULL;
+       acpi_sbs_rmdirs();
 
        return;
 }
index bb0e0da39fb15d355be664e5ae23f1dc5e632441..d80dd84e5bfdaab0713177c5cb21db15aac07996 100644 (file)
@@ -1068,7 +1068,9 @@ acpi_add_single_object(struct acpi_device **child,
                }
                break;
        default:
-               STRUCT_TO_INT(device->status) = 0x0F;
+               STRUCT_TO_INT(device->status) =
+                   ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+                   ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING;
                break;
        }
 
index ccc11b33d89cd713036ae2d0f5ad98bb9a4bd3f3..2d912b71e5435651226cc1278b9d01e8ea55b3e4 100644 (file)
@@ -350,21 +350,31 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
 {
        struct list_head *node, *next;
 
-       seq_printf(seq, "Device Sleep state     Status\n");
+       seq_printf(seq, "Device\tS-state\t  Status   Sysfs node\n");
 
        spin_lock(&acpi_device_lock);
        list_for_each_safe(node, next, &acpi_wakeup_device_list) {
                struct acpi_device *dev =
                    container_of(node, struct acpi_device, wakeup_list);
+               struct device *ldev;
 
                if (!dev->wakeup.flags.valid)
                        continue;
                spin_unlock(&acpi_device_lock);
-               seq_printf(seq, "%4s    %4d             %s%8s\n",
+
+               ldev = acpi_get_physical_device(dev->handle);
+               seq_printf(seq, "%s\t  S%d\t%c%-8s  ",
                           dev->pnp.bus_id,
                           (u32) dev->wakeup.sleep_state,
-                          dev->wakeup.flags.run_wake ? "*" : "",
+                          dev->wakeup.flags.run_wake ? '*' : ' ',
                           dev->wakeup.state.enabled ? "enabled" : "disabled");
+               if (ldev)
+                       seq_printf(seq, "%s:%s",
+                               ldev->bus ? ldev->bus->name : "no-bus",
+                               ldev->bus_id);
+               seq_printf(seq, "\n");
+               put_device(ldev);
+
                spin_lock(&acpi_device_lock);
        }
        spin_unlock(&acpi_device_lock);
index 807c7116e94b8eaa19471ce66ab4196e0ef66c06..1db833eb2417c5988890dc8ce4b62bed764e0d45 100644 (file)
@@ -347,6 +347,18 @@ static void acpi_tb_convert_fadt(void)
                acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
 
        }
+
+       /*
+        * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero)
+        * are indeed zero. This will workaround BIOSs that inadvertently placed
+        * values in these fields.
+        */
+       if (acpi_gbl_FADT.header.revision < 3) {
+               acpi_gbl_FADT.preferred_profile = 0;
+               acpi_gbl_FADT.pstate_control = 0;
+               acpi_gbl_FADT.cst_control = 0;
+               acpi_gbl_FADT.boot_flags = 0;
+       }
 }
 
 /******************************************************************************
index 7bdbe5a914d0ce78f34d10325ce0e9eba31fb126..365c306c7cf81e2fcfd75d4be9c3fb1e2c39e303 100644 (file)
@@ -156,11 +156,6 @@ config SATA_INIC162X
        help
          This option enables support for Initio 162x Serial ATA.
 
-config SATA_INTEL_COMBINED
-       bool
-       depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
-       default y
-
 config SATA_ACPI
        bool
        depends on ACPI && PCI
@@ -184,7 +179,7 @@ config PATA_ALI
          If unsure, say N.
 
 config PATA_AMD
-       tristate "AMD/NVidia PATA support (Experimental)"
+       tristate "AMD/NVidia PATA support"
        depends on PCI
        help
          This option enables support for the AMD and NVidia PATA
@@ -209,6 +204,16 @@ config PATA_ATIIXP
 
          If unsure, say N.
 
+config PATA_CMD640_PCI
+       tristate "CMD640 PCI PATA support (Very Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables support for the CMD640 PCI IDE
+         interface chip. Only the primary channel is currently
+         supported.
+
+         If unsure, say N.
+
 config PATA_CMD64X
        tristate "CMD64x PATA support (Very Experimental)"
        depends on PCI&& EXPERIMENTAL
@@ -273,7 +278,7 @@ config ATA_GENERIC
          If unsure, say N.
 
 config PATA_HPT366
-       tristate "HPT 366/368 PATA support (Very Experimental)"
+       tristate "HPT 366/368 PATA support (Experimental)"
        depends on PCI && EXPERIMENTAL
        help
          This option enables support for the HPT 366 and 368
@@ -282,7 +287,7 @@ config PATA_HPT366
          If unsure, say N.
 
 config PATA_HPT37X
-       tristate "HPT 370/370A/371/372/374/302 PATA support (Very Experimental)"
+       tristate "HPT 370/370A/371/372/374/302 PATA support (Experimental)"
        depends on PCI && EXPERIMENTAL
        help
          This option enables support for the majority of the later HPT
@@ -309,7 +314,7 @@ config PATA_HPT3X3
          If unsure, say N.
 
 config PATA_ISAPNP
-       tristate "ISA Plug and Play PATA support (Very Experimental)"
+       tristate "ISA Plug and Play PATA support (Experimental)"
        depends on EXPERIMENTAL && ISAPNP
        help
          This option enables support for ISA plug & play ATA
@@ -318,8 +323,8 @@ config PATA_ISAPNP
          If unsure, say N.
 
 config PATA_IT821X
-       tristate "IT8211/2 PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+       tristate "IT8211/2 PATA support"
+       depends on PCI
        help
          This option enables support for the ITE 8211 and 8212
          PATA controllers via the new ATA layer, including RAID
@@ -390,10 +395,10 @@ config PATA_MPIIX
          If unsure, say N.
 
 config PATA_OLDPIIX
-       tristate "Intel PATA old PIIX support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+       tristate "Intel PATA old PIIX support"
+       depends on PCI
        help
-         This option enables support for old(?) PIIX PATA support.
+         This option enables support for early PIIX PATA support.
 
          If unsure, say N.
 
@@ -444,7 +449,7 @@ config PATA_PCMCIA
          If unsure, say N.
 
 config PATA_PDC_OLD
-       tristate "Older Promise PATA controller support (Very Experimental)"
+       tristate "Older Promise PATA controller support (Experimental)"
        depends on PCI && EXPERIMENTAL
        help
          This option enables support for the Promise 20246, 20262, 20263,
@@ -459,7 +464,7 @@ config PATA_QDI
          Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
 
 config PATA_RADISYS
-       tristate "RADISYS 82600 PATA support (Very experimental)"
+       tristate "RADISYS 82600 PATA support (Very Experimental)"
        depends on PCI && EXPERIMENTAL
        help
          This option enables support for the RADISYS 82600
@@ -477,7 +482,7 @@ config PATA_RZ1000
          If unsure, say N.
 
 config PATA_SC1200
-       tristate "SC1200 PATA support (Raving Lunatic)"
+       tristate "SC1200 PATA support (Very Experimental)"
        depends on PCI && EXPERIMENTAL
        help
          This option enables support for the NatSemi/AMD SC1200 SoC
@@ -486,8 +491,8 @@ config PATA_SC1200
          If unsure, say N.
 
 config PATA_SERVERWORKS
-       tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+       tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support"
+       depends on PCI
        help
          This option enables support for the Serverworks OSB4/CSB5/CSB6 and
          HT1000 PATA controllers, via the new ATA layer.
index 13d7397e0008080fe84dc020f69e7f10a5e2b870..b7055e302650dc4d6dea4e81d6346dc2457208b1 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_PATA_ALI)                += pata_ali.o
 obj-$(CONFIG_PATA_AMD)         += pata_amd.o
 obj-$(CONFIG_PATA_ARTOP)       += pata_artop.o
 obj-$(CONFIG_PATA_ATIIXP)      += pata_atiixp.o
+obj-$(CONFIG_PATA_CMD640_PCI)  += pata_cmd640.o
 obj-$(CONFIG_PATA_CMD64X)      += pata_cmd64x.o
 obj-$(CONFIG_PATA_CS5520)      += pata_cs5520.o
 obj-$(CONFIG_PATA_CS5530)      += pata_cs5530.o
index fd27227771b48a8038ec867c62f9804fc34aa9af..34c5534ed64c22c65779b418a57793739b98f16f 100644 (file)
@@ -170,6 +170,10 @@ enum {
        AHCI_FLAG_IGN_IRQ_IF_ERR        = (1 << 25), /* ignore IRQ_IF_ERR */
        AHCI_FLAG_HONOR_PI              = (1 << 26), /* honor PORTS_IMPL */
        AHCI_FLAG_IGN_SERR_INTERNAL     = (1 << 27), /* ignore SERR_INTERNAL */
+
+       AHCI_FLAG_COMMON                = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                         ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+                                         ATA_FLAG_SKIP_D2H_BSY,
 };
 
 struct ahci_cmd_hdr {
@@ -188,8 +192,10 @@ struct ahci_sg {
 };
 
 struct ahci_host_priv {
-       u32                     cap;    /* cache of HOST_CAP register */
-       u32                     port_map; /* cache of HOST_PORTS_IMPL reg */
+       u32                     cap;            /* cap to use */
+       u32                     port_map;       /* port map to use */
+       u32                     saved_cap;      /* saved initial cap */
+       u32                     saved_port_map; /* saved initial port_map */
 };
 
 struct ahci_port_priv {
@@ -209,7 +215,6 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
 static void ahci_irq_clear(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
@@ -263,7 +268,6 @@ static const struct ata_port_operations ahci_ops = {
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
 
-       .irq_handler            = ahci_interrupt,
        .irq_clear              = ahci_irq_clear,
        .irq_on                 = ata_dummy_irq_on,
        .irq_ack                = ata_dummy_irq_ack,
@@ -298,7 +302,6 @@ static const struct ata_port_operations ahci_vt8251_ops = {
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
 
-       .irq_handler            = ahci_interrupt,
        .irq_clear              = ahci_irq_clear,
        .irq_on                 = ata_dummy_irq_on,
        .irq_ack                = ata_dummy_irq_ack,
@@ -324,58 +327,41 @@ static const struct ata_port_operations ahci_vt8251_ops = {
 static const struct ata_port_info ahci_port_info[] = {
        /* board_ahci */
        {
-               .sht            = &ahci_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY,
+               .flags          = AHCI_FLAG_COMMON,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
        },
        /* board_ahci_pi */
        {
-               .sht            = &ahci_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI,
+               .flags          = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
        },
        /* board_ahci_vt8251 */
        {
-               .sht            = &ahci_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY |
-                                 ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ,
+               .flags          = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
+                                 AHCI_FLAG_NO_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_vt8251_ops,
        },
        /* board_ahci_ign_iferr */
        {
-               .sht            = &ahci_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY |
-                                 AHCI_FLAG_IGN_IRQ_IF_ERR,
+               .flags          = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
        },
        /* board_ahci_sb600 */
        {
-               .sht            = &ahci_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY |
+               .flags          = AHCI_FLAG_COMMON |
                                  AHCI_FLAG_IGN_SERR_INTERNAL,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
        },
-
 };
 
 static const struct pci_device_id ahci_pci_tbl[] = {
@@ -413,11 +399,11 @@ static const struct pci_device_id ahci_pci_tbl[] = {
          PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
 
        /* ATI */
-       { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 non-raid */
-       { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
+       { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
 
        /* VIA */
        { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
+       { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
 
        /* NVIDIA */
        { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },            /* MCP65 */
@@ -471,10 +457,100 @@ static inline int ahci_nr_ports(u32 cap)
        return (cap & 0x1f) + 1;
 }
 
-static inline void __iomem *ahci_port_base(void __iomem *base,
-                                          unsigned int port)
+static inline void __iomem *ahci_port_base(struct ata_port *ap)
+{
+       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
+
+       return mmio + 0x100 + (ap->port_no * 0x80);
+}
+
+/**
+ *     ahci_save_initial_config - Save and fixup initial config values
+ *     @pdev: target PCI device
+ *     @pi: associated ATA port info
+ *     @hpriv: host private area to store config values
+ *
+ *     Some registers containing configuration info might be setup by
+ *     BIOS and might be cleared on reset.  This function saves the
+ *     initial values of those registers into @hpriv such that they
+ *     can be restored after controller reset.
+ *
+ *     If inconsistent, config values are fixed up by this function.
+ *
+ *     LOCKING:
+ *     None.
+ */
+static void ahci_save_initial_config(struct pci_dev *pdev,
+                                    const struct ata_port_info *pi,
+                                    struct ahci_host_priv *hpriv)
 {
-       return base + 0x100 + (port * 0x80);
+       void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
+       u32 cap, port_map;
+       int i;
+
+       /* Values prefixed with saved_ are written back to host after
+        * reset.  Values without are used for driver operation.
+        */
+       hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
+       hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
+
+       /* fixup zero port_map */
+       if (!port_map) {
+               port_map = (1 << ahci_nr_ports(hpriv->cap)) - 1;
+               dev_printk(KERN_WARNING, &pdev->dev,
+                          "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
+
+               /* write the fixed up value to the PI register */
+               hpriv->saved_port_map = port_map;
+       }
+
+       /* cross check port_map and cap.n_ports */
+       if (pi->flags & AHCI_FLAG_HONOR_PI) {
+               u32 tmp_port_map = port_map;
+               int n_ports = ahci_nr_ports(cap);
+
+               for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
+                       if (tmp_port_map & (1 << i)) {
+                               n_ports--;
+                               tmp_port_map &= ~(1 << i);
+                       }
+               }
+
+               /* Whine if inconsistent.  No need to update cap.
+                * port_map is used to determine number of ports.
+                */
+               if (n_ports || tmp_port_map)
+                       dev_printk(KERN_WARNING, &pdev->dev,
+                                  "nr_ports (%u) and implemented port map "
+                                  "(0x%x) don't match\n",
+                                  ahci_nr_ports(cap), port_map);
+       } else {
+               /* fabricate port_map from cap.nr_ports */
+               port_map = (1 << ahci_nr_ports(cap)) - 1;
+       }
+
+       /* record values to use during operation */
+       hpriv->cap = cap;
+       hpriv->port_map = port_map;
+}
+
+/**
+ *     ahci_restore_initial_config - Restore initial config
+ *     @host: target ATA host
+ *
+ *     Restore initial config stored by ahci_save_initial_config().
+ *
+ *     LOCKING:
+ *     None.
+ */
+static void ahci_restore_initial_config(struct ata_host *host)
+{
+       struct ahci_host_priv *hpriv = host->private_data;
+       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+
+       writel(hpriv->saved_cap, mmio + HOST_CAP);
+       writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
+       (void) readl(mmio + HOST_PORTS_IMPL);   /* flush */
 }
 
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
@@ -511,8 +587,9 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-static void ahci_start_engine(void __iomem *port_mmio)
+static void ahci_start_engine(struct ata_port *ap)
 {
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
 
        /* start DMA */
@@ -522,8 +599,9 @@ static void ahci_start_engine(void __iomem *port_mmio)
        readl(port_mmio + PORT_CMD); /* flush */
 }
 
-static int ahci_stop_engine(void __iomem *port_mmio)
+static int ahci_stop_engine(struct ata_port *ap)
 {
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
 
        tmp = readl(port_mmio + PORT_CMD);
@@ -545,19 +623,23 @@ static int ahci_stop_engine(void __iomem *port_mmio)
        return 0;
 }
 
-static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
-                             dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_start_fis_rx(struct ata_port *ap)
 {
+       void __iomem *port_mmio = ahci_port_base(ap);
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       struct ahci_port_priv *pp = ap->private_data;
        u32 tmp;
 
        /* set FIS registers */
-       if (cap & HOST_CAP_64)
-               writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
-       writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+       if (hpriv->cap & HOST_CAP_64)
+               writel((pp->cmd_slot_dma >> 16) >> 16,
+                      port_mmio + PORT_LST_ADDR_HI);
+       writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
 
-       if (cap & HOST_CAP_64)
-               writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
-       writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+       if (hpriv->cap & HOST_CAP_64)
+               writel((pp->rx_fis_dma >> 16) >> 16,
+                      port_mmio + PORT_FIS_ADDR_HI);
+       writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
 
        /* enable FIS reception */
        tmp = readl(port_mmio + PORT_CMD);
@@ -568,8 +650,9 @@ static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
        readl(port_mmio + PORT_CMD);
 }
 
-static int ahci_stop_fis_rx(void __iomem *port_mmio)
+static int ahci_stop_fis_rx(struct ata_port *ap)
 {
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
 
        /* disable FIS reception */
@@ -586,14 +669,16 @@ static int ahci_stop_fis_rx(void __iomem *port_mmio)
        return 0;
 }
 
-static void ahci_power_up(void __iomem *port_mmio, u32 cap)
+static void ahci_power_up(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 cmd;
 
        cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
 
        /* spin up device */
-       if (cap & HOST_CAP_SSS) {
+       if (hpriv->cap & HOST_CAP_SSS) {
                cmd |= PORT_CMD_SPIN_UP;
                writel(cmd, port_mmio + PORT_CMD);
        }
@@ -603,11 +688,13 @@ static void ahci_power_up(void __iomem *port_mmio, u32 cap)
 }
 
 #ifdef CONFIG_PM
-static void ahci_power_down(void __iomem *port_mmio, u32 cap)
+static void ahci_power_down(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 cmd, scontrol;
 
-       if (!(cap & HOST_CAP_SSS))
+       if (!(hpriv->cap & HOST_CAP_SSS))
                return;
 
        /* put device into listen mode, first set PxSCTL.DET to 0 */
@@ -622,29 +709,28 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap)
 }
 #endif
 
-static void ahci_init_port(void __iomem *port_mmio, u32 cap,
-                          dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_init_port(struct ata_port *ap)
 {
        /* enable FIS reception */
-       ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
+       ahci_start_fis_rx(ap);
 
        /* enable DMA */
-       ahci_start_engine(port_mmio);
+       ahci_start_engine(ap);
 }
 
-static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
+static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
 {
        int rc;
 
        /* disable DMA */
-       rc = ahci_stop_engine(port_mmio);
+       rc = ahci_stop_engine(ap);
        if (rc) {
                *emsg = "failed to stop engine";
                return rc;
        }
 
        /* disable FIS reception */
-       rc = ahci_stop_fis_rx(port_mmio);
+       rc = ahci_stop_fis_rx(ap);
        if (rc) {
                *emsg = "failed stop FIS RX";
                return rc;
@@ -653,12 +739,11 @@ static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
        return 0;
 }
 
-static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
+static int ahci_reset_controller(struct ata_host *host)
 {
-       u32 cap_save, impl_save, tmp;
-
-       cap_save = readl(mmio + HOST_CAP);
-       impl_save = readl(mmio + HOST_PORTS_IMPL);
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+       u32 tmp;
 
        /* global controller reset */
        tmp = readl(mmio + HOST_CTL);
@@ -674,7 +759,7 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
 
        tmp = readl(mmio + HOST_CTL);
        if (tmp & HOST_RESET) {
-               dev_printk(KERN_ERR, &pdev->dev,
+               dev_printk(KERN_ERR, host->dev,
                           "controller reset failed (0x%x)\n", tmp);
                return -EIO;
        }
@@ -683,18 +768,8 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
        writel(HOST_AHCI_EN, mmio + HOST_CTL);
        (void) readl(mmio + HOST_CTL);  /* flush */
 
-       /* These write-once registers are normally cleared on reset.
-        * Restore BIOS values... which we HOPE were present before
-        * reset.
-        */
-       if (!impl_save) {
-               impl_save = (1 << ahci_nr_ports(cap_save)) - 1;
-               dev_printk(KERN_WARNING, &pdev->dev,
-                          "PORTS_IMPL is zero, forcing 0x%x\n", impl_save);
-       }
-       writel(cap_save, mmio + HOST_CAP);
-       writel(impl_save, mmio + HOST_PORTS_IMPL);
-       (void) readl(mmio + HOST_PORTS_IMPL);   /* flush */
+       /* some registers might be cleared on reset.  restore initial values */
+       ahci_restore_initial_config(host);
 
        if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
                u16 tmp16;
@@ -708,23 +783,23 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
        return 0;
 }
 
-static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
-                                int n_ports, unsigned int port_flags,
-                                struct ahci_host_priv *hpriv)
+static void ahci_init_controller(struct ata_host *host)
 {
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        int i, rc;
        u32 tmp;
 
-       for (i = 0; i < n_ports; i++) {
-               void __iomem *port_mmio = ahci_port_base(mmio, i);
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+               void __iomem *port_mmio = ahci_port_base(ap);
                const char *emsg = NULL;
 
-               if ((port_flags & AHCI_FLAG_HONOR_PI) &&
-                   !(hpriv->port_map & (1 << i)))
+               if (ata_port_is_dummy(ap))
                        continue;
 
                /* make sure port is not active */
-               rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+               rc = ahci_deinit_port(ap, &emsg);
                if (rc)
                        dev_printk(KERN_WARNING, &pdev->dev,
                                   "%s (%d)\n", emsg, rc);
@@ -752,7 +827,7 @@ static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
 
 static unsigned int ahci_dev_classify(struct ata_port *ap)
 {
-       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+       void __iomem *port_mmio = ahci_port_base(ap);
        struct ata_taskfile tf;
        u32 tmp;
 
@@ -802,8 +877,7 @@ static int ahci_clo(struct ata_port *ap)
 static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 {
        struct ahci_port_priv *pp = ap->private_data;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *port_mmio = ahci_port_base(ap);
        const u32 cmd_fis_len = 5; /* five dwords */
        const char *reason = NULL;
        struct ata_taskfile tf;
@@ -820,7 +894,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
        }
 
        /* prepare for SRST (AHCI-1.1 10.4.1) */
-       rc = ahci_stop_engine(port_mmio);
+       rc = ahci_stop_engine(ap);
        if (rc) {
                reason = "failed to stop engine";
                goto fail_restart;
@@ -840,7 +914,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
        }
 
        /* restart engine */
-       ahci_start_engine(port_mmio);
+       ahci_start_engine(ap);
 
        ata_tf_init(ap->device, &tf);
        fis = pp->cmd_tbl;
@@ -899,7 +973,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
        return 0;
 
  fail_restart:
-       ahci_start_engine(port_mmio);
+       ahci_start_engine(ap);
  fail:
        ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
        return rc;
@@ -910,13 +984,11 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
        struct ahci_port_priv *pp = ap->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        int rc;
 
        DPRINTK("ENTER\n");
 
-       ahci_stop_engine(port_mmio);
+       ahci_stop_engine(ap);
 
        /* clear D2H reception area to properly wait for D2H FIS */
        ata_tf_init(ap->device, &tf);
@@ -925,7 +997,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
 
        rc = sata_std_hardreset(ap, class);
 
-       ahci_start_engine(port_mmio);
+       ahci_start_engine(ap);
 
        if (rc == 0 && ata_port_online(ap))
                *class = ahci_dev_classify(ap);
@@ -938,20 +1010,18 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
 
 static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
 {
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        int rc;
 
        DPRINTK("ENTER\n");
 
-       ahci_stop_engine(port_mmio);
+       ahci_stop_engine(ap);
 
        rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context));
 
        /* vt8251 needs SError cleared for the port to operate */
        ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
 
-       ahci_start_engine(port_mmio);
+       ahci_start_engine(ap);
 
        DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
 
@@ -963,7 +1033,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
 
 static void ahci_postreset(struct ata_port *ap, unsigned int *class)
 {
-       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 new_tmp, tmp;
 
        ata_std_postreset(ap, class);
@@ -1131,8 +1201,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 
 static void ahci_host_intr(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
        struct ata_eh_info *ehi = &ap->eh_info;
        struct ahci_port_priv *pp = ap->private_data;
        u32 status, qc_active;
@@ -1283,7 +1352,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+       void __iomem *port_mmio = ahci_port_base(ap);
 
        if (qc->tf.protocol == ATA_PROT_NCQ)
                writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1295,8 +1364,7 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 
 static void ahci_freeze(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *port_mmio = ahci_port_base(ap);
 
        /* turn IRQ off */
        writel(0, port_mmio + PORT_IRQ_MASK);
@@ -1305,7 +1373,7 @@ static void ahci_freeze(struct ata_port *ap)
 static void ahci_thaw(struct ata_port *ap)
 {
        void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
 
        /* clear IRQ */
@@ -1319,13 +1387,10 @@ static void ahci_thaw(struct ata_port *ap)
 
 static void ahci_error_handler(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
        if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                /* restart engine */
-               ahci_stop_engine(port_mmio);
-               ahci_start_engine(port_mmio);
+               ahci_stop_engine(ap);
+               ahci_start_engine(ap);
        }
 
        /* perform recovery */
@@ -1335,13 +1400,10 @@ static void ahci_error_handler(struct ata_port *ap)
 
 static void ahci_vt8251_error_handler(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
        if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                /* restart engine */
-               ahci_stop_engine(port_mmio);
-               ahci_start_engine(port_mmio);
+               ahci_stop_engine(ap);
+               ahci_start_engine(ap);
        }
 
        /* perform recovery */
@@ -1352,36 +1414,26 @@ static void ahci_vt8251_error_handler(struct ata_port *ap)
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 
-       if (qc->flags & ATA_QCFLAG_FAILED)
-               qc->err_mask |= AC_ERR_OTHER;
-
-       if (qc->err_mask) {
+       if (qc->flags & ATA_QCFLAG_FAILED) {
                /* make DMA engine forget about the failed command */
-               ahci_stop_engine(port_mmio);
-               ahci_start_engine(port_mmio);
+               ahci_stop_engine(ap);
+               ahci_start_engine(ap);
        }
 }
 
 #ifdef CONFIG_PM
 static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
 {
-       struct ahci_host_priv *hpriv = ap->host->private_data;
-       struct ahci_port_priv *pp = ap->private_data;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        const char *emsg = NULL;
        int rc;
 
-       rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+       rc = ahci_deinit_port(ap, &emsg);
        if (rc == 0)
-               ahci_power_down(port_mmio, hpriv->cap);
+               ahci_power_down(ap);
        else {
                ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
-               ahci_init_port(port_mmio, hpriv->cap,
-                              pp->cmd_slot_dma, pp->rx_fis_dma);
+               ahci_init_port(ap);
        }
 
        return rc;
@@ -1389,13 +1441,8 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
 
 static int ahci_port_resume(struct ata_port *ap)
 {
-       struct ahci_port_priv *pp = ap->private_data;
-       struct ahci_host_priv *hpriv = ap->host->private_data;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
-       ahci_power_up(port_mmio, hpriv->cap);
-       ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+       ahci_power_up(ap);
+       ahci_init_port(ap);
 
        return 0;
 }
@@ -1423,8 +1470,6 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 static int ahci_pci_device_resume(struct pci_dev *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
-       struct ahci_host_priv *hpriv = host->private_data;
-       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
@@ -1432,12 +1477,11 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
                return rc;
 
        if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
-               rc = ahci_reset_controller(mmio, pdev);
+               rc = ahci_reset_controller(host);
                if (rc)
                        return rc;
 
-               ahci_init_controller(mmio, pdev, host->n_ports,
-                                    host->ports[0]->flags, hpriv);
+               ahci_init_controller(host);
        }
 
        ata_host_resume(host);
@@ -1449,10 +1493,7 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
 static int ahci_port_start(struct ata_port *ap)
 {
        struct device *dev = ap->host->dev;
-       struct ahci_host_priv *hpriv = ap->host->private_data;
        struct ahci_port_priv *pp;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        void *mem;
        dma_addr_t mem_dma;
        int rc;
@@ -1500,85 +1541,29 @@ static int ahci_port_start(struct ata_port *ap)
        ap->private_data = pp;
 
        /* power up port */
-       ahci_power_up(port_mmio, hpriv->cap);
+       ahci_power_up(ap);
 
        /* initialize port */
-       ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+       ahci_init_port(ap);
 
        return 0;
 }
 
 static void ahci_port_stop(struct ata_port *ap)
 {
-       struct ahci_host_priv *hpriv = ap->host->private_data;
-       void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        const char *emsg = NULL;
        int rc;
 
        /* de-initialize port */
-       rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+       rc = ahci_deinit_port(ap, &emsg);
        if (rc)
                ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
 }
 
-static void ahci_setup_port(struct ata_ioports *port, void __iomem *base,
-                           unsigned int port_idx)
+static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
 {
-       VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
-       base = ahci_port_base(base, port_idx);
-       VPRINTK("base now==0x%lx\n", base);
-
-       port->cmd_addr          = base;
-       port->scr_addr          = base + PORT_SCR;
-
-       VPRINTK("EXIT\n");
-}
-
-static int ahci_host_init(struct ata_probe_ent *probe_ent)
-{
-       struct ahci_host_priv *hpriv = probe_ent->private_data;
-       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-       void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
-       unsigned int i, cap_n_ports, using_dac;
        int rc;
 
-       rc = ahci_reset_controller(mmio, pdev);
-       if (rc)
-               return rc;
-
-       hpriv->cap = readl(mmio + HOST_CAP);
-       hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
-       cap_n_ports = ahci_nr_ports(hpriv->cap);
-
-       VPRINTK("cap 0x%x  port_map 0x%x  n_ports %d\n",
-               hpriv->cap, hpriv->port_map, cap_n_ports);
-
-       if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) {
-               unsigned int n_ports = cap_n_ports;
-               u32 port_map = hpriv->port_map;
-               int max_port = 0;
-
-               for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
-                       if (port_map & (1 << i)) {
-                               n_ports--;
-                               port_map &= ~(1 << i);
-                               max_port = i;
-                       } else
-                               probe_ent->dummy_port_mask |= 1 << i;
-               }
-
-               if (n_ports || port_map)
-                       dev_printk(KERN_WARNING, &pdev->dev,
-                                  "nr_ports (%u) and implemented port map "
-                                  "(0x%x) don't match\n",
-                                  cap_n_ports, hpriv->port_map);
-
-               probe_ent->n_ports = max_port + 1;
-       } else
-               probe_ent->n_ports = cap_n_ports;
-
-       using_dac = hpriv->cap & HOST_CAP_64;
        if (using_dac &&
            !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
                rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
@@ -1604,23 +1589,14 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
                        return rc;
                }
        }
-
-       for (i = 0; i < probe_ent->n_ports; i++)
-               ahci_setup_port(&probe_ent->port[i], mmio, i);
-
-       ahci_init_controller(mmio, pdev, probe_ent->n_ports,
-                            probe_ent->port_flags, hpriv);
-
-       pci_set_master(pdev);
-
        return 0;
 }
 
-static void ahci_print_info(struct ata_probe_ent *probe_ent)
+static void ahci_print_info(struct ata_host *host)
 {
-       struct ahci_host_priv *hpriv = probe_ent->private_data;
-       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-       void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
+       struct ahci_host_priv *hpriv = host->private_data;
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        u32 vers, cap, impl, speed;
        const char *speed_s;
        u16 cc;
@@ -1690,11 +1666,12 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
-       unsigned int board_idx = (unsigned int) ent->driver_data;
+       struct ata_port_info pi = ahci_port_info[ent->driver_data];
+       const struct ata_port_info *ppi[] = { &pi, NULL };
        struct device *dev = &pdev->dev;
-       struct ata_probe_ent *probe_ent;
        struct ahci_host_priv *hpriv;
-       int rc;
+       struct ata_host *host;
+       int i, rc;
 
        VPRINTK("ENTER\n");
 
@@ -1703,6 +1680,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* acquire resources */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -1716,44 +1694,49 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (pci_enable_msi(pdev))
                pci_intx(pdev, 1);
 
-       probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
-               return -ENOMEM;
-
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
-
        hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
        if (!hpriv)
                return -ENOMEM;
 
-       probe_ent->sht          = ahci_port_info[board_idx].sht;
-       probe_ent->port_flags   = ahci_port_info[board_idx].flags;
-       probe_ent->pio_mask     = ahci_port_info[board_idx].pio_mask;
-       probe_ent->udma_mask    = ahci_port_info[board_idx].udma_mask;
-       probe_ent->port_ops     = ahci_port_info[board_idx].port_ops;
+       /* save initial config */
+       ahci_save_initial_config(pdev, &pi, hpriv);
 
-               probe_ent->irq = pdev->irq;
-               probe_ent->irq_flags = IRQF_SHARED;
-       probe_ent->iomap = pcim_iomap_table(pdev);
-       probe_ent->private_data = hpriv;
+       /* prepare host */
+       if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+               pi.flags |= ATA_FLAG_NCQ;
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
+       if (!host)
+               return -ENOMEM;
+       host->iomap = pcim_iomap_table(pdev);
+       host->private_data = hpriv;
+
+       for (i = 0; i < host->n_ports; i++) {
+               if (hpriv->port_map & (1 << i)) {
+                       struct ata_port *ap = host->ports[i];
+                       void __iomem *port_mmio = ahci_port_base(ap);
+
+                       ap->ioaddr.cmd_addr = port_mmio;
+                       ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
+               } else
+                       host->ports[i]->ops = &ata_dummy_port_ops;
+       }
 
        /* initialize adapter */
-       rc = ahci_host_init(probe_ent);
+       rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
        if (rc)
                return rc;
 
-       if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
-           (hpriv->cap & HOST_CAP_NCQ))
-               probe_ent->port_flags |= ATA_FLAG_NCQ;
-
-       ahci_print_info(probe_ent);
+       rc = ahci_reset_controller(host);
+       if (rc)
+               return rc;
 
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
+       ahci_init_controller(host);
+       ahci_print_info(host);
 
-       devm_kfree(dev, probe_ent);
-       return 0;
+       pci_set_master(pdev);
+       return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
+                                &ahci_sht);
 }
 
 static int __init ahci_init(void)
index d8e79882b8809a97df8eff73efd87f9e228d1bc7..92a491ddd03055555c2926ecf16f23c6a4526749 100644 (file)
  *     A generic parallel ATA driver using libata
  */
 
-/**
- *     generic_pre_reset               -       probe begin
- *     @ap: ATA port
- *
- *     Set up cable type and use generic probe init
- */
-
-static int generic_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA80;
-       return ata_std_prereset(ap);
-}
-
-
-/**
- *     generic_error_handler - Probe specified port on PATA host controller
- *     @ap: Port to probe
- *     @classes:
- *
- *     LOCKING:
- *     None (inherited from caller).
- */
-
-
-static void generic_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, generic_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
 /**
  *     generic_set_mode        -       mode setting
  *     @ap: interface to set up
@@ -144,8 +115,9 @@ static struct ata_port_operations generic_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = generic_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_unknown,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
index b952c584338fb4fe3f797435a1f720c8b6070ef4..55d306a3e5386e779e12d040a9156040d93a5c69 100644 (file)
@@ -93,7 +93,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "ata_piix"
-#define DRV_VERSION    "2.10ac1"
+#define DRV_VERSION    "2.11"
 
 enum {
        PIIX_IOCFG              = 0x54, /* IDE I/O configuration register */
@@ -155,11 +155,11 @@ struct piix_host_priv {
 static int piix_init_one (struct pci_dev *pdev,
                                    const struct pci_device_id *ent);
 static void piix_pata_error_handler(struct ata_port *ap);
-static void ich_pata_error_handler(struct ata_port *ap);
 static void piix_sata_error_handler(struct ata_port *ap);
 static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
 static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
 static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+static int ich_pata_cable_detect(struct ata_port *ap);
 
 static unsigned int in_module_init = 1;
 
@@ -305,6 +305,7 @@ static const struct ata_port_operations piix_pata_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = piix_pata_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_40wire,
 
        .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
@@ -336,8 +337,9 @@ static const struct ata_port_operations ich_pata_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = ich_pata_error_handler,
+       .error_handler          = piix_pata_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ich_pata_cable_detect,
 
        .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
@@ -580,12 +582,13 @@ static const struct ich_laptop ich_laptop[] = {
        /* devid, subvendor, subdev */
        { 0x27DF, 0x0005, 0x0280 },     /* ICH7 on Acer 5602WLMi */
        { 0x27DF, 0x1025, 0x0110 },     /* ICH7 on Acer 3682WLMi */
+       { 0x27DF, 0x1043, 0x1267 },     /* ICH7 on Asus W5F */
        /* end marker */
        { 0, }
 };
 
 /**
- *     piix_pata_cbl_detect - Probe host controller cable detect info
+ *     ich_pata_cable_detect - Probe host controller cable detect info
  *     @ap: Port for which cable detect info is desired
  *
  *     Read 80c cable indicator from ATA PCI device's PCI config
@@ -595,23 +598,18 @@ static const struct ich_laptop ich_laptop[] = {
  *     None (inherited from caller).
  */
 
-static void ich_pata_cbl_detect(struct ata_port *ap)
+static int ich_pata_cable_detect(struct ata_port *ap)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        const struct ich_laptop *lap = &ich_laptop[0];
        u8 tmp, mask;
 
-       /* no 80c support in host controller? */
-       if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
-               goto cbl40;
-
        /* Check for specials - Acer Aspire 5602WLMi */
        while (lap->device) {
                if (lap->device == pdev->device &&
                    lap->subvendor == pdev->subsystem_vendor &&
                    lap->subdevice == pdev->subsystem_device) {
-                       ap->cbl = ATA_CBL_PATA40_SHORT;
-                       return;
+                       return ATA_CBL_PATA40_SHORT;
                }
                lap++;
        }
@@ -620,20 +618,14 @@ static void ich_pata_cbl_detect(struct ata_port *ap)
        mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
        pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
        if ((tmp & mask) == 0)
-               goto cbl40;
-
-       ap->cbl = ATA_CBL_PATA80;
-       return;
-
-cbl40:
-       ap->cbl = ATA_CBL_PATA40;
+               return ATA_CBL_PATA40;
+       return ATA_CBL_PATA80;
 }
 
 /**
  *     piix_pata_prereset - prereset for PATA host controller
  *     @ap: Target port
  *
- *
  *     LOCKING:
  *     None (inherited from caller).
  */
@@ -643,8 +635,6 @@ static int piix_pata_prereset(struct ata_port *ap)
 
        if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
                return -ENOENT;
-
-       ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 }
 
@@ -655,30 +645,6 @@ static void piix_pata_error_handler(struct ata_port *ap)
 }
 
 
-/**
- *     ich_pata_prereset - prereset for PATA host controller
- *     @ap: Target port
- *
- *
- *     LOCKING:
- *     None (inherited from caller).
- */
-static int ich_pata_prereset(struct ata_port *ap)
-{
-       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-
-       if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
-               return -ENOENT;
-       ich_pata_cbl_detect(ap);
-       return ata_std_prereset(ap);
-}
-
-static void ich_pata_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, ich_pata_prereset, ata_std_softreset, NULL,
-                          ata_std_postreset);
-}
-
 static void piix_sata_error_handler(struct ata_port *ap)
 {
        ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
index 0abd72d0dec215bb2fa529c4c84b3c8abfe81646..ca67484af1ebe2259164f5b3531d6ee8056ac89f 100644 (file)
@@ -72,7 +72,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
 static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
 static void ata_dev_xfermask(struct ata_device *dev);
 
-static unsigned int ata_print_id = 1;
+unsigned int ata_print_id = 1;
 static struct workqueue_struct *ata_wq;
 
 struct workqueue_struct *ata_aux_wq;
@@ -89,6 +89,10 @@ int libata_fua = 0;
 module_param_named(fua, libata_fua, int, 0444);
 MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
 
+static int ata_ignore_hpa = 0;
+module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
+MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)");
+
 static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
 module_param(ata_probe_timeout, int, 0444);
 MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
@@ -808,6 +812,205 @@ void ata_id_c_string(const u16 *id, unsigned char *s,
        *p = '\0';
 }
 
+static u64 ata_tf_to_lba48(struct ata_taskfile *tf)
+{
+       u64 sectors = 0;
+
+       sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40;
+       sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32;
+       sectors |= (tf->hob_lbal & 0xff) << 24;
+       sectors |= (tf->lbah & 0xff) << 16;
+       sectors |= (tf->lbam & 0xff) << 8;
+       sectors |= (tf->lbal & 0xff);
+
+       return ++sectors;
+}
+
+static u64 ata_tf_to_lba(struct ata_taskfile *tf)
+{
+       u64 sectors = 0;
+
+       sectors |= (tf->device & 0x0f) << 24;
+       sectors |= (tf->lbah & 0xff) << 16;
+       sectors |= (tf->lbam & 0xff) << 8;
+       sectors |= (tf->lbal & 0xff);
+
+       return ++sectors;
+}
+
+/**
+ *     ata_read_native_max_address_ext -       LBA48 native max query
+ *     @dev: Device to query
+ *
+ *     Perform an LBA48 size query upon the device in question. Return the
+ *     actual LBA48 size or zero if the command fails.
+ */
+
+static u64 ata_read_native_max_address_ext(struct ata_device *dev)
+{
+       unsigned int err;
+       struct ata_taskfile tf;
+
+       ata_tf_init(dev, &tf);
+
+       tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
+       tf.protocol |= ATA_PROT_NODATA;
+       tf.device |= 0x40;
+
+       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       if (err)
+               return 0;
+
+       return ata_tf_to_lba48(&tf);
+}
+
+/**
+ *     ata_read_native_max_address     -       LBA28 native max query
+ *     @dev: Device to query
+ *
+ *     Performa an LBA28 size query upon the device in question. Return the
+ *     actual LBA28 size or zero if the command fails.
+ */
+
+static u64 ata_read_native_max_address(struct ata_device *dev)
+{
+       unsigned int err;
+       struct ata_taskfile tf;
+
+       ata_tf_init(dev, &tf);
+
+       tf.command = ATA_CMD_READ_NATIVE_MAX;
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+       tf.protocol |= ATA_PROT_NODATA;
+       tf.device |= 0x40;
+
+       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       if (err)
+               return 0;
+
+       return ata_tf_to_lba(&tf);
+}
+
+/**
+ *     ata_set_native_max_address_ext  -       LBA48 native max set
+ *     @dev: Device to query
+ *
+ *     Perform an LBA48 size set max upon the device in question. Return the
+ *     actual LBA48 size or zero if the command fails.
+ */
+
+static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors)
+{
+       unsigned int err;
+       struct ata_taskfile tf;
+
+       new_sectors--;
+
+       ata_tf_init(dev, &tf);
+
+       tf.command = ATA_CMD_SET_MAX_EXT;
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
+       tf.protocol |= ATA_PROT_NODATA;
+       tf.device |= 0x40;
+
+       tf.lbal = (new_sectors >> 0) & 0xff;
+       tf.lbam = (new_sectors >> 8) & 0xff;
+       tf.lbah = (new_sectors >> 16) & 0xff;
+
+       tf.hob_lbal = (new_sectors >> 24) & 0xff;
+       tf.hob_lbam = (new_sectors >> 32) & 0xff;
+       tf.hob_lbah = (new_sectors >> 40) & 0xff;
+
+       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       if (err)
+               return 0;
+
+       return ata_tf_to_lba48(&tf);
+}
+
+/**
+ *     ata_set_native_max_address      -       LBA28 native max set
+ *     @dev: Device to query
+ *
+ *     Perform an LBA28 size set max upon the device in question. Return the
+ *     actual LBA28 size or zero if the command fails.
+ */
+
+static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
+{
+       unsigned int err;
+       struct ata_taskfile tf;
+
+       new_sectors--;
+
+       ata_tf_init(dev, &tf);
+
+       tf.command = ATA_CMD_SET_MAX;
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+       tf.protocol |= ATA_PROT_NODATA;
+
+       tf.lbal = (new_sectors >> 0) & 0xff;
+       tf.lbam = (new_sectors >> 8) & 0xff;
+       tf.lbah = (new_sectors >> 16) & 0xff;
+       tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40;
+
+       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       if (err)
+               return 0;
+
+       return ata_tf_to_lba(&tf);
+}
+
+/**
+ *     ata_hpa_resize          -       Resize a device with an HPA set
+ *     @dev: Device to resize
+ *
+ *     Read the size of an LBA28 or LBA48 disk with HPA features and resize
+ *     it if required to the full size of the media. The caller must check
+ *     the drive has the HPA feature set enabled.
+ */
+
+static u64 ata_hpa_resize(struct ata_device *dev)
+{
+       u64 sectors = dev->n_sectors;
+       u64 hpa_sectors;
+       
+       if (ata_id_has_lba48(dev->id))
+               hpa_sectors = ata_read_native_max_address_ext(dev);
+       else
+               hpa_sectors = ata_read_native_max_address(dev);
+
+       /* if no hpa, both should be equal */
+       ata_dev_printk(dev, KERN_INFO, "%s 1: sectors = %lld, "
+                               "hpa_sectors = %lld\n",
+               __FUNCTION__, (long long)sectors, (long long)hpa_sectors);
+
+       if (hpa_sectors > sectors) {
+               ata_dev_printk(dev, KERN_INFO,
+                       "Host Protected Area detected:\n"
+                       "\tcurrent size: %lld sectors\n"
+                       "\tnative size: %lld sectors\n",
+                       (long long)sectors, (long long)hpa_sectors);
+
+               if (ata_ignore_hpa) {
+                       if (ata_id_has_lba48(dev->id))
+                               hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors);
+                       else
+                               hpa_sectors = ata_set_native_max_address(dev,
+                                                               hpa_sectors);
+
+                       if (hpa_sectors) {
+                               ata_dev_printk(dev, KERN_INFO, "native size "
+                                       "increased to %lld sectors\n",
+                                       (long long)hpa_sectors);
+                               return hpa_sectors;
+                       }
+               }
+       }
+       return sectors;
+}
+
 static u64 ata_id_n_sectors(const u16 *id)
 {
        if (ata_id_has_lba(id)) {
@@ -1270,12 +1473,16 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
        if (ap->ops->post_internal_cmd)
                ap->ops->post_internal_cmd(qc);
 
-       if ((qc->flags & ATA_QCFLAG_FAILED) && !qc->err_mask) {
-               if (ata_msg_warn(ap))
-                       ata_dev_printk(dev, KERN_WARNING,
-                               "zero err_mask for failed "
-                               "internal command, assuming AC_ERR_OTHER\n");
-               qc->err_mask |= AC_ERR_OTHER;
+       /* perform minimal error analysis */
+       if (qc->flags & ATA_QCFLAG_FAILED) {
+               if (qc->result_tf.command & (ATA_ERR | ATA_DF))
+                       qc->err_mask |= AC_ERR_DEV;
+
+               if (!qc->err_mask)
+                       qc->err_mask |= AC_ERR_OTHER;
+
+               if (qc->err_mask & ~AC_ERR_OTHER)
+                       qc->err_mask &= ~AC_ERR_OTHER;
        }
 
        /* finish up */
@@ -1379,30 +1586,44 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
  *     Check if the current speed of the device requires IORDY. Used
  *     by various controllers for chip configuration.
  */
-
 unsigned int ata_pio_need_iordy(const struct ata_device *adev)
 {
-       int pio;
-       int speed = adev->pio_mode - XFER_PIO_0;
-
-       if (speed < 2)
+       /* Controller doesn't support  IORDY. Probably a pointless check
+          as the caller should know this */
+       if (adev->ap->flags & ATA_FLAG_NO_IORDY)
                return 0;
-       if (speed > 2)
+       /* PIO3 and higher it is mandatory */
+       if (adev->pio_mode > XFER_PIO_2)
+               return 1;
+       /* We turn it on when possible */
+       if (ata_id_has_iordy(adev->id))
                return 1;
+       return 0;
+}
 
+/**
+ *     ata_pio_mask_no_iordy   -       Return the non IORDY mask
+ *     @adev: ATA device
+ *
+ *     Compute the highest mode possible if we are not using iordy. Return
+ *     -1 if no iordy mode is available.
+ */
+static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
+{
        /* If we have no drive specific rule, then PIO 2 is non IORDY */
-
        if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE */
-               pio = adev->id[ATA_ID_EIDE_PIO];
+               u16 pio = adev->id[ATA_ID_EIDE_PIO];
                /* Is the speed faster than the drive allows non IORDY ? */
                if (pio) {
                        /* This is cycle times not frequency - watch the logic! */
                        if (pio > 240)  /* PIO2 is 240nS per cycle */
-                               return 1;
-                       return 0;
+                               return 3 << ATA_SHIFT_PIO;
+                       return 7 << ATA_SHIFT_PIO;
                }
        }
-       return 0;
+       return 3 << ATA_SHIFT_PIO;
 }
 
 /**
@@ -1431,13 +1652,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
        struct ata_taskfile tf;
        unsigned int err_mask = 0;
        const char *reason;
+       int tried_spinup = 0;
        int rc;
 
        if (ata_msg_ctl(ap))
                ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);
 
        ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
-
  retry:
        ata_tf_init(dev, &tf);
 
@@ -1494,6 +1715,32 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                        goto err_out;
        }
 
+       if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) {
+               tried_spinup = 1;
+               /*
+                * Drive powered-up in standby mode, and requires a specific
+                * SET_FEATURES spin-up subcommand before it will accept
+                * anything other than the original IDENTIFY command.
+                */
+               ata_tf_init(dev, &tf);
+               tf.command = ATA_CMD_SET_FEATURES;
+               tf.feature = SETFEATURES_SPINUP;
+               tf.protocol = ATA_PROT_NODATA;
+               tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+               err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+               if (err_mask) {
+                       rc = -EIO;
+                       reason = "SPINUP failed";
+                       goto err_out;
+               }
+               /*
+                * If the drive initially returned incomplete IDENTIFY info,
+                * we now must reissue the IDENTIFY command.
+                */
+               if (id[2] == 0x37c8)
+                       goto retry;
+       }
+
        if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) {
                /*
                 * The exact sequence expected by certain pre-ATA4 drives is:
@@ -1560,20 +1807,6 @@ static void ata_dev_config_ncq(struct ata_device *dev,
                snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
 }
 
-static void ata_set_port_max_cmd_len(struct ata_port *ap)
-{
-       int i;
-
-       if (ap->scsi_host) {
-               unsigned int len = 0;
-
-               for (i = 0; i < ATA_MAX_DEVICES; i++)
-                       len = max(len, ap->device[i].cdb_len);
-
-               ap->scsi_host->max_cmd_len = len;
-       }
-}
-
 /**
  *     ata_dev_configure - Configure the specified ATA/ATAPI device
  *     @dev: Target device to configure
@@ -1658,6 +1891,7 @@ int ata_dev_configure(struct ata_device *dev)
                        snprintf(revbuf, 7, "ATA-%d",  ata_id_major_version(id));
 
                dev->n_sectors = ata_id_n_sectors(id);
+               dev->n_sectors_boot = dev->n_sectors;
 
                /* SCSI only uses 4-char revisions, dump full 8 chars from ATA */
                ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV,
@@ -1684,6 +1918,9 @@ int ata_dev_configure(struct ata_device *dev)
                                        dev->flags |= ATA_DFLAG_FLUSH_EXT;
                        }
 
+                       if (ata_id_hpa_enabled(dev->id))
+                               dev->n_sectors = ata_hpa_resize(dev);
+
                        /* config NCQ */
                        ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
 
@@ -1773,8 +2010,6 @@ int ata_dev_configure(struct ata_device *dev)
                }
        }
 
-       ata_set_port_max_cmd_len(ap);
-
        /* limit bridge transfers to udma5, 200 sectors */
        if (ata_dev_knobble(dev)) {
                if (ata_msg_drv(ap) && print_info)
@@ -1785,14 +2020,15 @@ int ata_dev_configure(struct ata_device *dev)
        }
 
        if (ata_device_blacklisted(dev) & ATA_HORKAGE_MAX_SEC_128)
-               dev->max_sectors = min(ATA_MAX_SECTORS_128, dev->max_sectors);
+               dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
+                                        dev->max_sectors);
 
        /* limit ATAPI DMA to R/W commands only */
        if (ata_device_blacklisted(dev) & ATA_HORKAGE_DMA_RW_ONLY)
                dev->horkage |= ATA_HORKAGE_DMA_RW_ONLY;
 
        if (ap->ops->dev_config)
-               ap->ops->dev_config(ap, dev);
+               ap->ops->dev_config(dev);
 
        if (ata_msg_probe(ap))
                ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
@@ -1806,6 +2042,56 @@ err_out_nosup:
        return rc;
 }
 
+/**
+ *     ata_cable_40wire        -       return 40 wire cable type
+ *     @ap: port
+ *
+ *     Helper method for drivers which want to hardwire 40 wire cable
+ *     detection.
+ */
+
+int ata_cable_40wire(struct ata_port *ap)
+{
+       return ATA_CBL_PATA40;
+}
+
+/**
+ *     ata_cable_80wire        -       return 80 wire cable type
+ *     @ap: port
+ *
+ *     Helper method for drivers which want to hardwire 80 wire cable
+ *     detection.
+ */
+
+int ata_cable_80wire(struct ata_port *ap)
+{
+       return ATA_CBL_PATA80;
+}
+
+/**
+ *     ata_cable_unknown       -       return unknown PATA cable.
+ *     @ap: port
+ *
+ *     Helper method for drivers which have no PATA cable detection.
+ */
+
+int ata_cable_unknown(struct ata_port *ap)
+{
+       return ATA_CBL_PATA_UNK;
+}
+
+/**
+ *     ata_cable_sata  -       return SATA cable type
+ *     @ap: port
+ *
+ *     Helper method for drivers which have SATA cables
+ */
+
+int ata_cable_sata(struct ata_port *ap)
+{
+       return ATA_CBL_SATA;
+}
+
 /**
  *     ata_bus_probe - Reset and probe ATA bus
  *     @ap: Bus to probe
@@ -1876,6 +2162,10 @@ int ata_bus_probe(struct ata_port *ap)
                        goto fail;
        }
 
+       /* Now ask for the cable type as PDIAG- should have been released */
+       if (ap->ops->cable_detect)
+               ap->cbl = ap->ops->cable_detect(ap);
+
        /* After the identify sequence we can now set up the devices. We do
           this in the normal order so that the user doesn't get confused */
 
@@ -1958,7 +2248,7 @@ void ata_port_probe(struct ata_port *ap)
  *     LOCKING:
  *     None.
  */
-static void sata_print_link_status(struct ata_port *ap)
+void sata_print_link_status(struct ata_port *ap)
 {
        u32 sstatus, scontrol, tmp;
 
@@ -2352,6 +2642,12 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
                t->active += (t->cycle - (t->active + t->recover)) / 2;
                t->recover = t->cycle - t->active;
        }
+       
+       /* In a few cases quantisation may produce enough errors to
+          leave t->cycle too low for the sum of active and recovery
+          if so we must correct this */
+       if (t->active + t->recover > t->cycle)
+               t->cycle = t->active + t->recover;
 
        return 0;
 }
@@ -2481,12 +2777,13 @@ static int ata_dev_set_mode(struct ata_device *dev)
 }
 
 /**
- *     ata_set_mode - Program timings and issue SET FEATURES - XFER
+ *     ata_do_set_mode - Program timings and issue SET FEATURES - XFER
  *     @ap: port on which timings will be programmed
  *     @r_failed_dev: out paramter for failed device
  *
- *     Set ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
- *     ata_set_mode() fails, pointer to the failing device is
+ *     Standard implementation of the function used to tune and set
+ *     ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
+ *     ata_dev_set_mode() fails, pointer to the failing device is
  *     returned in @r_failed_dev.
  *
  *     LOCKING:
@@ -2495,14 +2792,12 @@ static int ata_dev_set_mode(struct ata_device *dev)
  *     RETURNS:
  *     0 on success, negative errno otherwise
  */
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+
+int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
 {
        struct ata_device *dev;
        int i, rc = 0, used_dma = 0, found = 0;
 
-       /* has private set_mode? */
-       if (ap->ops->set_mode)
-               return ap->ops->set_mode(ap, r_failed_dev);
 
        /* step 1: calculate xfer_mask */
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
@@ -2586,6 +2881,29 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
        return rc;
 }
 
+/**
+ *     ata_set_mode - Program timings and issue SET FEATURES - XFER
+ *     @ap: port on which timings will be programmed
+ *     @r_failed_dev: out paramter for failed device
+ *
+ *     Set ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
+ *     ata_set_mode() fails, pointer to the failing device is
+ *     returned in @r_failed_dev.
+ *
+ *     LOCKING:
+ *     PCI/etc. bus probe sem.
+ *
+ *     RETURNS:
+ *     0 on success, negative errno otherwise
+ */
+int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+       /* has private set_mode? */
+       if (ap->ops->set_mode)
+               return ap->ops->set_mode(ap, r_failed_dev);
+       return ata_do_set_mode(ap, r_failed_dev);
+}
+
 /**
  *     ata_tf_to_host - issue ATA taskfile to host controller
  *     @ap: port to which command is being issued
@@ -3267,6 +3585,11 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
                               "%llu != %llu\n",
                               (unsigned long long)dev->n_sectors,
                               (unsigned long long)new_n_sectors);
+               /* Are we the boot time size - if so we appear to be the
+                  same disk at this point and our HPA got reapplied */
+               if (ata_ignore_hpa && dev->n_sectors_boot == new_n_sectors 
+                   && ata_id_hpa_enabled(new_id))
+                       return 1;
                return 0;
        }
 
@@ -3441,19 +3764,7 @@ static void ata_dev_xfermask(struct ata_device *dev)
        xfer_mask = ata_pack_xfermask(ap->pio_mask,
                                      ap->mwdma_mask, ap->udma_mask);
 
-       /* Apply cable rule here.  Don't apply it early because when
-        * we handle hot plug the cable type can itself change.
-        */
-       if (ap->cbl == ATA_CBL_PATA40)
-               xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
-       /* Apply drive side cable rule. Unknown or 80 pin cables reported
-        * host side are checked drive side as well. Cases where we know a
-        * 40wire cable is used safely for 80 are not checked here.
-        */
-        if (ata_drive_40wire(dev->id) && (ap->cbl == ATA_CBL_PATA_UNK || ap->cbl == ATA_CBL_PATA80))
-               xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
-
-
+       /* drive modes available */
        xfer_mask &= ata_pack_xfermask(dev->pio_mask,
                                       dev->mwdma_mask, dev->udma_mask);
        xfer_mask &= ata_id_xfermask(dev->id);
@@ -3482,8 +3793,30 @@ static void ata_dev_xfermask(struct ata_device *dev)
                               "other device, disabling DMA\n");
        }
 
+       if (ap->flags & ATA_FLAG_NO_IORDY)
+               xfer_mask &= ata_pio_mask_no_iordy(dev);
+
        if (ap->ops->mode_filter)
-               xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask);
+               xfer_mask = ap->ops->mode_filter(dev, xfer_mask);
+
+       /* Apply cable rule here.  Don't apply it early because when
+        * we handle hot plug the cable type can itself change.
+        * Check this last so that we know if the transfer rate was
+        * solely limited by the cable.
+        * Unknown or 80 wire cables reported host side are checked
+        * drive side as well. Cases where we know a 40wire cable
+        * is used safely for 80 are not checked here.
+        */
+       if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA))
+               /* UDMA/44 or higher would be available */
+               if((ap->cbl == ATA_CBL_PATA40) ||
+                   (ata_drive_40wire(dev->id) &&
+                    (ap->cbl == ATA_CBL_PATA_UNK ||
+                     ap->cbl == ATA_CBL_PATA80))) {
+                       ata_dev_printk(dev, KERN_WARNING,
+                                "limited to UDMA/33 due to 40-wire cable\n");
+                       xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
+               }
 
        ata_unpack_xfermask(xfer_mask, &dev->pio_mask,
                            &dev->mwdma_mask, &dev->udma_mask);
@@ -4022,10 +4355,10 @@ void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
 
 
 /**
- *     ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data.
+ *     ata_pio_sector - Transfer a sector of data.
  *     @qc: Command on going
  *
- *     Transfer ATA_SECT_SIZE of data from/to the ATA device.
+ *     Transfer qc->sect_size bytes of data from/to the ATA device.
  *
  *     LOCKING:
  *     Inherited from caller.
@@ -4040,7 +4373,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
        unsigned int offset;
        unsigned char *buf;
 
-       if (qc->curbytes == qc->nbytes - ATA_SECT_SIZE)
+       if (qc->curbytes == qc->nbytes - qc->sect_size)
                ap->hsm_task_state = HSM_ST_LAST;
 
        page = sg[qc->cursg].page;
@@ -4060,17 +4393,17 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
                buf = kmap_atomic(page, KM_IRQ0);
 
                /* do the actual data transfer */
-               ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+               ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write);
 
                kunmap_atomic(buf, KM_IRQ0);
                local_irq_restore(flags);
        } else {
                buf = page_address(page);
-               ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+               ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write);
        }
 
-       qc->curbytes += ATA_SECT_SIZE;
-       qc->cursg_ofs += ATA_SECT_SIZE;
+       qc->curbytes += qc->sect_size;
+       qc->cursg_ofs += qc->sect_size;
 
        if (qc->cursg_ofs == (&sg[qc->cursg])->length) {
                qc->cursg++;
@@ -4079,10 +4412,10 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
 }
 
 /**
- *     ata_pio_sectors - Transfer one or many 512-byte sectors.
+ *     ata_pio_sectors - Transfer one or many sectors.
  *     @qc: Command on going
  *
- *     Transfer one or many ATA_SECT_SIZE of data from/to the
+ *     Transfer one or many sectors of data from/to the
  *     ATA device for the DRQ request.
  *
  *     LOCKING:
@@ -4097,7 +4430,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
 
                WARN_ON(qc->dev->multi_count == 0);
 
-               nsect = min((qc->nbytes - qc->curbytes) / ATA_SECT_SIZE,
+               nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size,
                            qc->dev->multi_count);
                while (nsect--)
                        ata_pio_sector(qc);
@@ -5577,42 +5910,35 @@ void ata_dev_init(struct ata_device *dev)
 }
 
 /**
- *     ata_port_init - Initialize an ata_port structure
- *     @ap: Structure to initialize
- *     @host: Collection of hosts to which @ap belongs
- *     @ent: Probe information provided by low-level driver
- *     @port_no: Port number associated with this ata_port
+ *     ata_port_alloc - allocate and initialize basic ATA port resources
+ *     @host: ATA host this allocated port belongs to
  *
- *     Initialize a new ata_port structure.
+ *     Allocate and initialize basic ATA port resources.
+ *
+ *     RETURNS:
+ *     Allocate ATA port on success, NULL on failure.
  *
  *     LOCKING:
- *     Inherited from caller.
+ *     Inherited from calling layer (may sleep).
  */
-void ata_port_init(struct ata_port *ap, struct ata_host *host,
-                  const struct ata_probe_ent *ent, unsigned int port_no)
+struct ata_port *ata_port_alloc(struct ata_host *host)
 {
+       struct ata_port *ap;
        unsigned int i;
 
+       DPRINTK("ENTER\n");
+
+       ap = kzalloc(sizeof(*ap), GFP_KERNEL);
+       if (!ap)
+               return NULL;
+
        ap->lock = &host->lock;
        ap->flags = ATA_FLAG_DISABLED;
-       ap->print_id = ata_print_id++;
+       ap->print_id = -1;
        ap->ctl = ATA_DEVCTL_OBS;
        ap->host = host;
-       ap->dev = ent->dev;
-       ap->port_no = port_no;
-       if (port_no == 1 && ent->pinfo2) {
-               ap->pio_mask = ent->pinfo2->pio_mask;
-               ap->mwdma_mask = ent->pinfo2->mwdma_mask;
-               ap->udma_mask = ent->pinfo2->udma_mask;
-               ap->flags |= ent->pinfo2->flags;
-               ap->ops = ent->pinfo2->port_ops;
-       } else {
-               ap->pio_mask = ent->pio_mask;
-               ap->mwdma_mask = ent->mwdma_mask;
-               ap->udma_mask = ent->udma_mask;
-               ap->flags |= ent->port_flags;
-               ap->ops = ent->port_ops;
-       }
+       ap->dev = host->dev;
+
        ap->hw_sata_spd_limit = UINT_MAX;
        ap->active_tag = ATA_TAG_POISON;
        ap->last_ctl = 0xFF;
@@ -5632,10 +5958,7 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
        INIT_LIST_HEAD(&ap->eh_done_q);
        init_waitqueue_head(&ap->eh_wait_q);
 
-       /* set cable type */
        ap->cbl = ATA_CBL_NONE;
-       if (ap->flags & ATA_FLAG_SATA)
-               ap->cbl = ATA_CBL_SATA;
 
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                struct ata_device *dev = &ap->device[i];
@@ -5648,100 +5971,209 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
        ap->stats.unhandled_irq = 1;
        ap->stats.idle_irq = 1;
 #endif
+       return ap;
+}
 
-       memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
+static void ata_host_release(struct device *gendev, void *res)
+{
+       struct ata_host *host = dev_get_drvdata(gendev);
+       int i;
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+
+               if (!ap)
+                       continue;
+
+               if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop)
+                       ap->ops->port_stop(ap);
+       }
+
+       if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop)
+               host->ops->host_stop(host);
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+
+               if (!ap)
+                       continue;
+
+               if (ap->scsi_host)
+                       scsi_host_put(ap->scsi_host);
+
+               kfree(ap);
+               host->ports[i] = NULL;
+       }
+
+       dev_set_drvdata(gendev, NULL);
 }
 
 /**
- *     ata_port_init_shost - Initialize SCSI host associated with ATA port
- *     @ap: ATA port to initialize SCSI host for
- *     @shost: SCSI host associated with @ap
+ *     ata_host_alloc - allocate and init basic ATA host resources
+ *     @dev: generic device this host is associated with
+ *     @max_ports: maximum number of ATA ports associated with this host
  *
- *     Initialize SCSI host @shost associated with ATA port @ap.
+ *     Allocate and initialize basic ATA host resources.  LLD calls
+ *     this function to allocate a host, initializes it fully and
+ *     attaches it using ata_host_register().
+ *
+ *     @max_ports ports are allocated and host->n_ports is
+ *     initialized to @max_ports.  The caller is allowed to decrease
+ *     host->n_ports before calling ata_host_register().  The unused
+ *     ports will be automatically freed on registration.
+ *
+ *     RETURNS:
+ *     Allocate ATA host on success, NULL on failure.
  *
  *     LOCKING:
- *     Inherited from caller.
+ *     Inherited from calling layer (may sleep).
  */
-static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost)
+struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
 {
-       ap->scsi_host = shost;
+       struct ata_host *host;
+       size_t sz;
+       int i;
+
+       DPRINTK("ENTER\n");
+
+       if (!devres_open_group(dev, NULL, GFP_KERNEL))
+               return NULL;
+
+       /* alloc a container for our list of ATA ports (buses) */
+       sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *);
+       /* alloc a container for our list of ATA ports (buses) */
+       host = devres_alloc(ata_host_release, sz, GFP_KERNEL);
+       if (!host)
+               goto err_out;
+
+       devres_add(dev, host);
+       dev_set_drvdata(dev, host);
 
-       shost->unique_id = ap->print_id;
-       shost->max_id = 16;
-       shost->max_lun = 1;
-       shost->max_channel = 1;
-       shost->max_cmd_len = 12;
+       spin_lock_init(&host->lock);
+       host->dev = dev;
+       host->n_ports = max_ports;
+
+       /* allocate ports bound to this host */
+       for (i = 0; i < max_ports; i++) {
+               struct ata_port *ap;
+
+               ap = ata_port_alloc(host);
+               if (!ap)
+                       goto err_out;
+
+               ap->port_no = i;
+               host->ports[i] = ap;
+       }
+
+       devres_remove_group(dev, NULL);
+       return host;
+
+ err_out:
+       devres_release_group(dev, NULL);
+       return NULL;
 }
 
 /**
- *     ata_port_add - Attach low-level ATA driver to system
- *     @ent: Information provided by low-level driver
- *     @host: Collections of ports to which we add
- *     @port_no: Port number associated with this host
+ *     ata_host_alloc_pinfo - alloc host and init with port_info array
+ *     @dev: generic device this host is associated with
+ *     @ppi: array of ATA port_info to initialize host with
+ *     @n_ports: number of ATA ports attached to this host
  *
- *     Attach low-level ATA driver to system.
- *
- *     LOCKING:
- *     PCI/etc. bus probe sem.
+ *     Allocate ATA host and initialize with info from @ppi.  If NULL
+ *     terminated, @ppi may contain fewer entries than @n_ports.  The
+ *     last entry will be used for the remaining ports.
  *
  *     RETURNS:
- *     New ata_port on success, for NULL on error.
+ *     Allocate ATA host on success, NULL on failure.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
  */
-static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
-                                     struct ata_host *host,
-                                     unsigned int port_no)
+struct ata_host *ata_host_alloc_pinfo(struct device *dev,
+                                     const struct ata_port_info * const * ppi,
+                                     int n_ports)
 {
-       struct Scsi_Host *shost;
-       struct ata_port *ap;
-
-       DPRINTK("ENTER\n");
+       const struct ata_port_info *pi;
+       struct ata_host *host;
+       int i, j;
 
-       if (!ent->port_ops->error_handler &&
-           !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
-               printk(KERN_ERR "ata%u: no reset mechanism available\n",
-                      port_no);
+       host = ata_host_alloc(dev, n_ports);
+       if (!host)
                return NULL;
-       }
 
-       shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
-       if (!shost)
-               return NULL;
+       for (i = 0, j = 0, pi = NULL; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
 
-       shost->transportt = &ata_scsi_transport_template;
+               if (ppi[j])
+                       pi = ppi[j++];
 
-       ap = ata_shost_to_port(shost);
+               ap->pio_mask = pi->pio_mask;
+               ap->mwdma_mask = pi->mwdma_mask;
+               ap->udma_mask = pi->udma_mask;
+               ap->flags |= pi->flags;
+               ap->ops = pi->port_ops;
 
-       ata_port_init(ap, host, ent, port_no);
-       ata_port_init_shost(ap, shost);
+               if (!host->ops && (pi->port_ops != &ata_dummy_port_ops))
+                       host->ops = pi->port_ops;
+               if (!host->private_data && pi->private_data)
+                       host->private_data = pi->private_data;
+       }
 
-       return ap;
+       return host;
 }
 
-static void ata_host_release(struct device *gendev, void *res)
+/**
+ *     ata_host_start - start and freeze ports of an ATA host
+ *     @host: ATA host to start ports for
+ *
+ *     Start and then freeze ports of @host.  Started status is
+ *     recorded in host->flags, so this function can be called
+ *     multiple times.  Ports are guaranteed to get started only
+ *     once.  If host->ops isn't initialized yet, its set to the
+ *     first non-dummy port ops.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 if all ports are started successfully, -errno otherwise.
+ */
+int ata_host_start(struct ata_host *host)
 {
-       struct ata_host *host = dev_get_drvdata(gendev);
-       int i;
+       int i, rc;
+
+       if (host->flags & ATA_HOST_STARTED)
+               return 0;
 
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
 
-               if (ap && ap->ops->port_stop)
-                       ap->ops->port_stop(ap);
+               if (!host->ops && !ata_port_is_dummy(ap))
+                       host->ops = ap->ops;
+
+               if (ap->ops->port_start) {
+                       rc = ap->ops->port_start(ap);
+                       if (rc) {
+                               ata_port_printk(ap, KERN_ERR, "failed to "
+                                               "start port (errno=%d)\n", rc);
+                               goto err_out;
+                       }
+               }
+
+               ata_eh_freeze_port(ap);
        }
 
-       if (host->ops->host_stop)
-               host->ops->host_stop(host);
+       host->flags |= ATA_HOST_STARTED;
+       return 0;
 
-       for (i = 0; i < host->n_ports; i++) {
+ err_out:
+       while (--i >= 0) {
                struct ata_port *ap = host->ports[i];
 
-               if (ap)
-                       scsi_host_put(ap->scsi_host);
-
-               host->ports[i] = NULL;
+               if (ap->ops->port_stop)
+                       ap->ops->port_stop(ap);
        }
-
-       dev_set_drvdata(gendev, NULL);
+       return rc;
 }
 
 /**
@@ -5755,7 +6187,7 @@ static void ata_host_release(struct device *gendev, void *res)
  *     PCI/etc. bus probe sem.
  *
  */
-
+/* KILLME - the only user left is ipr */
 void ata_host_init(struct ata_host *host, struct device *dev,
                   unsigned long flags, const struct ata_port_operations *ops)
 {
@@ -5766,155 +6198,95 @@ void ata_host_init(struct ata_host *host, struct device *dev,
 }
 
 /**
- *     ata_device_add - Register hardware device with ATA and SCSI layers
- *     @ent: Probe information describing hardware device to be registered
+ *     ata_host_register - register initialized ATA host
+ *     @host: ATA host to register
+ *     @sht: template for SCSI host
  *
- *     This function processes the information provided in the probe
- *     information struct @ent, allocates the necessary ATA and SCSI
- *     host information structures, initializes them, and registers
- *     everything with requisite kernel subsystems.
- *
- *     This function requests irqs, probes the ATA bus, and probes
- *     the SCSI bus.
+ *     Register initialized ATA host.  @host is allocated using
+ *     ata_host_alloc() and fully initialized by LLD.  This function
+ *     starts ports, registers @host with ATA and SCSI layers and
+ *     probe registered devices.
  *
  *     LOCKING:
- *     PCI/etc. bus probe sem.
+ *     Inherited from calling layer (may sleep).
  *
  *     RETURNS:
- *     Number of ports registered.  Zero on error (no ports registered).
+ *     0 on success, -errno otherwise.
  */
-int ata_device_add(const struct ata_probe_ent *ent)
+int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
 {
-       unsigned int i;
-       struct device *dev = ent->dev;
-       struct ata_host *host;
-       int rc;
-
-       DPRINTK("ENTER\n");
+       int i, rc;
 
-       if (ent->irq == 0) {
-               dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
-               return 0;
+       /* host must have been started */
+       if (!(host->flags & ATA_HOST_STARTED)) {
+               dev_printk(KERN_ERR, host->dev,
+                          "BUG: trying to register unstarted host\n");
+               WARN_ON(1);
+               return -EINVAL;
        }
 
-       if (!devres_open_group(dev, ata_device_add, GFP_KERNEL))
-               return 0;
+       /* Blow away unused ports.  This happens when LLD can't
+        * determine the exact number of ports to allocate at
+        * allocation time.
+        */
+       for (i = host->n_ports; host->ports[i]; i++)
+               kfree(host->ports[i]);
 
-       /* alloc a container for our list of ATA ports (buses) */
-       host = devres_alloc(ata_host_release, sizeof(struct ata_host) +
-                           (ent->n_ports * sizeof(void *)), GFP_KERNEL);
-       if (!host)
-               goto err_out;
-       devres_add(dev, host);
-       dev_set_drvdata(dev, host);
+       /* give ports names and add SCSI hosts */
+       for (i = 0; i < host->n_ports; i++)
+               host->ports[i]->print_id = ata_print_id++;
 
-       ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
-       host->n_ports = ent->n_ports;
-       host->irq = ent->irq;
-       host->irq2 = ent->irq2;
-       host->iomap = ent->iomap;
-       host->private_data = ent->private_data;
+       rc = ata_scsi_add_hosts(host, sht);
+       if (rc)
+               return rc;
 
-       /* register each port bound to this device */
+       /* set cable, sata_spd_limit and report */
        for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap;
-               unsigned long xfer_mode_mask;
-               int irq_line = ent->irq;
+               struct ata_port *ap = host->ports[i];
+               int irq_line;
+               u32 scontrol;
+               unsigned long xfer_mask;
 
-               ap = ata_port_add(ent, host, i);
-               host->ports[i] = ap;
-               if (!ap)
-                       goto err_out;
+               /* set SATA cable type if still unset */
+               if (ap->cbl == ATA_CBL_NONE && (ap->flags & ATA_FLAG_SATA))
+                       ap->cbl = ATA_CBL_SATA;
 
-               /* dummy? */
-               if (ent->dummy_port_mask & (1 << i)) {
-                       ata_port_printk(ap, KERN_INFO, "DUMMY\n");
-                       ap->ops = &ata_dummy_port_ops;
-                       continue;
-               }
-
-               /* start port */
-               rc = ap->ops->port_start(ap);
-               if (rc) {
-                       host->ports[i] = NULL;
-                       scsi_host_put(ap->scsi_host);
-                       goto err_out;
+               /* init sata_spd_limit to the current value */
+               if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
+                       int spd = (scontrol >> 4) & 0xf;
+                       ap->hw_sata_spd_limit &= (1 << spd) - 1;
                }
+               ap->sata_spd_limit = ap->hw_sata_spd_limit;
 
-               /* Report the secondary IRQ for second channel legacy */
-               if (i == 1 && ent->irq2)
-                       irq_line = ent->irq2;
+               /* report the secondary IRQ for second channel legacy */
+               irq_line = host->irq;
+               if (i == 1 && host->irq2)
+                       irq_line = host->irq2;
 
-               xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
-                               (ap->mwdma_mask << ATA_SHIFT_MWDMA) |
-                               (ap->pio_mask << ATA_SHIFT_PIO);
+               xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
+                                             ap->udma_mask);
 
                /* print per-port info to dmesg */
-               ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
-                               "ctl 0x%p bmdma 0x%p irq %d\n",
-                               ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
-                               ata_mode_string(xfer_mode_mask),
-                               ap->ioaddr.cmd_addr,
-                               ap->ioaddr.ctl_addr,
-                               ap->ioaddr.bmdma_addr,
-                               irq_line);
-
-               /* freeze port before requesting IRQ */
-               ata_eh_freeze_port(ap);
-       }
-
-       /* obtain irq, that may be shared between channels */
-       rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler,
-                             ent->irq_flags, DRV_NAME, host);
-       if (rc) {
-               dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
-                          ent->irq, rc);
-               goto err_out;
-       }
-
-       /* do we have a second IRQ for the other channel, eg legacy mode */
-       if (ent->irq2) {
-               /* We will get weird core code crashes later if this is true
-                  so trap it now */
-               BUG_ON(ent->irq == ent->irq2);
-
-               rc = devm_request_irq(dev, ent->irq2,
-                               ent->port_ops->irq_handler, ent->irq_flags,
-                               DRV_NAME, host);
-               if (rc) {
-                       dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
-                                  ent->irq2, rc);
-                       goto err_out;
-               }
+               if (!ata_port_is_dummy(ap))
+                       ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
+                                       "ctl 0x%p bmdma 0x%p irq %d\n",
+                                       ap->cbl == ATA_CBL_SATA ? 'S' : 'P',
+                                       ata_mode_string(xfer_mask),
+                                       ap->ioaddr.cmd_addr,
+                                       ap->ioaddr.ctl_addr,
+                                       ap->ioaddr.bmdma_addr,
+                                       irq_line);
+               else
+                       ata_port_printk(ap, KERN_INFO, "DUMMY\n");
        }
 
-       /* resource acquisition complete */
-       devres_remove_group(dev, ata_device_add);
-
        /* perform each probe synchronously */
        DPRINTK("probe begin\n");
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
-               u32 scontrol;
                int rc;
 
-               /* init sata_spd_limit to the current value */
-               if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
-                       int spd = (scontrol >> 4) & 0xf;
-                       ap->hw_sata_spd_limit &= (1 << spd) - 1;
-               }
-               ap->sata_spd_limit = ap->hw_sata_spd_limit;
-
-               rc = scsi_add_host(ap->scsi_host, dev);
-               if (rc) {
-                       ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
-                       /* FIXME: do something useful here */
-                       /* FIXME: handle unconditional calls to
-                        * scsi_scan_host and ata_host_remove, below,
-                        * at the very least
-                        */
-               }
-
+               /* probe */
                if (ap->ops->error_handler) {
                        struct ata_eh_info *ehi = &ap->eh_info;
                        unsigned long flags;
@@ -5959,15 +6331,51 @@ int ata_device_add(const struct ata_probe_ent *ent)
                ata_scsi_scan_host(ap);
        }
 
-       VPRINTK("EXIT, returning %u\n", ent->n_ports);
-       return ent->n_ports; /* success */
-
- err_out:
-       devres_release_group(dev, ata_device_add);
-       VPRINTK("EXIT, returning %d\n", rc);
        return 0;
 }
 
+/**
+ *     ata_host_activate - start host, request IRQ and register it
+ *     @host: target ATA host
+ *     @irq: IRQ to request
+ *     @irq_handler: irq_handler used when requesting IRQ
+ *     @irq_flags: irq_flags used when requesting IRQ
+ *     @sht: scsi_host_template to use when registering the host
+ *
+ *     After allocating an ATA host and initializing it, most libata
+ *     LLDs perform three steps to activate the host - start host,
+ *     request IRQ and register it.  This helper takes necessasry
+ *     arguments and performs the three steps in one go.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_host_activate(struct ata_host *host, int irq,
+                     irq_handler_t irq_handler, unsigned long irq_flags,
+                     struct scsi_host_template *sht)
+{
+       int rc;
+
+       rc = ata_host_start(host);
+       if (rc)
+               return rc;
+
+       rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
+                             dev_driver_string(host->dev), host);
+       if (rc)
+               return rc;
+
+       rc = ata_host_register(host, sht);
+       /* if failed, just free the IRQ and leave ports alone */
+       if (rc)
+               devm_free_irq(host->dev, irq, host);
+
+       return rc;
+}
+
 /**
  *     ata_port_detach - Detach ATA port in prepration of device removal
  *     @ap: ATA port to be detached
@@ -6043,32 +6451,6 @@ void ata_host_detach(struct ata_host *host)
                ata_port_detach(host->ports[i]);
 }
 
-struct ata_probe_ent *
-ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
-{
-       struct ata_probe_ent *probe_ent;
-
-       probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (!probe_ent) {
-               printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
-                      kobject_name(&(dev->kobj)));
-               return NULL;
-       }
-
-       INIT_LIST_HEAD(&probe_ent->node);
-       probe_ent->dev = dev;
-
-       probe_ent->sht = port->sht;
-       probe_ent->port_flags = port->flags;
-       probe_ent->pio_mask = port->pio_mask;
-       probe_ent->mwdma_mask = port->mwdma_mask;
-       probe_ent->udma_mask = port->udma_mask;
-       probe_ent->port_ops = port->port_ops;
-       probe_ent->private_data = port->private_data;
-
-       return probe_ent;
-}
-
 /**
  *     ata_std_ports - initialize ioaddr with standard port offsets.
  *     @ioaddr: IO address structure to be initialized
@@ -6334,6 +6716,10 @@ const struct ata_port_operations ata_dummy_port_ops = {
        .port_stop              = ata_dummy_noret,
 };
 
+const struct ata_port_info ata_dummy_port_info = {
+       .port_ops               = &ata_dummy_port_ops,
+};
+
 /*
  * libata is essentially a library of internal helper functions for
  * low-level ATA host controller drivers.  As such, the API/ABI is
@@ -6345,10 +6731,15 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
 EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
 EXPORT_SYMBOL_GPL(sata_deb_timing_long);
 EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
+EXPORT_SYMBOL_GPL(ata_dummy_port_info);
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_host_init);
-EXPORT_SYMBOL_GPL(ata_device_add);
+EXPORT_SYMBOL_GPL(ata_host_alloc);
+EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
+EXPORT_SYMBOL_GPL(ata_host_start);
+EXPORT_SYMBOL_GPL(ata_host_register);
+EXPORT_SYMBOL_GPL(ata_host_activate);
 EXPORT_SYMBOL_GPL(ata_host_detach);
 EXPORT_SYMBOL_GPL(ata_sg_init);
 EXPORT_SYMBOL_GPL(ata_sg_init_one);
@@ -6360,6 +6751,7 @@ EXPORT_SYMBOL_GPL(ata_tf_load);
 EXPORT_SYMBOL_GPL(ata_tf_read);
 EXPORT_SYMBOL_GPL(ata_noop_dev_select);
 EXPORT_SYMBOL_GPL(ata_std_dev_select);
+EXPORT_SYMBOL_GPL(sata_print_link_status);
 EXPORT_SYMBOL_GPL(ata_tf_to_fis);
 EXPORT_SYMBOL_GPL(ata_tf_from_fis);
 EXPORT_SYMBOL_GPL(ata_check_status);
@@ -6367,6 +6759,7 @@ EXPORT_SYMBOL_GPL(ata_altstatus);
 EXPORT_SYMBOL_GPL(ata_exec_command);
 EXPORT_SYMBOL_GPL(ata_port_start);
 EXPORT_SYMBOL_GPL(ata_interrupt);
+EXPORT_SYMBOL_GPL(ata_do_set_mode);
 EXPORT_SYMBOL_GPL(ata_data_xfer);
 EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
 EXPORT_SYMBOL_GPL(ata_qc_prep);
@@ -6429,7 +6822,8 @@ EXPORT_SYMBOL_GPL(ata_timing_merge);
 
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL_GPL(pci_test_config_bits);
-EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
+EXPORT_SYMBOL_GPL(ata_pci_init_native_host);
+EXPORT_SYMBOL_GPL(ata_pci_prepare_native_host);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
 #ifdef CONFIG_PM
@@ -6461,3 +6855,8 @@ EXPORT_SYMBOL_GPL(ata_dummy_irq_on);
 EXPORT_SYMBOL_GPL(ata_irq_ack);
 EXPORT_SYMBOL_GPL(ata_dummy_irq_ack);
 EXPORT_SYMBOL_GPL(ata_dev_try_classify);
+
+EXPORT_SYMBOL_GPL(ata_cable_40wire);
+EXPORT_SYMBOL_GPL(ata_cable_80wire);
+EXPORT_SYMBOL_GPL(ata_cable_unknown);
+EXPORT_SYMBOL_GPL(ata_cable_sata);
index 39f556c0299265ffb99a4430588f7aa9cac194ff..2bff9adcacf15de02b7f0f6c35f83116410df606 100644 (file)
@@ -1056,7 +1056,7 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
        }
        if (serror & SERR_INTERNAL) {
                err_mask |= AC_ERR_SYSTEM;
-               action |= ATA_EH_SOFTRESET;
+               action |= ATA_EH_HARDRESET;
        }
        if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
                ata_ehi_hotplugged(&ehc->i);
@@ -1151,7 +1151,9 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
                return ATA_EH_SOFTRESET;
        }
 
-       if (!(qc->err_mask & AC_ERR_DEV))
+       if (stat & (ATA_ERR | ATA_DF))
+               qc->err_mask |= AC_ERR_DEV;
+       else
                return 0;
 
        switch (qc->dev->class) {
@@ -1669,7 +1671,10 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                                reset == softreset ? "soft" : "hard");
 
        /* mark that this EH session started with reset */
-       ehc->i.flags |= ATA_EHI_DID_RESET;
+       if (reset == hardreset)
+               ehc->i.flags |= ATA_EHI_DID_HARDRESET;
+       else
+               ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
 
        rc = ata_do_reset(ap, reset, classes);
 
@@ -1808,6 +1813,10 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
                }
        }
 
+       /* PDIAG- should have been released, ask cable type if post-reset */
+       if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect)
+               ap->cbl = ap->ops->cable_detect(ap);
+
        /* Configure new devices forward such that user doesn't see
         * device detection messages backwards.
         */
index e9364434182c437fe8e0cb73e38d60a73803ed29..9afba2ba489e52097bc5fca2fe8fd98747b6b887 100644 (file)
@@ -104,7 +104,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
  * libata transport template.  libata doesn't do real transport stuff.
  * It just needs the eh_timed_out hook.
  */
-struct scsi_transport_template ata_scsi_transport_template = {
+static struct scsi_transport_template ata_scsi_transport_template = {
        .eh_strategy_handler    = ata_scsi_error,
        .eh_timed_out           = ata_scsi_timed_out,
        .user_scan              = ata_scsi_user_scan,
@@ -2678,6 +2678,18 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
                tf->device = qc->dev->devno ?
                        tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
 
+       /* READ/WRITE LONG use a non-standard sect_size */
+       qc->sect_size = ATA_SECT_SIZE;
+       switch (tf->command) {
+       case ATA_CMD_READ_LONG:
+       case ATA_CMD_READ_LONG_ONCE:
+       case ATA_CMD_WRITE_LONG:
+       case ATA_CMD_WRITE_LONG_ONCE:
+               if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
+                       goto invalid_fld;
+               qc->sect_size = scmd->request_bufflen;
+       }
+
        /*
         * Filter SET_FEATURES - XFER MODE command -- otherwise,
         * SET_FEATURES - XFER MODE must be preceded/succeeded
@@ -2792,8 +2804,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
 {
        int rc = 0;
 
-       if (unlikely(!scmd->cmd_len)) {
-               ata_dev_printk(dev, KERN_WARNING, "WARNING: zero len CDB\n");
+       if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) {
+               DPRINTK("bad CDB len=%u, max=%u\n",
+                       scmd->cmd_len, dev->cdb_len);
                scmd->result = DID_ERROR << 16;
                done(scmd);
                return 0;
@@ -2948,6 +2961,48 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
        }
 }
 
+int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
+{
+       int i, rc;
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+               struct Scsi_Host *shost;
+
+               rc = -ENOMEM;
+               shost = scsi_host_alloc(sht, sizeof(struct ata_port *));
+               if (!shost)
+                       goto err_alloc;
+
+               *(struct ata_port **)&shost->hostdata[0] = ap;
+               ap->scsi_host = shost;
+
+               shost->transportt = &ata_scsi_transport_template;
+               shost->unique_id = ap->print_id;
+               shost->max_id = 16;
+               shost->max_lun = 1;
+               shost->max_channel = 1;
+               shost->max_cmd_len = 16;
+
+               rc = scsi_add_host(ap->scsi_host, ap->host->dev);
+               if (rc)
+                       goto err_add;
+       }
+
+       return 0;
+
+ err_add:
+       scsi_host_put(host->ports[i]->scsi_host);
+ err_alloc:
+       while (--i >= 0) {
+               struct Scsi_Host *shost = host->ports[i]->scsi_host;
+
+               scsi_remove_host(shost);
+               scsi_host_put(shost);
+       }
+       return rc;
+}
+
 void ata_scsi_scan_host(struct ata_port *ap)
 {
        unsigned int i;
@@ -3224,21 +3279,21 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host,
                                    struct ata_port_info *port_info,
                                    struct Scsi_Host *shost)
 {
-       struct ata_port *ap = kzalloc(sizeof(*ap), GFP_KERNEL);
-       struct ata_probe_ent *ent;
+       struct ata_port *ap;
 
+       ap = ata_port_alloc(host);
        if (!ap)
                return NULL;
 
-       ent = ata_probe_ent_alloc(host->dev, port_info);
-       if (!ent) {
-               kfree(ap);
-               return NULL;
-       }
-
-       ata_port_init(ap, host, ent, 0);
+       ap->port_no = 0;
        ap->lock = shost->host_lock;
-       devm_kfree(host->dev, ent);
+       ap->pio_mask = port_info->pio_mask;
+       ap->mwdma_mask = port_info->mwdma_mask;
+       ap->udma_mask = port_info->udma_mask;
+       ap->flags |= port_info->flags;
+       ap->ops = port_info->port_ops;
+       ap->cbl = ATA_CBL_SATA;
+
        return ap;
 }
 EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
@@ -3294,8 +3349,10 @@ int ata_sas_port_init(struct ata_port *ap)
 {
        int rc = ap->ops->port_start(ap);
 
-       if (!rc)
+       if (!rc) {
+               ap->print_id = ata_print_id++;
                rc = ata_bus_probe(ap);
+       }
 
        return rc;
 }
index 2ffcca063d80adc3405ab16c484ab7da8788a5d5..8af18ad1ca7f4de2856d6a21b7b495771305120f 100644 (file)
@@ -526,168 +526,399 @@ static int ata_resources_present(struct pci_dev *pdev, int port)
        port = port * 2;
        for (i = 0; i < 2; i ++) {
                if (pci_resource_start(pdev, port + i) == 0 ||
-                       pci_resource_len(pdev, port + i) == 0)
-               return 0;
+                   pci_resource_len(pdev, port + i) == 0)
+                       return 0;
        }
        return 1;
 }
 
 /**
- *     ata_pci_init_native_mode - Initialize native-mode driver
- *     @pdev:  pci device to be initialized
- *     @port:  array[2] of pointers to port info structures.
- *     @ports: bitmap of ports present
- *
- *     Utility function which allocates and initializes an
- *     ata_probe_ent structure for a standard dual-port
- *     PIO-based IDE controller.  The returned ata_probe_ent
- *     structure can be passed to ata_device_add().  The returned
- *     ata_probe_ent structure should then be freed with kfree().
- *
- *     The caller need only pass the address of the primary port, the
- *     secondary will be deduced automatically. If the device has non
- *     standard secondary port mappings this function can be called twice,
- *     once for each interface.
+ *     ata_pci_init_bmdma - acquire PCI BMDMA resources and init ATA host
+ *     @host: target ATA host
+ *
+ *     Acquire PCI BMDMA resources and initialize @host accordingly.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
  */
+static int ata_pci_init_bmdma(struct ata_host *host)
+{
+       struct device *gdev = host->dev;
+       struct pci_dev *pdev = to_pci_dev(gdev);
+       int i, rc;
+
+       /* TODO: If we get no DMA mask we should fall back to PIO */
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               return rc;
+       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               return rc;
+
+       /* request and iomap DMA region */
+       rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME);
+       if (rc) {
+               dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n");
+               return -ENOMEM;
+       }
+       host->iomap = pcim_iomap_table(pdev);
+
+       for (i = 0; i < 2; i++) {
+               struct ata_port *ap = host->ports[i];
+               void __iomem *bmdma = host->iomap[4] + 8 * i;
+
+               if (ata_port_is_dummy(ap))
+                       continue;
+
+               ap->ioaddr.bmdma_addr = bmdma;
+               if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
+                   (ioread8(bmdma + 2) & 0x80))
+                       host->flags |= ATA_HOST_SIMPLEX;
+       }
+
+       return 0;
+}
 
-struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
+/**
+ *     ata_pci_init_native_host - acquire native ATA resources and init host
+ *     @host: target ATA host
+ *     @port_mask: ports to consider
+ *
+ *     Acquire native PCI ATA resources for @host and initialize
+ *     @host accordoingly.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_pci_init_native_host(struct ata_host *host, unsigned int port_mask)
 {
-       struct ata_probe_ent *probe_ent;
-       int i, p = 0;
-       void __iomem * const *iomap;
-
-       /* iomap BARs */
-       for (i = 0; i < 4; i++) {
-               if (pcim_iomap(pdev, i, 0) == NULL) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "failed to iomap PCI BAR %d\n", i);
-                       return NULL;
+       struct device *gdev = host->dev;
+       struct pci_dev *pdev = to_pci_dev(gdev);
+       int i, rc;
+
+       /* Discard disabled ports.  Some controllers show their unused
+        * channels this way.  Disabled ports are made dummy.
+        */
+       for (i = 0; i < 2; i++) {
+               if ((port_mask & (1 << i)) && !ata_resources_present(pdev, i)) {
+                       host->ports[i]->ops = &ata_dummy_port_ops;
+                       port_mask &= ~(1 << i);
                }
        }
 
-       pcim_iomap(pdev, 4, 0); /* may fail */
-       iomap = pcim_iomap_table(pdev);
-
-       /* alloc and init probe_ent */
-       probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
-       if (!probe_ent)
-               return NULL;
-
-       probe_ent->irq = pdev->irq;
-       probe_ent->irq_flags = IRQF_SHARED;
-
-       /* Discard disabled ports. Some controllers show their
-          unused channels this way */
-       if (ata_resources_present(pdev, 0) == 0)
-               ports &= ~ATA_PORT_PRIMARY;
-       if (ata_resources_present(pdev, 1) == 0)
-               ports &= ~ATA_PORT_SECONDARY;
-
-       if (ports & ATA_PORT_PRIMARY) {
-               probe_ent->port[p].cmd_addr = iomap[0];
-               probe_ent->port[p].altstatus_addr =
-               probe_ent->port[p].ctl_addr = (void __iomem *)
-                       ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS);
-               if (iomap[4]) {
-                       if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
-                           (ioread8(iomap[4] + 2) & 0x80))
-                               probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
-                       probe_ent->port[p].bmdma_addr = iomap[4];
-               }
-               ata_std_ports(&probe_ent->port[p]);
-               p++;
+       if (!port_mask) {
+               dev_printk(KERN_ERR, gdev, "no available port\n");
+               return -ENODEV;
        }
 
-       if (ports & ATA_PORT_SECONDARY) {
-               probe_ent->port[p].cmd_addr = iomap[2];
-               probe_ent->port[p].altstatus_addr =
-               probe_ent->port[p].ctl_addr = (void __iomem *)
-                       ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS);
-               if (iomap[4]) {
-                       if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
-                           (ioread8(iomap[4] + 10) & 0x80))
-                               probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
-                       probe_ent->port[p].bmdma_addr = iomap[4] + 8;
+       /* request, iomap BARs and init port addresses accordingly */
+       for (i = 0; i < 2; i++) {
+               struct ata_port *ap = host->ports[i];
+               int base = i * 2;
+               void __iomem * const *iomap;
+
+               if (!(port_mask & (1 << i)))
+                       continue;
+
+               rc = pcim_iomap_regions(pdev, 0x3 << base, DRV_NAME);
+               if (rc) {
+                       dev_printk(KERN_ERR, gdev, "failed to request/iomap "
+                                  "BARs for port %d (errno=%d)\n", i, rc);
+                       if (rc == -EBUSY)
+                               pcim_pin_device(pdev);
+                       return rc;
                }
-               ata_std_ports(&probe_ent->port[p]);
-               probe_ent->pinfo2 = port[1];
-               p++;
+               host->iomap = iomap = pcim_iomap_table(pdev);
+
+               ap->ioaddr.cmd_addr = iomap[base];
+               ap->ioaddr.altstatus_addr =
+               ap->ioaddr.ctl_addr = (void __iomem *)
+                       ((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS);
+               ata_std_ports(&ap->ioaddr);
        }
 
-       probe_ent->n_ports = p;
-       return probe_ent;
+       return 0;
 }
 
-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
-                               struct ata_port_info **port, int port_mask)
+/**
+ *     ata_pci_prepare_native_host - helper to prepare native PCI ATA host
+ *     @pdev: target PCI device
+ *     @ppi: array of port_info
+ *     @n_ports: number of ports to allocate
+ *     @r_host: out argument for the initialized ATA host
+ *
+ *     Helper to allocate ATA host for @pdev, acquire all native PCI
+ *     resources and initialize it accordingly in one go.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_pci_prepare_native_host(struct pci_dev *pdev,
+                               const struct ata_port_info * const * ppi,
+                               int n_ports, struct ata_host **r_host)
+{
+       struct ata_host *host;
+       unsigned int port_mask;
+       int rc;
+
+       if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
+               return -ENOMEM;
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+       if (!host) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "failed to allocate ATA host\n");
+               rc = -ENOMEM;
+               goto err_out;
+       }
+
+       port_mask = ATA_PORT_PRIMARY;
+       if (n_ports > 1)
+               port_mask |= ATA_PORT_SECONDARY;
+
+       rc = ata_pci_init_native_host(host, port_mask);
+       if (rc)
+               goto err_out;
+
+       /* init DMA related stuff */
+       rc = ata_pci_init_bmdma(host);
+       if (rc)
+               goto err_bmdma;
+
+       devres_remove_group(&pdev->dev, NULL);
+       *r_host = host;
+       return 0;
+
+ err_bmdma:
+       /* This is necessary because PCI and iomap resources are
+        * merged and releasing the top group won't release the
+        * acquired resources if some of those have been acquired
+        * before entering this function.
+        */
+       pcim_iounmap_regions(pdev, 0xf);
+ err_out:
+       devres_release_group(&pdev->dev, NULL);
+       return rc;
+}
+
+struct ata_legacy_devres {
+       unsigned int    mask;
+       unsigned long   cmd_port[2];
+       void __iomem *  cmd_addr[2];
+       void __iomem *  ctl_addr[2];
+       unsigned int    irq[2];
+       void *          irq_dev_id[2];
+};
+
+static void ata_legacy_free_irqs(struct ata_legacy_devres *legacy_dr)
 {
-       struct ata_probe_ent *probe_ent;
-       void __iomem *iomap[5] = { }, *bmdma;
-
-       if (port_mask & ATA_PORT_PRIMARY) {
-               iomap[0] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CMD, 8);
-               iomap[1] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CTL, 1);
-               if (!iomap[0] || !iomap[1])
-                       return NULL;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               if (!legacy_dr->irq[i])
+                       continue;
+
+               free_irq(legacy_dr->irq[i], legacy_dr->irq_dev_id[i]);
+               legacy_dr->irq[i] = 0;
+               legacy_dr->irq_dev_id[i] = NULL;
        }
+}
+
+static void ata_legacy_release(struct device *gdev, void *res)
+{
+       struct ata_legacy_devres *this = res;
+       int i;
 
-       if (port_mask & ATA_PORT_SECONDARY) {
-               iomap[2] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CMD, 8);
-               iomap[3] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CTL, 1);
-               if (!iomap[2] || !iomap[3])
-                       return NULL;
+       ata_legacy_free_irqs(this);
+
+       for (i = 0; i < 2; i++) {
+               if (this->cmd_addr[i])
+                       ioport_unmap(this->cmd_addr[i]);
+               if (this->ctl_addr[i])
+                       ioport_unmap(this->ctl_addr[i]);
+               if (this->cmd_port[i])
+                       release_region(this->cmd_port[i], 8);
        }
+}
 
-       bmdma = pcim_iomap(pdev, 4, 16); /* may fail */
-
-       /* alloc and init probe_ent */
-       probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
-       if (!probe_ent)
-               return NULL;
-
-       probe_ent->n_ports = 2;
-       probe_ent->irq_flags = IRQF_SHARED;
-
-       if (port_mask & ATA_PORT_PRIMARY) {
-               probe_ent->irq = ATA_PRIMARY_IRQ(pdev);
-               probe_ent->port[0].cmd_addr = iomap[0];
-               probe_ent->port[0].altstatus_addr =
-               probe_ent->port[0].ctl_addr = iomap[1];
-               if (bmdma) {
-                       probe_ent->port[0].bmdma_addr = bmdma;
-                       if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
-                           (ioread8(bmdma + 2) & 0x80))
-                               probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
-               }
-               ata_std_ports(&probe_ent->port[0]);
-       } else
-               probe_ent->dummy_port_mask |= ATA_PORT_PRIMARY;
+static int ata_init_legacy_port(struct ata_port *ap,
+                               struct ata_legacy_devres *legacy_dr)
+{
+       struct ata_host *host = ap->host;
+       int port_no = ap->port_no;
+       unsigned long cmd_port, ctl_port;
+
+       if (port_no == 0) {
+               cmd_port = ATA_PRIMARY_CMD;
+               ctl_port = ATA_PRIMARY_CTL;
+       } else {
+               cmd_port = ATA_SECONDARY_CMD;
+               ctl_port = ATA_SECONDARY_CTL;
+       }
 
-       if (port_mask & ATA_PORT_SECONDARY) {
-               if (probe_ent->irq)
-                       probe_ent->irq2 = ATA_SECONDARY_IRQ(pdev);
+       /* request cmd_port */
+       if (request_region(cmd_port, 8, "libata"))
+               legacy_dr->cmd_port[port_no] = cmd_port;
+       else {
+               dev_printk(KERN_WARNING, host->dev,
+                          "0x%0lX IDE port busy\n", cmd_port);
+               return -EBUSY;
+       }
+
+       /* iomap cmd and ctl ports */
+       legacy_dr->cmd_addr[port_no] = ioport_map(cmd_port, 8);
+       legacy_dr->ctl_addr[port_no] = ioport_map(ctl_port, 1);
+       if (!legacy_dr->cmd_addr[port_no] || !legacy_dr->ctl_addr[port_no])
+               return -ENOMEM;
+
+       /* init IO addresses */
+       ap->ioaddr.cmd_addr = legacy_dr->cmd_addr[port_no];
+       ap->ioaddr.altstatus_addr = legacy_dr->ctl_addr[port_no];
+       ap->ioaddr.ctl_addr = legacy_dr->ctl_addr[port_no];
+       ata_std_ports(&ap->ioaddr);
+
+       return 0;
+}
+
+/**
+ *     ata_init_legacy_host - acquire legacy ATA resources and init ATA host
+ *     @host: target ATA host
+ *     @legacy_mask: out parameter, mask indicating ports is in legacy mode
+ *     @was_busy: out parameter, indicates whether any port was busy
+ *
+ *     Acquire legacy ATA resources for ports.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+static int ata_init_legacy_host(struct ata_host *host,
+                               unsigned int *legacy_mask, int *was_busy)
+{
+       struct device *gdev = host->dev;
+       struct ata_legacy_devres *legacy_dr;
+       int i, rc;
+
+       if (!devres_open_group(gdev, NULL, GFP_KERNEL))
+               return -ENOMEM;
+
+       rc = -ENOMEM;
+       legacy_dr = devres_alloc(ata_legacy_release, sizeof(*legacy_dr),
+                                GFP_KERNEL);
+       if (!legacy_dr)
+               goto err_out;
+       devres_add(gdev, legacy_dr);
+
+       for (i = 0; i < 2; i++) {
+               *legacy_mask &= ~(1 << i);
+               rc = ata_init_legacy_port(host->ports[i], legacy_dr);
+               if (rc == 0)
+                       legacy_dr->mask |= 1 << i;
+               else if (rc == -EBUSY)
+                       (*was_busy)++;
+       }
+
+       if (!legacy_dr->mask)
+               return -EBUSY;
+
+       for (i = 0; i < 2; i++)
+               if (!(legacy_dr->mask & (1 << i)))
+                       host->ports[i]->ops = &ata_dummy_port_ops;
+
+       *legacy_mask |= legacy_dr->mask;
+
+       devres_remove_group(gdev, NULL);
+       return 0;
+
+ err_out:
+       devres_release_group(gdev, NULL);
+       return rc;
+}
+
+/**
+ *     ata_request_legacy_irqs - request legacy ATA IRQs
+ *     @host: target ATA host
+ *     @handler: array of IRQ handlers
+ *     @irq_flags: array of IRQ flags
+ *     @dev_id: array of IRQ dev_ids
+ *
+ *     Request legacy IRQs for non-dummy legacy ports in @host.  All
+ *     IRQ parameters are passed as array to allow ports to have
+ *     separate IRQ handlers.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+static int ata_request_legacy_irqs(struct ata_host *host,
+                                  irq_handler_t const *handler,
+                                  const unsigned int *irq_flags,
+                                  void * const *dev_id)
+{
+       struct device *gdev = host->dev;
+       struct ata_legacy_devres *legacy_dr;
+       int i, rc;
+
+       legacy_dr = devres_find(host->dev, ata_legacy_release, NULL, NULL);
+       BUG_ON(!legacy_dr);
+
+       for (i = 0; i < 2; i++) {
+               unsigned int irq;
+
+               /* FIXME: ATA_*_IRQ() should take generic device not pci_dev */
+               if (i == 0)
+                       irq = ATA_PRIMARY_IRQ(to_pci_dev(gdev));
                else
-                       probe_ent->irq = ATA_SECONDARY_IRQ(pdev);
-               probe_ent->port[1].cmd_addr = iomap[2];
-               probe_ent->port[1].altstatus_addr =
-               probe_ent->port[1].ctl_addr = iomap[3];
-               if (bmdma) {
-                       probe_ent->port[1].bmdma_addr = bmdma + 8;
-                       if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
-                           (ioread8(bmdma + 10) & 0x80))
-                               probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+                       irq = ATA_SECONDARY_IRQ(to_pci_dev(gdev));
+
+               if (!(legacy_dr->mask & (1 << i)))
+                       continue;
+
+               if (!handler[i]) {
+                       dev_printk(KERN_ERR, gdev,
+                                  "NULL handler specified for port %d\n", i);
+                       rc = -EINVAL;
+                       goto err_out;
+               }
+
+               rc = request_irq(irq, handler[i], irq_flags[i], DRV_NAME,
+                                dev_id[i]);
+               if (rc) {
+                       dev_printk(KERN_ERR, gdev,
+                               "irq %u request failed (errno=%d)\n", irq, rc);
+                       goto err_out;
                }
-               ata_std_ports(&probe_ent->port[1]);
 
-               /* FIXME: could be pointing to stack area; must copy */
-               probe_ent->pinfo2 = port[1];
-       } else
-               probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
+               /* record irq allocation in legacy_dr */
+               legacy_dr->irq[i] = irq;
+               legacy_dr->irq_dev_id[i] = dev_id[i];
 
-       return probe_ent;
-}
+               /* only used to print info */
+               if (i == 0)
+                       host->irq = irq;
+               else
+                       host->irq2 = irq;
+       }
 
+       return 0;
+
+ err_out:
+       ata_legacy_free_irqs(legacy_dr);
+       return rc;
+}
 
 /**
  *     ata_pci_init_one - Initialize/register PCI IDE host controller
@@ -718,8 +949,8 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
                      unsigned int n_ports)
 {
        struct device *dev = &pdev->dev;
-       struct ata_probe_ent *probe_ent = NULL;
-       struct ata_port_info *port[2];
+       struct ata_host *host = NULL;
+       const struct ata_port_info *port[2];
        u8 mask;
        unsigned int legacy_mode = 0;
        int rc;
@@ -743,7 +974,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
 
           Checking dev->is_enabled is insufficient as this is not set at
           boot for the primary video which is BIOS enabled
-         */
+         */
 
        rc = pcim_enable_device(pdev);
        if (rc)
@@ -769,96 +1000,68 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
 #endif
        }
 
+       /* alloc and init host */
+       host = ata_host_alloc_pinfo(dev, port, 2);
+       if (!host) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "failed to allocate ATA host\n");
+               rc = -ENOMEM;
+               goto err_out;
+       }
+
        if (!legacy_mode) {
-               rc = pci_request_regions(pdev, DRV_NAME);
-               if (rc) {
-                       pcim_pin_device(pdev);
+               unsigned int port_mask;
+
+               port_mask = ATA_PORT_PRIMARY;
+               if (n_ports > 1)
+                       port_mask |= ATA_PORT_SECONDARY;
+
+               rc = ata_pci_init_native_host(host, port_mask);
+               if (rc)
                        goto err_out;
-               }
        } else {
-               /* Deal with combined mode hack. This side of the logic all
-                  goes away once the combined mode hack is killed in 2.6.21 */
-               if (!devm_request_region(dev, ATA_PRIMARY_CMD, 8, "libata")) {
-                       struct resource *conflict, res;
-                       res.start = ATA_PRIMARY_CMD;
-                       res.end = ATA_PRIMARY_CMD + 8 - 1;
-                       conflict = ____request_resource(&ioport_resource, &res);
-                       while (conflict->child)
-                               conflict = ____request_resource(conflict, &res);
-                       if (!strcmp(conflict->name, "libata"))
-                               legacy_mode |= ATA_PORT_PRIMARY;
-                       else {
-                               pcim_pin_device(pdev);
-                               printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \
-                                                   "ata: conflict with %s\n",
-                                                   ATA_PRIMARY_CMD,
-                                                   conflict->name);
-                       }
-               } else
-                       legacy_mode |= ATA_PORT_PRIMARY;
-
-               if (!devm_request_region(dev, ATA_SECONDARY_CMD, 8, "libata")) {
-                       struct resource *conflict, res;
-                       res.start = ATA_SECONDARY_CMD;
-                       res.end = ATA_SECONDARY_CMD + 8 - 1;
-                       conflict = ____request_resource(&ioport_resource, &res);
-                       while (conflict->child)
-                               conflict = ____request_resource(conflict, &res);
-                       if (!strcmp(conflict->name, "libata"))
-                               legacy_mode |= ATA_PORT_SECONDARY;
-                       else {
-                               pcim_pin_device(pdev);
-                               printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \
-                                                   "ata: conflict with %s\n",
-                                                   ATA_SECONDARY_CMD,
-                                                   conflict->name);
-                       }
-               } else
-                       legacy_mode |= ATA_PORT_SECONDARY;
-
-               if (legacy_mode & ATA_PORT_PRIMARY)
-                       pci_request_region(pdev, 1, DRV_NAME);
-               if (legacy_mode & ATA_PORT_SECONDARY)
-                       pci_request_region(pdev, 3, DRV_NAME);
-               /* If there is a DMA resource, allocate it */
-               pci_request_region(pdev, 4, DRV_NAME);
-       }
+               int was_busy = 0;
 
-       /* we have legacy mode, but all ports are unavailable */
-       if (legacy_mode == (1 << 3)) {
-               rc = -EBUSY;
-               goto err_out;
+               rc = ata_init_legacy_host(host, &legacy_mode, &was_busy);
+               if (was_busy)
+                       pcim_pin_device(pdev);
+               if (rc)
+                       goto err_out;
+
+               /* request respective PCI regions, may fail */
+               rc = pci_request_region(pdev, 1, DRV_NAME);
+               rc = pci_request_region(pdev, 3, DRV_NAME);
        }
 
-       /* TODO: If we get no DMA mask we should fall back to PIO */
-       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-       if (rc)
-               goto err_out;
-       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+       /* init BMDMA, may fail */
+       ata_pci_init_bmdma(host);
+       pci_set_master(pdev);
+
+       /* start host and request IRQ */
+       rc = ata_host_start(host);
        if (rc)
                goto err_out;
 
-       if (legacy_mode) {
-               probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode);
-       } else {
-               if (n_ports == 2)
-                       probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-               else
-                       probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
+       if (!legacy_mode)
+               rc = devm_request_irq(dev, pdev->irq,
+                                     port_info[0]->port_ops->irq_handler,
+                                     IRQF_SHARED, DRV_NAME, host);
+       else {
+               irq_handler_t handler[2] = { host->ops->irq_handler,
+                                            host->ops->irq_handler };
+               unsigned int irq_flags[2] = { IRQF_SHARED, IRQF_SHARED };
+               void *dev_id[2] = { host, host };
+
+               rc = ata_request_legacy_irqs(host, handler, irq_flags, dev_id);
        }
-       if (!probe_ent) {
-               rc = -ENOMEM;
+       if (rc)
                goto err_out;
-       }
-
-       pci_set_master(pdev);
 
-       if (!ata_device_add(probe_ent)) {
-               rc = -ENODEV;
+       /* register */
+       rc = ata_host_register(host, port_info[0]->sht);
+       if (rc)
                goto err_out;
-       }
 
-       devm_kfree(dev, probe_ent);
        devres_remove_group(dev, NULL);
        return 0;
 
@@ -893,12 +1096,12 @@ int ata_pci_clear_simplex(struct pci_dev *pdev)
        return 0;
 }
 
-unsigned long ata_pci_default_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long xfer_mask)
+unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer_mask)
 {
        /* Filter out DMA modes if the device has been configured by
           the BIOS as PIO only */
 
-       if (ap->ioaddr.bmdma_addr == 0)
+       if (adev->ap->ioaddr.bmdma_addr == 0)
                xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
        return xfer_mask;
 }
index 1f1e3a51f85965f7cebadb3f6b10cfbdb07afb29..5f4d40cd32888a9aaae5c3dc76a2bb3d84bd69aa 100644 (file)
@@ -52,6 +52,7 @@ enum {
        ATA_DNXFER_QUIET        = (1 << 31),
 };
 
+extern unsigned int ata_print_id;
 extern struct workqueue_struct *ata_aux_wq;
 extern int atapi_enabled;
 extern int atapi_dmadir;
@@ -92,10 +93,7 @@ extern int ata_flush_cache(struct ata_device *dev);
 extern void ata_dev_init(struct ata_device *dev);
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
-extern void ata_port_init(struct ata_port *ap, struct ata_host *host,
-                         const struct ata_probe_ent *ent, unsigned int port_no);
-extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
-                                                const struct ata_port_info *port);
+extern struct ata_port *ata_port_alloc(struct ata_host *host);
 
 /* libata-acpi.c */
 #ifdef CONFIG_SATA_ACPI
@@ -113,8 +111,8 @@ static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
 #endif
 
 /* libata-scsi.c */
-extern struct scsi_transport_template ata_scsi_transport_template;
-
+extern int ata_scsi_add_hosts(struct ata_host *host,
+                             struct scsi_host_template *sht);
 extern void ata_scsi_scan_host(struct ata_port *ap);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
 extern void ata_scsi_hotplug(struct work_struct *work);
index 11ea552a58cac00507f7853e1e53a598ec5afe41..d40edebb510a59ba41b6fbbd1600a8d9530a19a8 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/dmi.h>
 
 #define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.7.3"
+#define DRV_VERSION "0.7.4"
 
 /*
  *     Cable special cases
@@ -89,59 +89,6 @@ static int ali_c2_cable_detect(struct ata_port *ap)
                return ATA_CBL_PATA80;
 }
 
-/**
- *     ali_early_error_handler -       reset for eary chip
- *     @ap: ATA port
- *
- *     Handle the reset callback for the later chips with cable detect
- */
-
-static int ali_c2_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ali_c2_cable_detect(ap);
-       return ata_std_prereset(ap);
-}
-
-static void ali_c2_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, ali_c2_pre_reset,
-                              ata_std_softreset, NULL,
-                              ata_std_postreset);
-}
-
-/**
- *     ali_early_cable_detect  -       cable detection
- *     @ap: ATA port
- *
- *     Perform cable detection for older chipsets. This turns out to be
- *     rather easy to implement
- */
-
-static int ali_early_cable_detect(struct ata_port *ap)
-{
-       return ATA_CBL_PATA40;
-}
-
-/**
- *     ali_early_probe_init    -       reset for early chip
- *     @ap: ATA port
- *
- *     Handle the reset callback for the early (pre cable detect) chips.
- */
-
-static int ali_early_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ali_early_cable_detect(ap);
-       return ata_std_prereset(ap);
-}
-
-static void ali_early_error_handler(struct ata_port *ap)
-{
-       return ata_bmdma_drive_eh(ap, ali_early_pre_reset,
-                                    ata_std_softreset, NULL,
-                                    ata_std_postreset);
-}
-
 /**
  *     ali_20_filter           -       filter for earlier ALI DMA
  *     @ap: ALi ATA port
@@ -151,7 +98,7 @@ static void ali_early_error_handler(struct ata_port *ap)
  *     fix that later on. Also ensure we do not do UDMA on WDC drives
  */
 
-static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long ali_20_filter(struct ata_device *adev, unsigned long mask)
 {
        char model_num[ATA_ID_PROD_LEN + 1];
        /* No DMA on anything but a disk for now */
@@ -160,7 +107,7 @@ static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device
        ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
        if (strstr(model_num, "WDC"))
                return mask &= ~ATA_MASK_UDMA;
-       return ata_pci_default_filter(ap, adev, mask);
+       return ata_pci_default_filter(adev, mask);
 }
 
 /**
@@ -314,7 +261,6 @@ static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 
 /**
  *     ali_lock_sectors        -       Keep older devices to 255 sector mode
- *     @ap: ATA port
  *     @adev: Device
  *
  *     Called during the bus probe for each device that is found. We use
@@ -324,7 +270,7 @@ static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
  *     slower PIO methods
  */
 
-static void ali_lock_sectors(struct ata_port *ap, struct ata_device *adev)
+static void ali_lock_sectors(struct ata_device *adev)
 {
        adev->max_sectors = 255;
 }
@@ -366,8 +312,9 @@ static struct ata_port_operations ali_early_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = ali_early_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
@@ -402,8 +349,9 @@ static struct ata_port_operations ali_20_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = ali_early_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -440,8 +388,9 @@ static struct ata_port_operations ali_c2_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = ali_c2_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ali_c2_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -477,8 +426,9 @@ static struct ata_port_operations ali_c5_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = ali_c2_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ali_c2_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index 18381762908bf8b474918bc5c4f93c5fcca7026c..536ee892ab72da7aa2b789010c1bf60381de893d 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.2.8"
+#define DRV_VERSION "0.3.8"
 
 /**
  *     timing_setup            -       shared timing computation and load
@@ -119,32 +119,25 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
 }
 
 /**
- *     amd_probe_init          -       cable detection
+ *     amd_probe_init          -       perform reset handling
  *     @ap: ATA port
  *
- *     Perform cable detection. The BIOS stores this in PCI config
- *     space for us.
+ *     Reset sequence checking enable bits to see which ports are
+ *     active.
  */
 
 static int amd_pre_reset(struct ata_port *ap)
 {
-       static const u32 bitmask[2] = {0x03, 0x0C};
        static const struct pci_bits amd_enable_bits[] = {
                { 0x40, 1, 0x02, 0x02 },
                { 0x40, 1, 0x01, 0x01 }
        };
 
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u8 ata66;
 
        if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       pci_read_config_byte(pdev, 0x42, &ata66);
-       if (ata66 & bitmask[ap->port_no])
-               ap->cbl = ATA_CBL_PATA80;
-       else
-               ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 
 }
@@ -156,28 +149,16 @@ static void amd_error_handler(struct ata_port *ap)
                                      ata_std_postreset);
 }
 
-static int amd_early_pre_reset(struct ata_port *ap)
+static int amd_cable_detect(struct ata_port *ap)
 {
+       static const u32 bitmask[2] = {0x03, 0x0C};
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       static struct pci_bits amd_enable_bits[] = {
-               { 0x40, 1, 0x02, 0x02 },
-               { 0x40, 1, 0x01, 0x01 }
-       };
-
-       if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
-               return -ENOENT;
-
-       /* No host side cable detection */
-       ap->cbl = ATA_CBL_PATA80;
-       return ata_std_prereset(ap);
-
-}
+       u8 ata66;
 
-static void amd_early_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, amd_early_pre_reset,
-                              ata_std_softreset, NULL,
-                              ata_std_postreset);
+       pci_read_config_byte(pdev, 0x42, &ata66);
+       if (ata66 & bitmask[ap->port_no])
+               return ATA_CBL_PATA80;
+       return ATA_CBL_PATA40;
 }
 
 /**
@@ -247,31 +228,16 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
  */
 
 static int nv_pre_reset(struct ata_port *ap) {
-       static const u8 bitmask[2] = {0x03, 0x0C};
        static const struct pci_bits nv_enable_bits[] = {
                { 0x50, 1, 0x02, 0x02 },
                { 0x50, 1, 0x01, 0x01 }
        };
 
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u8 ata66;
-       u16 udma;
 
        if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       pci_read_config_byte(pdev, 0x52, &ata66);
-       if (ata66 & bitmask[ap->port_no])
-               ap->cbl = ATA_CBL_PATA80;
-       else
-               ap->cbl = ATA_CBL_PATA40;
-
-       /* We now have to double check because the Nvidia boxes BIOS
-          doesn't always set the cable bits but does set mode bits */
-
-       pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
-       if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
-               ap->cbl = ATA_CBL_PATA80;
        return ata_std_prereset(ap);
 }
 
@@ -281,6 +247,29 @@ static void nv_error_handler(struct ata_port *ap)
                               ata_std_softreset, NULL,
                               ata_std_postreset);
 }
+
+static int nv_cable_detect(struct ata_port *ap)
+{
+       static const u8 bitmask[2] = {0x03, 0x0C};
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       u8 ata66;
+       u16 udma;
+       int cbl;
+
+       pci_read_config_byte(pdev, 0x52, &ata66);
+       if (ata66 & bitmask[ap->port_no])
+               cbl = ATA_CBL_PATA80;
+       else
+               cbl = ATA_CBL_PATA40;
+
+       /* We now have to double check because the Nvidia boxes BIOS
+          doesn't always set the cable bits but does set mode bits */
+       pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
+       if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
+               cbl = ATA_CBL_PATA80;
+       return cbl;
+}
+
 /**
  *     nv100_set_piomode       -       set initial PIO mode data
  *     @ap: ATA interface
@@ -353,8 +342,9 @@ static struct ata_port_operations amd33_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = amd_early_error_handler,
+       .error_handler  = amd_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -387,8 +377,9 @@ static struct ata_port_operations amd66_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = amd_early_error_handler,
+       .error_handler  = amd_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_unknown,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -423,6 +414,7 @@ static struct ata_port_operations amd100_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = amd_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_unknown,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -457,6 +449,7 @@ static struct ata_port_operations amd133_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = amd_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = amd_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -491,6 +484,7 @@ static struct ata_port_operations nv100_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = nv_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = nv_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -525,6 +519,7 @@ static struct ata_port_operations nv133_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = nv_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = nv_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index 21c30282717ccafea9a541f9173552467bec932a..00e9ec342db001cda8e2ff32e9e29435f10fb92e 100644 (file)
@@ -49,8 +49,6 @@ static int artop6210_pre_reset(struct ata_port *ap)
 
        if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
                return -ENOENT;
-
-       ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 }
 
@@ -85,18 +83,28 @@ static int artop6260_pre_reset(struct ata_port *ap)
        };
 
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u8 tmp;
 
        /* Odd numbered device ids are the units with enable bits (the -R cards) */
        if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
                return -ENOENT;
+       return ata_std_prereset(ap);
+}
 
+/**
+ *     artop6260_cable_detect  -       identify cable type
+ *     @ap: Port
+ *
+ *     Identify the cable type for the ARTOp interface in question
+ */
+static int artop6260_cable_detect(struct ata_port *ap)
+{
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       u8 tmp;
        pci_read_config_byte(pdev, 0x49, &tmp);
        if (tmp & (1 << ap->port_no))
-               ap->cbl = ATA_CBL_PATA40;
-       else
-               ap->cbl = ATA_CBL_PATA80;
-       return ata_std_prereset(ap);
+               return ATA_CBL_PATA40;
+       return ATA_CBL_PATA80;
 }
 
 /**
@@ -225,7 +233,7 @@ static void artop6260_set_piomode(struct ata_port *ap, struct ata_device *adev)
 /**
  *     artop6210_set_dmamode - Initialize host controller PATA PIO timings
  *     @ap: Port whose timings we are configuring
- *     @adev: um
+ *     @adev: Device whose timings we are configuring
  *
  *     Set DMA mode for device, in host controller PCI config space.
  *
@@ -333,6 +341,7 @@ static const struct ata_port_operations artop6210_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = artop6210_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_40wire,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
@@ -366,6 +375,7 @@ static const struct ata_port_operations artop6260_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = artop6260_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = artop6260_cable_detect,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
index 51d9923be02efe9e03f75b107f7ba97581f4db60..39c871a3ddac9578fb8a3be5437eb2ecc69667b4 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_atiixp"
-#define DRV_VERSION "0.4.4"
+#define DRV_VERSION "0.4.5"
 
 enum {
        ATIIXP_IDE_PIO_TIMING   = 0x40,
@@ -35,23 +35,15 @@ enum {
 
 static int atiixp_pre_reset(struct ata_port *ap)
 {
-       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        static const struct pci_bits atiixp_enable_bits[] = {
                { 0x48, 1, 0x01, 0x00 },
                { 0x48, 1, 0x08, 0x00 }
        };
-       u8 udma;
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       /* Hack from drivers/ide/pci. Really we want to know how to do the
-          raw detection not play follow the bios mode guess */
-       pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
-       if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40)
-               ap->cbl = ATA_CBL_PATA80;
-       else
-               ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 }
 
@@ -60,6 +52,19 @@ static void atiixp_error_handler(struct ata_port *ap)
        ata_bmdma_drive_eh(ap, atiixp_pre_reset, ata_std_softreset, NULL,   ata_std_postreset);
 }
 
+static int atiixp_cable_detect(struct ata_port *ap)
+{
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       u8 udma;
+
+       /* Hack from drivers/ide/pci. Really we want to know how to do the
+          raw detection not play follow the bios mode guess */
+       pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
+       if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40)
+               return  ATA_CBL_PATA80;
+       return ATA_CBL_PATA40;
+}
+
 /**
  *     atiixp_set_pio_timing   -       set initial PIO mode data
  *     @ap: ATA interface
@@ -245,6 +250,7 @@ static struct ata_port_operations atiixp_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = atiixp_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = atiixp_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = atiixp_bmdma_start,
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
new file mode 100644 (file)
index 0000000..2105985
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * pata_cmd640.c       - CMD640 PCI PATA for new ATA layer
+ *                       (C) 2007 Red Hat Inc
+ *                       Alan Cox <alan@redhat.com>
+ *
+ * Based upon
+ *  linux/drivers/ide/pci/cmd640.c             Version 1.02  Sep 01, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & authors (see driver)
+ *
+ *     This drives only the PCI version of the controller. If you have a
+ *     VLB one then we have enough docs to support it but you can write
+ *     your own code.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_cmd640"
+#define DRV_VERSION "0.0.5"
+
+struct cmd640_reg {
+       int last;
+       u8 reg58[ATA_MAX_DEVICES];
+};
+
+enum {
+       CFR = 0x50,
+       CNTRL = 0x51,
+       CMDTIM = 0x52,
+       ARTIM0 = 0x53,
+       DRWTIM0 = 0x54,
+       ARTIM23 = 0x57,
+       DRWTIM23 = 0x58,
+       BRST = 0x59
+};
+
+/**
+ *     cmd640_set_piomode      -       set initial PIO mode data
+ *     @ap: ATA port
+ *     @adev: ATA device
+ *
+ *     Called to do the PIO mode setup.
+ */
+
+static void cmd640_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       struct cmd640_reg *timing = ap->private_data;
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       struct ata_timing t;
+       const unsigned long T = 1000000 / 33;
+       const u8 setup_data[] = { 0x40, 0x40, 0x40, 0x80, 0x00 };
+       u8 reg;
+       int arttim = ARTIM0 + 2 * adev->devno;
+       struct ata_device *pair = ata_dev_pair(adev);
+
+       if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+               printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
+               return;
+       }
+
+       /* The second channel has shared timings and the setup timing is
+          messy to switch to merge it for worst case */
+       if (ap->port_no && pair) {
+               struct ata_timing p;
+               ata_timing_compute(pair, pair->pio_mode, &p, T, 1);
+               ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP);
+       }
+
+       /* Make the timings fit */
+       if (t.recover > 16) {
+               t.active += t.recover - 16;
+               t.recover = 16;
+       }
+       if (t.active > 16)
+               t.active = 16;
+
+       /* Now convert the clocks into values we can actually stuff into
+          the chip */
+
+       if (t.recover > 1)
+               t.recover--;    /* 640B only */
+       else
+               t.recover = 15;
+
+       if (t.setup > 4)
+               t.setup = 0xC0;
+       else
+               t.setup = setup_data[t.setup];
+
+       if (ap->port_no == 0) {
+               t.active &= 0x0F;       /* 0 = 16 */
+
+               /* Load setup timing */
+               pci_read_config_byte(pdev, arttim, &reg);
+               reg &= 0x3F;
+               reg |= t.setup;
+               pci_write_config_byte(pdev, arttim, reg);
+
+               /* Load active/recovery */
+               pci_write_config_byte(pdev, arttim + 1, (t.active << 4) | t.recover);
+       } else {
+               /* Save the shared timings for channel, they will be loaded
+                  by qc_issue_prot. Reloading the setup time is expensive 
+                  so we keep a merged one loaded */
+               pci_read_config_byte(pdev, ARTIM23, &reg);
+               reg &= 0x3F;
+               reg |= t.setup;
+               pci_write_config_byte(pdev, ARTIM23, reg);
+               timing->reg58[adev->devno] = (t.active << 4) | t.recover;
+       }
+}
+
+
+/**
+ *     cmd640_qc_issue_prot    -       command preparation hook
+ *     @qc: Command to be issued
+ *
+ *     Channel 1 has shared timings. We must reprogram the
+ *     clock each drive 2/3 switch we do.
+ */
+
+static unsigned int cmd640_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct ata_device *adev = qc->dev;
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       struct cmd640_reg *timing = ap->private_data;
+
+       if (ap->port_no != 0 && adev->devno != timing->last) {
+               pci_write_config_byte(pdev, DRWTIM23, timing->reg58[adev->devno]);
+               timing->last = adev->devno;
+       }
+       return ata_qc_issue_prot(qc);
+}
+
+/**
+ *     cmd640_port_start       -       port setup
+ *     @ap: ATA port being set up
+ *
+ *     The CMD640 needs to maintain private data structures so we
+ *     allocate space here.
+ */
+
+static int cmd640_port_start(struct ata_port *ap)
+{
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       struct cmd640_reg *timing;
+
+       int ret = ata_port_start(ap);
+       if (ret < 0)
+               return ret;
+
+       timing = devm_kzalloc(&pdev->dev, sizeof(struct cmd640_reg), GFP_KERNEL);
+       if (timing == NULL)
+               return -ENOMEM;
+       timing->last = -1;      /* Force a load */
+       ap->private_data = timing;
+       return ret;
+}
+
+static struct scsi_host_template cmd640_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = DRV_NAME,
+       .ioctl                  = ata_scsi_ioctl,
+       .queuecommand           = ata_scsi_queuecmd,
+       .can_queue              = ATA_DEF_QUEUE,
+       .this_id                = ATA_SHT_THIS_ID,
+       .sg_tablesize           = LIBATA_MAX_PRD,
+       .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
+       .emulated               = ATA_SHT_EMULATED,
+       .use_clustering         = ATA_SHT_USE_CLUSTERING,
+       .proc_name              = DRV_NAME,
+       .dma_boundary           = ATA_DMA_BOUNDARY,
+       .slave_configure        = ata_scsi_slave_config,
+       .slave_destroy          = ata_scsi_slave_destroy,
+       .bios_param             = ata_std_bios_param,
+#ifdef CONFIG_PM
+       .resume                 = ata_scsi_device_resume,
+       .suspend                = ata_scsi_device_suspend,
+#endif
+};
+
+static struct ata_port_operations cmd640_port_ops = {
+       .port_disable   = ata_port_disable,
+       .set_piomode    = cmd640_set_piomode,
+       .mode_filter    = ata_pci_default_filter,
+       .tf_load        = ata_tf_load,
+       .tf_read        = ata_tf_read,
+       .check_status   = ata_check_status,
+       .exec_command   = ata_exec_command,
+       .dev_select     = ata_std_dev_select,
+
+       .freeze         = ata_bmdma_freeze,
+       .thaw           = ata_bmdma_thaw,
+       .error_handler  = ata_bmdma_error_handler,
+       .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
+
+       .bmdma_setup    = ata_bmdma_setup,
+       .bmdma_start    = ata_bmdma_start,
+       .bmdma_stop     = ata_bmdma_stop,
+       .bmdma_status   = ata_bmdma_status,
+
+       .qc_prep        = ata_qc_prep,
+       .qc_issue       = cmd640_qc_issue_prot,
+
+       /* In theory this is not needed once we kill the prefetcher */
+       .data_xfer      = ata_data_xfer_noirq,
+
+       .irq_handler    = ata_interrupt,
+       .irq_clear      = ata_bmdma_irq_clear,
+       .irq_on         = ata_irq_on,
+       .irq_ack        = ata_irq_ack,
+
+       .port_start     = cmd640_port_start,
+};
+
+static void cmd640_hardware_init(struct pci_dev *pdev)
+{
+       u8 r;
+       u8 ctrl;
+
+       /* CMD640 detected, commiserations */
+       pci_write_config_byte(pdev, 0x5B, 0x00);
+       /* Get version info */
+       pci_read_config_byte(pdev, CFR, &r);
+       /* PIO0 command cycles */
+       pci_write_config_byte(pdev, CMDTIM, 0);
+       /* 512 byte bursts (sector) */
+       pci_write_config_byte(pdev, BRST, 0x40);
+       /* 
+        * A reporter a long time ago
+        * Had problems with the data fifo
+        * So don't run the risk
+        * Of putting crap on the disk
+        * For its better just to go slow
+        */
+       /* Do channel 0 */
+       pci_read_config_byte(pdev, CNTRL, &ctrl);
+       pci_write_config_byte(pdev, CNTRL, ctrl | 0xC0);
+       /* Ditto for channel 1 */
+       pci_read_config_byte(pdev, ARTIM23, &ctrl);
+       ctrl |= 0x0C;
+       pci_write_config_byte(pdev, ARTIM23, ctrl);
+}
+
+static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       static struct ata_port_info info = {
+               .sht = &cmd640_sht,
+               .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+               .pio_mask = 0x1f,
+               .port_ops = &cmd640_port_ops
+       };
+
+       static struct ata_port_info *port_info[2] = { &info, &info };
+
+       cmd640_hardware_init(pdev);
+       return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static int cmd640_reinit_one(struct pci_dev *pdev)
+{
+       cmd640_hardware_init(pdev);
+#ifdef CONFIG_PM
+       return ata_pci_device_resume(pdev);
+#else
+       return 0;
+#endif
+}
+
+static const struct pci_device_id cmd640[] = {
+       { PCI_VDEVICE(CMD, 0x640), 0 },
+       { },
+};
+
+static struct pci_driver cmd640_pci_driver = {
+       .name           = DRV_NAME,
+       .id_table       = cmd640,
+       .probe          = cmd640_init_one,
+       .remove         = ata_pci_remove_one,
+#ifdef CONFIG_PM
+       .suspend        = ata_pci_device_suspend,
+#endif
+       .resume         = cmd640_reinit_one,
+};
+
+static int __init cmd640_init(void)
+{
+       return pci_register_driver(&cmd640_pci_driver);
+}
+
+static void __exit cmd640_exit(void)
+{
+       pci_unregister_driver(&cmd640_pci_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for CMD640 PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cmd640);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cmd640_init);
+module_exit(cmd640_exit);
index 5b13bdd1edc0863049143034b7b23b8d1ef60b3a..3989cc577fcd503b6e073a001f89eb72d935b6f0 100644 (file)
@@ -75,13 +75,7 @@ enum {
        DTPR1           = 0x7C
 };
 
-static int cmd64x_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA40;
-       return ata_std_prereset(ap);
-}
-
-static int cmd648_pre_reset(struct ata_port *ap)
+static int cmd648_cable_detect(struct ata_port *ap)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u8 r;
@@ -89,21 +83,8 @@ static int cmd648_pre_reset(struct ata_port *ap)
        /* Check cable detect bits */
        pci_read_config_byte(pdev, BMIDECSR, &r);
        if (r & (1 << ap->port_no))
-               ap->cbl = ATA_CBL_PATA80;
-       else
-               ap->cbl = ATA_CBL_PATA40;
-
-       return ata_std_prereset(ap);
-}
-
-static void cmd64x_error_handler(struct ata_port *ap)
-{
-       return ata_bmdma_drive_eh(ap, cmd64x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-static void cmd648_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, cmd648_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+               return ATA_CBL_PATA80;
+       return ATA_CBL_PATA40;
 }
 
 /**
@@ -304,8 +285,9 @@ static struct ata_port_operations cmd64x_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = cmd64x_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -338,8 +320,9 @@ static struct ata_port_operations cmd646r1_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = cmd64x_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -372,8 +355,9 @@ static struct ata_port_operations cmd648_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = cmd648_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = cmd648_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index 55cc293e74873d176aa78606f16253c0d5b82422..79bef0d1fad337106eb77d419bf192090834fc80 100644 (file)
@@ -139,18 +139,6 @@ static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
        cs5520_set_timings(ap, adev, adev->pio_mode);
 }
 
-
-static int cs5520_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA40;
-       return ata_std_prereset(ap);
-}
-
-static void cs5520_error_handler(struct ata_port *ap)
-{
-       return ata_bmdma_drive_eh(ap, cs5520_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
 static struct scsi_host_template cs5520_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -186,8 +174,9 @@ static struct ata_port_operations cs5520_port_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = cs5520_error_handler,
+       .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_40wire,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
@@ -197,7 +186,6 @@ static struct ata_port_operations cs5520_port_ops = {
        .qc_issue               = ata_qc_issue_prot,
        .data_xfer              = ata_data_xfer,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -205,91 +193,104 @@ static struct ata_port_operations cs5520_port_ops = {
        .port_start             = ata_port_start,
 };
 
-static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
+       struct ata_port_info pi = {
+               .flags          = ATA_FLAG_SLAVE_POSS,
+               .pio_mask       = 0x1f,
+               .port_ops       = &cs5520_port_ops,
+       };
+       const struct ata_port_info *ppi[2];
        u8 pcicfg;
-       void __iomem *iomap[5];
-       static struct ata_probe_ent probe[2];
-       int ports = 0;
+       void *iomap[5];
+       struct ata_host *host;
+       struct ata_ioports *ioaddr;
+       int i, rc;
 
        /* IDE port enable bits */
-       pci_read_config_byte(dev, 0x60, &pcicfg);
+       pci_read_config_byte(pdev, 0x60, &pcicfg);
 
        /* Check if the ATA ports are enabled */
        if ((pcicfg & 3) == 0)
                return -ENODEV;
 
+       ppi[0] = ppi[1] = &ata_dummy_port_info;
+       if (pcicfg & 1)
+               ppi[0] = &pi;
+       if (pcicfg & 2)
+               ppi[1] = &pi;
+
        if ((pcicfg & 0x40) == 0) {
-               printk(KERN_WARNING DRV_NAME ": DMA mode disabled. Enabling.\n");
-               pci_write_config_byte(dev, 0x60, pcicfg | 0x40);
+               dev_printk(KERN_WARNING, &pdev->dev,
+                          "DMA mode disabled. Enabling.\n");
+               pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
        }
 
+       pi.mwdma_mask = id->driver_data;
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+       if (!host)
+               return -ENOMEM;
+
        /* Perform set up for DMA */
-       if (pci_enable_device_bars(dev, 1<<2)) {
+       if (pci_enable_device_bars(pdev, 1<<2)) {
                printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n");
                return -ENODEV;
        }
-       pci_set_master(dev);
-       if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+
+       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
                printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.\n");
                return -ENODEV;
        }
-       if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) {
+       if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
                printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n");
                return -ENODEV;
        }
 
-       /* Map IO ports */
-       iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8);
-       iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1);
-       iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8);
-       iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1);
-       iomap[4] = pcim_iomap(dev, 2, 0);
+       /* Map IO ports and initialize host accordingly */
+       iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8);
+       iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1);
+       iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8);
+       iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1);
+       iomap[4] = pcim_iomap(pdev, 2, 0);
 
        if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
                return -ENOMEM;
 
-       /* We have to do our own plumbing as the PCI setup for this
-          chipset is non-standard so we can't punt to the libata code */
-
-       INIT_LIST_HEAD(&probe[0].node);
-       probe[0].dev = pci_dev_to_dev(dev);
-       probe[0].port_ops = &cs5520_port_ops;
-       probe[0].sht = &cs5520_sht;
-       probe[0].pio_mask = 0x1F;
-       probe[0].mwdma_mask = id->driver_data;
-       probe[0].irq = 14;
-       probe[0].irq_flags = 0;
-       probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
-       probe[0].n_ports = 1;
-       probe[0].port[0].cmd_addr = iomap[0];
-       probe[0].port[0].ctl_addr = iomap[1];
-       probe[0].port[0].altstatus_addr = iomap[1];
-       probe[0].port[0].bmdma_addr = iomap[4];
-
-       /* The secondary lurks at different addresses but is otherwise
-          the same beastie */
-
-       probe[1] = probe[0];
-       INIT_LIST_HEAD(&probe[1].node);
-       probe[1].irq = 15;
-       probe[1].port[0].cmd_addr = iomap[2];
-       probe[1].port[0].ctl_addr = iomap[3];
-       probe[1].port[0].altstatus_addr = iomap[3];
-       probe[1].port[0].bmdma_addr = iomap[4] + 8;
-
-       /* Let libata fill in the port details */
-       ata_std_ports(&probe[0].port[0]);
-       ata_std_ports(&probe[1].port[0]);
-
-       /* Now add the ports that are active */
-       if (pcicfg & 1)
-               ports += ata_device_add(&probe[0]);
-       if (pcicfg & 2)
-               ports += ata_device_add(&probe[1]);
-       if (ports)
-               return 0;
-       return -ENODEV;
+       ioaddr = &host->ports[0]->ioaddr;
+       ioaddr->cmd_addr = iomap[0];
+       ioaddr->ctl_addr = iomap[1];
+       ioaddr->altstatus_addr = iomap[1];
+       ioaddr->bmdma_addr = iomap[4];
+       ata_std_ports(ioaddr);
+
+       ioaddr = &host->ports[1]->ioaddr;
+       ioaddr->cmd_addr = iomap[2];
+       ioaddr->ctl_addr = iomap[3];
+       ioaddr->altstatus_addr = iomap[3];
+       ioaddr->bmdma_addr = iomap[4] + 8;
+       ata_std_ports(ioaddr);
+
+       /* activate the host */
+       pci_set_master(pdev);
+       rc = ata_host_start(host);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < 2; i++) {
+               static const int irq[] = { 14, 15 };
+               struct ata_port *ap = host->ports[0];
+
+               if (ata_port_is_dummy(ap))
+                       continue;
+
+               rc = devm_request_irq(&pdev->dev, irq[ap->port_no],
+                                     ata_interrupt, 0, DRV_NAME, host);
+               if (rc)
+                       return rc;
+       }
+
+       return ata_host_register(host, &cs5520_sht);
 }
 
 /**
index db63e80e608b3b65baefaba969c2706baf92d802..29642d5ee1891ee3d3aef8e40d51008f986b2fbc 100644 (file)
@@ -160,18 +160,6 @@ static unsigned int cs5530_qc_issue_prot(struct ata_queued_cmd *qc)
        return ata_qc_issue_prot(qc);
 }
 
-static int cs5530_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA40;
-       return ata_std_prereset(ap);
-}
-
-static void cs5530_error_handler(struct ata_port *ap)
-{
-       return ata_bmdma_drive_eh(ap, cs5530_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-
 static struct scsi_host_template cs5530_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -213,8 +201,9 @@ static struct ata_port_operations cs5530_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = cs5530_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = cs5530_qc_issue_prot,
index 1572e5c9031af86c58c5d8a009854144e5fecc59..08cccc9c659b9cebbbe7ff13fe2c1a1cdd292d2c 100644 (file)
 #define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL)==0x00009172 )
 
 /**
- *     cs5535_pre_reset        -       detect cable type
+ *     cs5535_cable_detect     -       detect cable type
  *     @ap: Port to detect on
  *
  *     Perform cable detection for ATA66 capable cable. Return a libata
  *     cable type.
  */
 
-static int cs5535_pre_reset(struct ata_port *ap)
+static int cs5535_cable_detect(struct ata_port *ap)
 {
        u8 cable;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        pci_read_config_byte(pdev, CS5535_CABLE_DETECT, &cable);
        if (cable & 1)
-               ap->cbl = ATA_CBL_PATA80;
+               return ATA_CBL_PATA80;
        else
-               ap->cbl = ATA_CBL_PATA40;
-       return ata_std_prereset(ap);
-}
-
-/**
- *     cs5535_error_handler            -       reset/probe
- *     @ap: Port to reset
- *
- *     Reset and configure a port
- */
-
-static void cs5535_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, cs5535_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+               return ATA_CBL_PATA40;
 }
 
 /**
@@ -205,8 +192,9 @@ static struct ata_port_operations cs5535_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = cs5535_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = cs5535_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index f69dde5f70665a37e2a019a23f7563177f1cbabf..6ec049c3b1dcf4e0fbe03b374a0d17f69672a405 100644 (file)
@@ -41,17 +41,6 @@ enum {
        CY82_INDEX_TIMEOUT      = 0x32
 };
 
-static int cy82c693_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA40;
-       return ata_std_prereset(ap);
-}
-
-static void cy82c693_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, cy82c693_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
 /**
  *     cy82c693_set_piomode    -       set initial PIO mode data
  *     @ap: ATA interface
@@ -156,8 +145,9 @@ static struct ata_port_operations cy82c693_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = cy82c693_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index dac7a6554f6c28c0febe60cb9320c61130b33bd0..a3216850bba15e10938da4f2335f50e863b516e5 100644 (file)
 #include <linux/ata.h>
 
 #define DRV_NAME       "pata_efar"
-#define DRV_VERSION    "0.4.3"
+#define DRV_VERSION    "0.4.4"
 
 /**
- *     efar_pre_reset  -       check for 40/80 pin
+ *     efar_pre_reset  -       Enable bits
  *     @ap: Port
  *
  *     Perform cable detection for the EFAR ATA interface. This is
@@ -38,18 +38,11 @@ static int efar_pre_reset(struct ata_port *ap)
                { 0x41U, 1U, 0x80UL, 0x80UL },  /* port 0 */
                { 0x43U, 1U, 0x80UL, 0x80UL },  /* port 1 */
        };
-
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u8 tmp;
 
        if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       pci_read_config_byte(pdev, 0x47, &tmp);
-       if (tmp & (2 >> ap->port_no))
-               ap->cbl = ATA_CBL_PATA40;
-       else
-               ap->cbl = ATA_CBL_PATA80;
        return ata_std_prereset(ap);
 }
 
@@ -66,6 +59,25 @@ static void efar_error_handler(struct ata_port *ap)
        ata_bmdma_drive_eh(ap, efar_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
 }
 
+/**
+ *     efar_cable_detect       -       check for 40/80 pin
+ *     @ap: Port
+ *
+ *     Perform cable detection for the EFAR ATA interface. This is
+ *     different to the PIIX arrangement
+ */
+
+static int efar_cable_detect(struct ata_port *ap)
+{
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       u8 tmp;
+
+       pci_read_config_byte(pdev, 0x47, &tmp);
+       if (tmp & (2 >> ap->port_no))
+               return ATA_CBL_PATA40;
+       return ATA_CBL_PATA80;
+}
+
 /**
  *     efar_set_piomode - Initialize host controller PATA PIO timings
  *     @ap: Port whose timings we are configuring
@@ -256,6 +268,7 @@ static const struct ata_port_operations efar_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = efar_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = efar_cable_detect,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
index baf35f87603061220fb7da4930fa0de0e7e967e3..93cfa6d300a5a08196d789817a4c93938b7b1da6 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt366"
-#define DRV_VERSION    "0.6.0"
+#define DRV_VERSION    "0.6.1"
 
 struct hpt_clock {
        u8      xfer_speed;
@@ -169,13 +169,12 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, cons
 
 /**
  *     hpt366_filter   -       mode selection filter
- *     @ap: ATA interface
  *     @adev: ATA device
  *
  *     Block UDMA on devices that cause trouble with this controller.
  */
 
-static unsigned long hpt366_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask)
 {
        if (adev->class == ATA_DEV_ATA) {
                if (hpt_dma_blacklisted(adev, "UDMA",  bad_ata33))
@@ -185,7 +184,7 @@ static unsigned long hpt366_filter(const struct ata_port *ap, struct ata_device
                if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4))
                        mask &= ~(0x0F << ATA_SHIFT_UDMA);
        }
-       return ata_pci_default_filter(ap, adev, mask);
+       return ata_pci_default_filter(adev, mask);
 }
 
 /**
@@ -210,24 +209,28 @@ static u32 hpt36x_find_mode(struct ata_port *ap, int speed)
        return 0xffffffffU;     /* silence compiler warning */
 }
 
+static int hpt36x_cable_detect(struct ata_port *ap)
+{
+       u8 ata66;
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+       pci_read_config_byte(pdev, 0x5A, &ata66);
+       if (ata66 & (1 << ap->port_no))
+               return ATA_CBL_PATA40;
+       return ATA_CBL_PATA80;
+}
+
 static int hpt36x_pre_reset(struct ata_port *ap)
 {
        static const struct pci_bits hpt36x_enable_bits[] = {
                { 0x50, 1, 0x04, 0x04 },
                { 0x54, 1, 0x04, 0x04 }
        };
-
-       u8 ata66;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       pci_read_config_byte(pdev, 0x5A, &ata66);
-       if (ata66 & (1 << ap->port_no))
-               ap->cbl = ATA_CBL_PATA40;
-       else
-               ap->cbl = ATA_CBL_PATA80;
        return ata_std_prereset(ap);
 }
 
@@ -354,6 +357,7 @@ static struct ata_port_operations hpt366_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = hpt36x_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = hpt36x_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index f331eeeafa0f39d75302023953c676910d446e64..41d8312963474447feb7faf6284a80efaa00cc53 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright (C) 1999-2003             Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001         Sun Microsystems, Inc.
  * Portions Copyright (C) 2003         Red Hat Inc
+ * Portions Copyright (C) 2005-2006    MontaVista Software, Inc.
  *
  * TODO
  *     PLL mode
@@ -25,7 +26,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt37x"
-#define DRV_VERSION    "0.6.0"
+#define DRV_VERSION    "0.6.5"
 
 struct hpt_clock {
        u8      xfer_speed;
@@ -61,201 +62,75 @@ struct hpt_chip {
  * 31     FIFO enable.
  */
 
-/* from highpoint documentation. these are old values */
-static const struct hpt_clock hpt370_timings_33[] = {
-/*     {       XFER_UDMA_5,    0x1A85F442,     0x16454e31      }, */
-       {       XFER_UDMA_5,    0x16454e31      },
-       {       XFER_UDMA_4,    0x16454e31      },
-       {       XFER_UDMA_3,    0x166d4e31      },
-       {       XFER_UDMA_2,    0x16494e31      },
-       {       XFER_UDMA_1,    0x164d4e31      },
-       {       XFER_UDMA_0,    0x16514e31      },
-
-       {       XFER_MW_DMA_2,  0x26514e21      },
-       {       XFER_MW_DMA_1,  0x26514e33      },
-       {       XFER_MW_DMA_0,  0x26514e97      },
-
-       {       XFER_PIO_4,     0x06514e21      },
-       {       XFER_PIO_3,     0x06514e22      },
-       {       XFER_PIO_2,     0x06514e33      },
-       {       XFER_PIO_1,     0x06914e43      },
-       {       XFER_PIO_0,     0x06914e57      },
-       {       0,              0x06514e57      }
+static struct hpt_clock hpt37x_timings_33[] = {
+       { XFER_UDMA_6,          0x12446231 },   /* 0x12646231 ?? */
+       { XFER_UDMA_5,          0x12446231 },
+       { XFER_UDMA_4,          0x12446231 },
+       { XFER_UDMA_3,          0x126c6231 },
+       { XFER_UDMA_2,          0x12486231 },
+       { XFER_UDMA_1,          0x124c6233 },
+       { XFER_UDMA_0,          0x12506297 },
+
+       { XFER_MW_DMA_2,        0x22406c31 },
+       { XFER_MW_DMA_1,        0x22406c33 },
+       { XFER_MW_DMA_0,        0x22406c97 },
+
+       { XFER_PIO_4,           0x06414e31 },
+       { XFER_PIO_3,           0x06414e42 },
+       { XFER_PIO_2,           0x06414e53 },
+       { XFER_PIO_1,           0x06814e93 },
+       { XFER_PIO_0,           0x06814ea7 }
 };
 
-static const struct hpt_clock hpt370_timings_66[] = {
-       {       XFER_UDMA_5,    0x14846231      },
-       {       XFER_UDMA_4,    0x14886231      },
-       {       XFER_UDMA_3,    0x148c6231      },
-       {       XFER_UDMA_2,    0x148c6231      },
-       {       XFER_UDMA_1,    0x14906231      },
-       {       XFER_UDMA_0,    0x14986231      },
-
-       {       XFER_MW_DMA_2,  0x26514e21      },
-       {       XFER_MW_DMA_1,  0x26514e33      },
-       {       XFER_MW_DMA_0,  0x26514e97      },
-
-       {       XFER_PIO_4,     0x06514e21      },
-       {       XFER_PIO_3,     0x06514e22      },
-       {       XFER_PIO_2,     0x06514e33      },
-       {       XFER_PIO_1,     0x06914e43      },
-       {       XFER_PIO_0,     0x06914e57      },
-       {       0,              0x06514e57      }
+static struct hpt_clock hpt37x_timings_50[] = {
+       { XFER_UDMA_6,          0x12848242 },
+       { XFER_UDMA_5,          0x12848242 },
+       { XFER_UDMA_4,          0x12ac8242 },
+       { XFER_UDMA_3,          0x128c8242 },
+       { XFER_UDMA_2,          0x120c8242 },
+       { XFER_UDMA_1,          0x12148254 },
+       { XFER_UDMA_0,          0x121882ea },
+
+       { XFER_MW_DMA_2,        0x22808242 },
+       { XFER_MW_DMA_1,        0x22808254 },
+       { XFER_MW_DMA_0,        0x228082ea },
+
+       { XFER_PIO_4,           0x0a81f442 },
+       { XFER_PIO_3,           0x0a81f443 },
+       { XFER_PIO_2,           0x0a81f454 },
+       { XFER_PIO_1,           0x0ac1f465 },
+       { XFER_PIO_0,           0x0ac1f48a }
 };
 
-/* these are the current (4 sep 2001) timings from highpoint */
-static const struct hpt_clock hpt370a_timings_33[] = {
-       {       XFER_UDMA_5,    0x12446231      },
-       {       XFER_UDMA_4,    0x12446231      },
-       {       XFER_UDMA_3,    0x126c6231      },
-       {       XFER_UDMA_2,    0x12486231      },
-       {       XFER_UDMA_1,    0x124c6233      },
-       {       XFER_UDMA_0,    0x12506297      },
-
-       {       XFER_MW_DMA_2,  0x22406c31      },
-       {       XFER_MW_DMA_1,  0x22406c33      },
-       {       XFER_MW_DMA_0,  0x22406c97      },
-
-       {       XFER_PIO_4,     0x06414e31      },
-       {       XFER_PIO_3,     0x06414e42      },
-       {       XFER_PIO_2,     0x06414e53      },
-       {       XFER_PIO_1,     0x06814e93      },
-       {       XFER_PIO_0,     0x06814ea7      },
-       {       0,              0x06814ea7      }
+static struct hpt_clock hpt37x_timings_66[] = {
+       { XFER_UDMA_6,          0x1c869c62 },
+       { XFER_UDMA_5,          0x1cae9c62 },   /* 0x1c8a9c62 */
+       { XFER_UDMA_4,          0x1c8a9c62 },
+       { XFER_UDMA_3,          0x1c8e9c62 },
+       { XFER_UDMA_2,          0x1c929c62 },
+       { XFER_UDMA_1,          0x1c9a9c62 },
+       { XFER_UDMA_0,          0x1c829c62 },
+
+       { XFER_MW_DMA_2,        0x2c829c62 },
+       { XFER_MW_DMA_1,        0x2c829c66 },
+       { XFER_MW_DMA_0,        0x2c829d2e },
+
+       { XFER_PIO_4,           0x0c829c62 },
+       { XFER_PIO_3,           0x0c829c84 },
+       { XFER_PIO_2,           0x0c829ca6 },
+       { XFER_PIO_1,           0x0d029d26 },
+       { XFER_PIO_0,           0x0d029d5e }
 };
 
-/* 2x 33MHz timings */
-static const struct hpt_clock hpt370a_timings_66[] = {
-       {       XFER_UDMA_5,    0x1488e673      },
-       {       XFER_UDMA_4,    0x1488e673      },
-       {       XFER_UDMA_3,    0x1498e673      },
-       {       XFER_UDMA_2,    0x1490e673      },
-       {       XFER_UDMA_1,    0x1498e677      },
-       {       XFER_UDMA_0,    0x14a0e73f      },
-
-       {       XFER_MW_DMA_2,  0x2480fa73      },
-       {       XFER_MW_DMA_1,  0x2480fa77      },
-       {       XFER_MW_DMA_0,  0x2480fb3f      },
-
-       {       XFER_PIO_4,     0x0c82be73      },
-       {       XFER_PIO_3,     0x0c82be95      },
-       {       XFER_PIO_2,     0x0c82beb7      },
-       {       XFER_PIO_1,     0x0d02bf37      },
-       {       XFER_PIO_0,     0x0d02bf5f      },
-       {       0,              0x0d02bf5f      }
-};
-
-static const struct hpt_clock hpt370a_timings_50[] = {
-       {       XFER_UDMA_5,    0x12848242      },
-       {       XFER_UDMA_4,    0x12ac8242      },
-       {       XFER_UDMA_3,    0x128c8242      },
-       {       XFER_UDMA_2,    0x120c8242      },
-       {       XFER_UDMA_1,    0x12148254      },
-       {       XFER_UDMA_0,    0x121882ea      },
-
-       {       XFER_MW_DMA_2,  0x22808242      },
-       {       XFER_MW_DMA_1,  0x22808254      },
-       {       XFER_MW_DMA_0,  0x228082ea      },
-
-       {       XFER_PIO_4,     0x0a81f442      },
-       {       XFER_PIO_3,     0x0a81f443      },
-       {       XFER_PIO_2,     0x0a81f454      },
-       {       XFER_PIO_1,     0x0ac1f465      },
-       {       XFER_PIO_0,     0x0ac1f48a      },
-       {       0,              0x0ac1f48a      }
-};
-
-static const struct hpt_clock hpt372_timings_33[] = {
-       {       XFER_UDMA_6,    0x1c81dc62      },
-       {       XFER_UDMA_5,    0x1c6ddc62      },
-       {       XFER_UDMA_4,    0x1c8ddc62      },
-       {       XFER_UDMA_3,    0x1c8edc62      },      /* checkme */
-       {       XFER_UDMA_2,    0x1c91dc62      },
-       {       XFER_UDMA_1,    0x1c9adc62      },      /* checkme */
-       {       XFER_UDMA_0,    0x1c82dc62      },      /* checkme */
-
-       {       XFER_MW_DMA_2,  0x2c829262      },
-       {       XFER_MW_DMA_1,  0x2c829266      },      /* checkme */
-       {       XFER_MW_DMA_0,  0x2c82922e      },      /* checkme */
-
-       {       XFER_PIO_4,     0x0c829c62      },
-       {       XFER_PIO_3,     0x0c829c84      },
-       {       XFER_PIO_2,     0x0c829ca6      },
-       {       XFER_PIO_1,     0x0d029d26      },
-       {       XFER_PIO_0,     0x0d029d5e      },
-       {       0,              0x0d029d5e      }
-};
-
-static const struct hpt_clock hpt372_timings_50[] = {
-       {       XFER_UDMA_5,    0x12848242      },
-       {       XFER_UDMA_4,    0x12ac8242      },
-       {       XFER_UDMA_3,    0x128c8242      },
-       {       XFER_UDMA_2,    0x120c8242      },
-       {       XFER_UDMA_1,    0x12148254      },
-       {       XFER_UDMA_0,    0x121882ea      },
-
-       {       XFER_MW_DMA_2,  0x22808242      },
-       {       XFER_MW_DMA_1,  0x22808254      },
-       {       XFER_MW_DMA_0,  0x228082ea      },
-
-       {       XFER_PIO_4,     0x0a81f442      },
-       {       XFER_PIO_3,     0x0a81f443      },
-       {       XFER_PIO_2,     0x0a81f454      },
-       {       XFER_PIO_1,     0x0ac1f465      },
-       {       XFER_PIO_0,     0x0ac1f48a      },
-       {       0,              0x0a81f443      }
-};
-
-static const struct hpt_clock hpt372_timings_66[] = {
-       {       XFER_UDMA_6,    0x1c869c62      },
-       {       XFER_UDMA_5,    0x1cae9c62      },
-       {       XFER_UDMA_4,    0x1c8a9c62      },
-       {       XFER_UDMA_3,    0x1c8e9c62      },
-       {       XFER_UDMA_2,    0x1c929c62      },
-       {       XFER_UDMA_1,    0x1c9a9c62      },
-       {       XFER_UDMA_0,    0x1c829c62      },
-
-       {       XFER_MW_DMA_2,  0x2c829c62      },
-       {       XFER_MW_DMA_1,  0x2c829c66      },
-       {       XFER_MW_DMA_0,  0x2c829d2e      },
-
-       {       XFER_PIO_4,     0x0c829c62      },
-       {       XFER_PIO_3,     0x0c829c84      },
-       {       XFER_PIO_2,     0x0c829ca6      },
-       {       XFER_PIO_1,     0x0d029d26      },
-       {       XFER_PIO_0,     0x0d029d5e      },
-       {       0,              0x0d029d26      }
-};
-
-static const struct hpt_clock hpt374_timings_33[] = {
-       {       XFER_UDMA_6,    0x12808242      },
-       {       XFER_UDMA_5,    0x12848242      },
-       {       XFER_UDMA_4,    0x12ac8242      },
-       {       XFER_UDMA_3,    0x128c8242      },
-       {       XFER_UDMA_2,    0x120c8242      },
-       {       XFER_UDMA_1,    0x12148254      },
-       {       XFER_UDMA_0,    0x121882ea      },
-
-       {       XFER_MW_DMA_2,  0x22808242      },
-       {       XFER_MW_DMA_1,  0x22808254      },
-       {       XFER_MW_DMA_0,  0x228082ea      },
-
-       {       XFER_PIO_4,     0x0a81f442      },
-       {       XFER_PIO_3,     0x0a81f443      },
-       {       XFER_PIO_2,     0x0a81f454      },
-       {       XFER_PIO_1,     0x0ac1f465      },
-       {       XFER_PIO_0,     0x0ac1f48a      },
-       {       0,              0x06814e93      }
-};
 
 static const struct hpt_chip hpt370 = {
        "HPT370",
        48,
        {
-               hpt370_timings_33,
+               hpt37x_timings_33,
                NULL,
                NULL,
-               hpt370_timings_66
+               NULL
        }
 };
 
@@ -263,10 +138,10 @@ static const struct hpt_chip hpt370a = {
        "HPT370A",
        48,
        {
-               hpt370a_timings_33,
+               hpt37x_timings_33,
                NULL,
-               hpt370a_timings_50,
-               hpt370a_timings_66
+               hpt37x_timings_50,
+               NULL
        }
 };
 
@@ -274,10 +149,10 @@ static const struct hpt_chip hpt372 = {
        "HPT372",
        55,
        {
-               hpt372_timings_33,
+               hpt37x_timings_33,
                NULL,
-               hpt372_timings_50,
-               hpt372_timings_66
+               hpt37x_timings_50,
+               hpt37x_timings_66
        }
 };
 
@@ -285,10 +160,10 @@ static const struct hpt_chip hpt302 = {
        "HPT302",
        66,
        {
-               hpt372_timings_33,
+               hpt37x_timings_33,
                NULL,
-               hpt372_timings_50,
-               hpt372_timings_66
+               hpt37x_timings_50,
+               hpt37x_timings_66
        }
 };
 
@@ -296,10 +171,10 @@ static const struct hpt_chip hpt371 = {
        "HPT371",
        66,
        {
-               hpt372_timings_33,
+               hpt37x_timings_33,
                NULL,
-               hpt372_timings_50,
-               hpt372_timings_66
+               hpt37x_timings_50,
+               hpt37x_timings_66
        }
 };
 
@@ -307,10 +182,10 @@ static const struct hpt_chip hpt372a = {
        "HPT372A",
        66,
        {
-               hpt372_timings_33,
+               hpt37x_timings_33,
                NULL,
-               hpt372_timings_50,
-               hpt372_timings_66
+               hpt37x_timings_50,
+               hpt37x_timings_66
        }
 };
 
@@ -318,7 +193,7 @@ static const struct hpt_chip hpt374 = {
        "HPT374",
        48,
        {
-               hpt374_timings_33,
+               hpt37x_timings_33,
                NULL,
                NULL,
                NULL
@@ -397,13 +272,12 @@ static const char *bad_ata100_5[] = {
 
 /**
  *     hpt370_filter   -       mode selection filter
- *     @ap: ATA interface
  *     @adev: ATA device
  *
  *     Block UDMA on devices that cause trouble with this controller.
  */
 
-static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask)
 {
        if (adev->class == ATA_DEV_ATA) {
                if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
@@ -411,24 +285,23 @@ static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device
                if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
                        mask &= ~(0x1F << ATA_SHIFT_UDMA);
        }
-       return ata_pci_default_filter(ap, adev, mask);
+       return ata_pci_default_filter(adev, mask);
 }
 
 /**
  *     hpt370a_filter  -       mode selection filter
- *     @ap: ATA interface
  *     @adev: ATA device
  *
  *     Block UDMA on devices that cause trouble with this controller.
  */
 
-static unsigned long hpt370a_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
 {
        if (adev->class != ATA_DEV_ATA) {
                if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
                        mask &= ~ (0x1F << ATA_SHIFT_UDMA);
        }
-       return ata_pci_default_filter(ap, adev, mask);
+       return ata_pci_default_filter(adev, mask);
 }
 
 /**
@@ -462,8 +335,7 @@ static int hpt37x_pre_reset(struct ata_port *ap)
                ap->cbl = ATA_CBL_PATA80;
 
        /* Reset the state machine */
-       pci_write_config_byte(pdev, 0x50, 0x37);
-       pci_write_config_byte(pdev, 0x54, 0x37);
+       pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
        udelay(100);
 
        return ata_std_prereset(ap);
@@ -513,8 +385,7 @@ static int hpt374_pre_reset(struct ata_port *ap)
                ap->cbl = ATA_CBL_PATA80;
 
        /* Reset the state machine */
-       pci_write_config_byte(pdev, 0x50, 0x37);
-       pci_write_config_byte(pdev, 0x54, 0x37);
+       pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
        udelay(100);
 
        return ata_std_prereset(ap);
@@ -1032,6 +903,24 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                .udma_mask = 0x3f,
                .port_ops = &hpt370a_port_ops
        };
+       /* HPT370 - UDMA100 */
+       static struct ata_port_info info_hpt370_33 = {
+               .sht = &hpt37x_sht,
+               .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+               .pio_mask = 0x1f,
+               .mwdma_mask = 0x07,
+               .udma_mask = 0x0f,
+               .port_ops = &hpt370_port_ops
+       };
+       /* HPT370A - UDMA100 */
+       static struct ata_port_info info_hpt370a_33 = {
+               .sht = &hpt37x_sht,
+               .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+               .pio_mask = 0x1f,
+               .mwdma_mask = 0x07,
+               .udma_mask = 0x0f,
+               .port_ops = &hpt370a_port_ops
+       };
        /* HPT371, 372 and friends - UDMA133 */
        static struct ata_port_info info_hpt372 = {
                .sht = &hpt37x_sht,
@@ -1067,7 +956,11 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
        u8 irqmask;
        u32 class_rev;
+       u8 mcr1;
        u32 freq;
+       int prefer_dpll = 1;
+       
+       unsigned long iobase = pci_resource_start(dev, 4);
 
        const struct hpt_chip *chip_table;
        int clock_slot;
@@ -1088,10 +981,12 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        case 3:
                                port = &info_hpt370;
                                chip_table = &hpt370;
+                               prefer_dpll = 0;
                                break;
                        case 4:
                                port = &info_hpt370a;
                                chip_table = &hpt370a;
+                               prefer_dpll = 0;
                                break;
                        case 5:
                                port = &info_hpt372;
@@ -1119,8 +1014,16 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                                chip_table = &hpt302;
                                break;
                        case PCI_DEVICE_ID_TTI_HPT371:
+                               if (class_rev > 1)
+                                       return -ENODEV;
                                port = &info_hpt372;
                                chip_table = &hpt371;
+                               /* Single channel device, master is not present
+                                  but the BIOS (or us for non x86) must mark it
+                                  absent */
+                               pci_read_config_byte(dev, 0x50, &mcr1);
+                               mcr1 &= ~0x04;
+                               pci_write_config_byte(dev, 0x50, mcr1);
                                break;
                        case PCI_DEVICE_ID_TTI_HPT374:
                                chip_table = &hpt374;
@@ -1150,8 +1053,18 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
         */
 
        pci_write_config_byte(dev, 0x5b, 0x23);
+       
+       /*
+        * HighPoint does this for HPT372A.
+        * NOTE: This register is only writeable via I/O space.
+        */
+       if (chip_table == &hpt372a)
+               outb(0x0e, iobase + 0x9c);
 
-       pci_read_config_dword(dev, 0x70, &freq);
+       /* Some devices do not let this value be accessed via PCI space
+          according to the old driver */
+
+       freq = inl(iobase + 0x90);
        if ((freq >> 12) != 0xABCDE) {
                int i;
                u8 sr;
@@ -1162,7 +1075,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                /* This is the process the HPT371 BIOS is reported to use */
                for(i = 0; i < 128; i++) {
                        pci_read_config_byte(dev, 0x78, &sr);
-                       total += sr;
+                       total += sr & 0x1FF;
                        udelay(15);
                }
                freq = total / 128;
@@ -1173,15 +1086,27 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
         *      Turn the frequency check into a band and then find a timing
         *      table to match it.
         */
-
+        
        clock_slot = hpt37x_clock_slot(freq, chip_table->base);
-       if (chip_table->clocks[clock_slot] == NULL) {
+       if (chip_table->clocks[clock_slot] == NULL || prefer_dpll) {
                /*
                 *      We need to try PLL mode instead
+                *
+                *      For non UDMA133 capable devices we should
+                *      use a 50MHz DPLL by choice
                 */
-               unsigned int f_low = (MHz[clock_slot] * chip_table->base) / 192;
-               unsigned int f_high = f_low + 2;
+               unsigned int f_low, f_high;
                int adjust;
+               
+               clock_slot = 2;
+               if (port->udma_mask & 0xE0)
+                       clock_slot = 3;
+               
+               f_low = (MHz[clock_slot] * chip_table->base) / 192;
+               f_high = f_low + 2;
+
+               /* Select the DPLL clock. */
+               pci_write_config_byte(dev, 0x5b, 0x21);
 
                for(adjust = 0; adjust < 8; adjust++) {
                        if (hpt37x_calibrate_dpll(dev))
@@ -1197,25 +1122,27 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        printk(KERN_WARNING "hpt37x: DPLL did not stabilize.\n");
                        return -ENODEV;
                }
-               /* Check if this works for all cases */
-               port->private_data = (void *)hpt370_timings_66;
+               if (clock_slot == 3)
+                       port->private_data = (void *)hpt37x_timings_66;
+               else
+                       port->private_data = (void *)hpt37x_timings_50;
 
                printk(KERN_INFO "hpt37x: Bus clock %dMHz, using DPLL.\n", MHz[clock_slot]);
        } else {
                port->private_data = (void *)chip_table->clocks[clock_slot];
                /*
-                *      Perform a final fixup. The 371 and 372 clock determines
-                *      if UDMA133 is available.
-                */
-
-               if (clock_slot == 2 && chip_table == &hpt372) { /* 50Mhz */
-                       printk(KERN_WARNING "pata_hpt37x: No UDMA133 support available with 50MHz bus clock.\n");
-                       if (port == &info_hpt372)
-                               port = &info_hpt372_50;
-                       else BUG();
-               }
+                *      Perform a final fixup. Note that we will have used the
+                *      DPLL on the HPT372 which means we don't have to worry
+                *      about lack of UDMA133 support on lower clocks
+                */
+
+               if (clock_slot < 2 && port == &info_hpt370)
+                       port = &info_hpt370_33;
+               if (clock_slot < 2 && port == &info_hpt370a)
+                       port = &info_hpt370a_33;
                printk(KERN_INFO "hpt37x: %s: Bus clock %dMHz.\n", chip_table->name, MHz[clock_slot]);
        }
+
        port_info[0] = port_info[1] = port;
        /* Now kick off ATA set up */
        return ata_pci_init_one(dev, port_info, 2);
index 65f2e180e7fa285644e9bf38522d39846da446b5..6a34521b9e01a7ded70309d3b528c0d7b4f1410e 100644 (file)
@@ -8,10 +8,10 @@
  * Copyright (C) 1999-2003             Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001         Sun Microsystems, Inc.
  * Portions Copyright (C) 2003         Red Hat Inc
+ * Portions Copyright (C) 2005-2006    MontaVista Software, Inc.
  *
  *
  * TODO
- *     371N
  *     Work out best PLL policy
  */
 
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt3x2n"
-#define DRV_VERSION    "0.3.2"
+#define DRV_VERSION    "0.3.3"
 
 enum {
        HPT_PCI_FAST    =       (1 << 31),
@@ -115,14 +115,13 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
 }
 
 /**
- *     hpt3x2n_pre_reset       -       reset the hpt3x2n bus
- *     @ap: ATA port to reset
+ *     hpt3x2n_cable_detect    -       Detect the cable type
+ *     @ap: ATA port to detect on
  *
- *     Perform the initial reset handling for the 3x2n series controllers.
- *     Reset the hardware and state machine, obtain the cable type.
+ *     Return the cable type attached to this port
  */
 
-static int hpt3xn_pre_reset(struct ata_port *ap)
+static int hpt3x2n_cable_detect(struct ata_port *ap)
 {
        u8 scr2, ata66;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -135,15 +134,26 @@ static int hpt3xn_pre_reset(struct ata_port *ap)
        pci_write_config_byte(pdev, 0x5B, scr2);
 
        if (ata66 & (1 << ap->port_no))
-               ap->cbl = ATA_CBL_PATA40;
+               return ATA_CBL_PATA40;
        else
-               ap->cbl = ATA_CBL_PATA80;
+               return ATA_CBL_PATA80;
+}
+
+/**
+ *     hpt3x2n_pre_reset       -       reset the hpt3x2n bus
+ *     @ap: ATA port to reset
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     Perform the initial reset handling for the 3x2n series controllers.
+ *     Reset the hardware and state machine,
+ */
 
+static int hpt3xn_pre_reset(struct ata_port *ap)
+{
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        /* Reset the state machine */
-       pci_write_config_byte(pdev, 0x50, 0x37);
-       pci_write_config_byte(pdev, 0x54, 0x37);
+       pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
        udelay(100);
-
        return ata_std_prereset(ap);
 }
 
@@ -364,6 +374,7 @@ static struct ata_port_operations hpt3x2n_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = hpt3x2n_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = hpt3x2n_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -422,8 +433,9 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
 {
        unsigned long freq;
        u32 fcnt;
+       unsigned long iobase = pci_resource_start(pdev, 4);
 
-       pci_read_config_dword(pdev, 0x70/*CHECKME*/, &fcnt);
+       fcnt = inl(iobase + 0x90);      /* Not PCI readable for some chips */
        if ((fcnt >> 12) != 0xABCDE) {
                printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n");
                return 33;      /* Not BIOS set */
@@ -492,6 +504,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        unsigned int pci_mhz;
        unsigned int f_low, f_high;
        int adjust;
+       unsigned long iobase = pci_resource_start(dev, 4);
 
        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
        class_rev &= 0xFF;
@@ -501,6 +514,11 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        if (class_rev < 6)
                                return -ENODEV;
                        break;
+               case PCI_DEVICE_ID_TTI_HPT371:
+                       if (class_rev < 2)
+                               return -ENODEV;
+                       /* 371N if rev > 1 */
+                       break;
                case PCI_DEVICE_ID_TTI_HPT372:
                        /* 372N if rev >= 1*/
                        if (class_rev == 0)
@@ -528,6 +546,19 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        irqmask &= ~0x10;
        pci_write_config_byte(dev, 0x5a, irqmask);
 
+       /*
+        * HPT371 chips physically have only one channel, the secondary one,
+        * but the primary channel registers do exist!  Go figure...
+        * So,  we manually disable the non-existing channel here
+        * (if the BIOS hasn't done this already).
+        */
+       if (dev->device == PCI_DEVICE_ID_TTI_HPT371) {
+               u8 mcr1;
+               pci_read_config_byte(dev, 0x50, &mcr1);
+               mcr1 &= ~0x04;
+               pci_write_config_byte(dev, 0x50, mcr1);
+       }
+
        /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
           50 for UDMA100. Right now we always use 66 */
 
@@ -546,14 +577,24 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        break;
                pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
        }
-       if (adjust == 8)
-               printk(KERN_WARNING "hpt3xn: DPLL did not stabilize.\n");
+       if (adjust == 8) {
+               printk(KERN_WARNING "hpt3x2n: DPLL did not stabilize.\n");
+               return -ENODEV;
+       }
 
        /* Set our private data up. We only need a few flags so we use
           it directly */
        port->private_data = NULL;
-       if (pci_mhz > 60)
+       if (pci_mhz > 60) {
                port->private_data = (void *)PCI66;
+               /*
+                * On  HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+                * the MISC. register to stretch the UltraDMA Tss timing.
+                * NOTE: This register is only writeable via I/O space.
+                */
+               if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
+                       outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
+       }
 
        /* Now kick off ATA set up */
        port_info[0] = port_info[1] = port;
@@ -562,6 +603,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
 static const struct pci_device_id hpt3x2n[] = {
        { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+       { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), },
        { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
        { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
        { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), },
index 813485c8526c433a0d7931ea429351680ef7aeb5..ac28ec8c50aa61a19f03c704c843f50b8709ba05 100644 (file)
 #define DRV_NAME       "pata_hpt3x3"
 #define DRV_VERSION    "0.4.2"
 
-static int hpt3x3_probe_init(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA40;
-       return ata_std_prereset(ap);
-}
-
-/**
- *     hpt3x3_probe_reset      -       reset the hpt3x3 bus
- *     @ap: ATA port to reset
- *
- *     Perform the housekeeping when doing an ATA bus reeset. We just
- *     need to force the cable type.
- */
-
-static void hpt3x3_error_handler(struct ata_port *ap)
-{
-       return ata_bmdma_drive_eh(ap, hpt3x3_probe_init, ata_std_softreset, NULL, ata_std_postreset);
-}
-
 /**
  *     hpt3x3_set_piomode              -       PIO setup
  *     @ap: ATA interface
@@ -139,8 +120,9 @@ static struct ata_port_operations hpt3x3_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = hpt3x3_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index 1a61cc89174191cb65e9e8ef6474b6cf74b633d2..d042efdfbac4d5483f277306146dbd9384b32b7e 100644 (file)
@@ -49,13 +49,13 @@ static struct ata_port_operations isapnp_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
 
        .data_xfer      = ata_data_xfer,
 
-       .irq_handler    = ata_interrupt,
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
        .irq_ack        = ata_irq_ack,
@@ -74,8 +74,10 @@ static struct ata_port_operations isapnp_port_ops = {
 
 static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id)
 {
-       struct ata_probe_ent ae;
+       struct ata_host *host;
+       struct ata_port *ap;
        void __iomem *cmd_addr, *ctl_addr;
+       int rc;
 
        if (pnp_port_valid(idev, 0) == 0)
                return -ENODEV;
@@ -84,34 +86,36 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
        if (pnp_irq_valid(idev, 0) == 0)
                return -ENODEV;
 
+       /* allocate host */
+       host = ata_host_alloc(&idev->dev, 1);
+       if (!host)
+               return -ENOMEM;
+
+       /* acquire resources and fill host */
        cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8);
        if (!cmd_addr)
                return -ENOMEM;
 
-       memset(&ae, 0, sizeof(struct ata_probe_ent));
-       INIT_LIST_HEAD(&ae.node);
-       ae.dev = &idev->dev;
-       ae.port_ops = &isapnp_port_ops;
-       ae.sht = &isapnp_sht;
-       ae.n_ports = 1;
-       ae.pio_mask = 1;                /* ISA so PIO 0 cycles */
-       ae.irq = pnp_irq(idev, 0);
-       ae.irq_flags = 0;
-       ae.port_flags = ATA_FLAG_SLAVE_POSS;
-       ae.port[0].cmd_addr = cmd_addr;
+       ap = host->ports[0];
+
+       ap->ops = &isapnp_port_ops;
+       ap->pio_mask = 1;
+       ap->flags |= ATA_FLAG_SLAVE_POSS;
+
+       ap->ioaddr.cmd_addr = cmd_addr;
 
        if (pnp_port_valid(idev, 1) == 0) {
                ctl_addr = devm_ioport_map(&idev->dev,
                                           pnp_port_start(idev, 1), 1);
-               ae.port[0].altstatus_addr = ctl_addr;
-               ae.port[0].ctl_addr = ctl_addr;
-               ae.port_flags |= ATA_FLAG_SRST;
+               ap->ioaddr.altstatus_addr = ctl_addr;
+               ap->ioaddr.ctl_addr = ctl_addr;
        }
-       ata_std_ports(&ae.port[0]);
 
-       if (ata_device_add(&ae) == 0)
-               return -ENODEV;
-       return 0;
+       ata_std_ports(&ap->ioaddr);
+
+       /* activate */
+       return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0,
+                                &isapnp_sht);
 }
 
 /**
index ea734701555ee8d0f1ecb9810fdf561a755b33ed..011306ef8334f8d7b701d6748190cb858fd79602 100644 (file)
@@ -25,8 +25,8 @@
  *     it8213_pre_reset        -       check for 40/80 pin
  *     @ap: Port
  *
- *     Perform cable detection for the 8213 ATA interface. This is
- *     different to the PIIX arrangement
+ *     Filter out ports by the enable bits before doing the normal reset
+ *     and probe.
  */
 
 static int it8213_pre_reset(struct ata_port *ap)
@@ -34,23 +34,14 @@ static int it8213_pre_reset(struct ata_port *ap)
        static const struct pci_bits it8213_enable_bits[] = {
                { 0x41U, 1U, 0x80UL, 0x80UL },  /* port 0 */
        };
-
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u8 tmp;
-
        if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
                return -ENOENT;
-
-       pci_read_config_byte(pdev, 0x42, &tmp);
-       if (tmp & 2)    /* The initial docs are incorrect */
-               ap->cbl = ATA_CBL_PATA40;
-       else
-               ap->cbl = ATA_CBL_PATA80;
        return ata_std_prereset(ap);
 }
 
 /**
- *     it8213_probe_reset - Probe specified port on PATA host controller
+ *     it8213_error_handler - Probe specified port on PATA host controller
  *     @ap: Port to probe
  *
  *     LOCKING:
@@ -62,10 +53,28 @@ static void it8213_error_handler(struct ata_port *ap)
        ata_bmdma_drive_eh(ap, it8213_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
 }
 
+/**
+ *     it8213_cable_detect     -       check for 40/80 pin
+ *     @ap: Port
+ *
+ *     Perform cable detection for the 8213 ATA interface. This is
+ *     different to the PIIX arrangement
+ */
+
+static int it8213_cable_detect(struct ata_port *ap)
+{
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       u8 tmp;
+       pci_read_config_byte(pdev, 0x42, &tmp);
+       if (tmp & 2)    /* The initial docs are incorrect */
+               return ATA_CBL_PATA40;
+       return ATA_CBL_PATA80;
+}
+
 /**
  *     it8213_set_piomode - Initialize host controller PATA PIO timings
  *     @ap: Port whose timings we are configuring
- *     @adev: um
+ *     @adev: Device whose timings we are configuring
  *
  *     Set PIO mode for device, in host controller PCI config space.
  *
@@ -268,6 +277,7 @@ static const struct ata_port_operations it8213_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = it8213_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = it8213_cable_detect,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
index 35ecb2ba067b8b09453d0236071c4bde42a51214..f1f8cec8c224aad4ae1375eb0ea551a810652966 100644 (file)
@@ -80,7 +80,7 @@
 
 
 #define DRV_NAME "pata_it821x"
-#define DRV_VERSION "0.3.4"
+#define DRV_VERSION "0.3.6"
 
 struct it821x_dev
 {
@@ -112,31 +112,6 @@ struct it821x_dev
 
 static int it8212_noraid;
 
-/**
- *     it821x_pre_reset        -       probe
- *     @ap: ATA port
- *
- *     Set the cable type
- */
-
-static int it821x_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA80;
-       return ata_std_prereset(ap);
-}
-
-/**
- *     it821x_error_handler    -       probe/reset
- *     @ap: ATA port
- *
- *     Set the cable type and trigger a probe
- */
-
-static void it821x_error_handler(struct ata_port *ap)
-{
-       return ata_bmdma_drive_eh(ap, it821x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
 /**
  *     it821x_program  -       program the PIO/MWDMA registers
  *     @ap: ATA port
@@ -520,7 +495,6 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused
 
 /**
  *     it821x_dev_config       -       Called each device identify
- *     @ap: ATA port
  *     @adev: Device that has just been identified
  *
  *     Perform the initial setup needed for each device that is chip
@@ -531,7 +505,7 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused
  *     basically we need to filter commands for this chip.
  */
 
-static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev)
+static void it821x_dev_config(struct ata_device *adev)
 {
        unsigned char model_num[ATA_ID_PROD_LEN + 1];
 
@@ -667,8 +641,9 @@ static struct ata_port_operations it821x_smart_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = it821x_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_unknown,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -703,8 +678,9 @@ static struct ata_port_operations it821x_passthru_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = it821x_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_unknown,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = it821x_passthru_bmdma_start,
index c6f0e192755156523ccb3cb93cf84e656c2833fe..420c343e57111107d88684557e8ea753f485fb39 100644 (file)
@@ -129,8 +129,8 @@ static struct ata_port_operations ixp4xx_port_ops = {
        .qc_issue       = ata_qc_issue_prot,
        .eng_timeout    = ata_eng_timeout,
        .data_xfer      = ixp4xx_mmio_data_xfer,
+       .cable_detect   = ata_cable_40wire,
 
-       .irq_handler    = ata_interrupt,
        .irq_clear      = ixp4xx_irq_clear,
        .irq_on         = ata_irq_on,
        .irq_ack        = ata_irq_ack,
@@ -173,12 +173,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
 
 static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
 {
-       int ret;
        unsigned int irq;
        struct resource *cs0, *cs1;
-       struct ata_probe_ent ae;
-
+       struct ata_host *host;
+       struct ata_port *ap;
        struct ixp4xx_pata_data *data = pdev->dev.platform_data;
+       int rc;
 
        cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -186,6 +186,12 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
        if (!cs0 || !cs1)
                return -EINVAL;
 
+       /* allocate host */
+       host = ata_host_alloc(&pdev->dev, 1);
+       if (!host)
+               return -ENOMEM;
+
+       /* acquire resources and fill host */
        pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
 
        data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
@@ -199,32 +205,22 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
        *data->cs0_cfg = data->cs0_bits;
        *data->cs1_cfg = data->cs1_bits;
 
-       memset(&ae, 0, sizeof(struct ata_probe_ent));
-       INIT_LIST_HEAD(&ae.node);
+       ap = host->ports[0];
 
-       ae.dev          = &pdev->dev;
-       ae.port_ops     = &ixp4xx_port_ops;
-       ae.sht          = &ixp4xx_sht;
-       ae.n_ports      = 1;
-       ae.pio_mask     = 0x1f; /* PIO4 */
-       ae.irq          = irq;
-       ae.irq_flags    = 0;
-       ae.port_flags   = ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY
-                       | ATA_FLAG_NO_ATAPI | ATA_FLAG_SRST;
+       ap->ops = &ixp4xx_port_ops;
+       ap->pio_mask = 0x1f; /* PIO4 */
+       ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
 
        /* run in polling mode if no irq has been assigned */
        if (!irq)
-               ae.port_flags |= ATA_FLAG_PIO_POLLING;
+               ap->flags |= ATA_FLAG_PIO_POLLING;
 
-       ixp4xx_setup_port(&ae.port[0], data);
+       ixp4xx_setup_port(&ap->ioaddr, data);
 
        dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
 
-       ret = ata_device_add(&ae);
-       if (ret == 0)
-               return -ENODEV;
-
-       return 0;
+       /* activate host */
+       return ata_host_activate(host, irq, ata_interrupt, 0, &ixp4xx_sht);
 }
 
 static __devexit int ixp4xx_pata_remove(struct platform_device *dev)
index 86fbcd6a742b5dbb486b471806e496ef8ebf6712..707099291e017ae5beca51a8f866a6b1df99ebd1 100644 (file)
@@ -162,6 +162,7 @@ static struct ata_port_operations simple_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
@@ -185,6 +186,7 @@ static struct ata_port_operations legacy_port_ops = {
        .check_status   = ata_check_status,
        .exec_command   = ata_exec_command,
        .dev_select     = ata_std_dev_select,
+       .cable_detect   = ata_cable_40wire,
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
@@ -305,6 +307,7 @@ static struct ata_port_operations pdc20230_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
@@ -360,6 +363,7 @@ static struct ata_port_operations ht6560a_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
@@ -426,6 +430,7 @@ static struct ata_port_operations ht6560b_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
@@ -547,6 +552,7 @@ static struct ata_port_operations opti82c611a_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
@@ -680,6 +686,7 @@ static struct ata_port_operations opti82c46x_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = opti82c46x_qc_issue_prot,
@@ -709,7 +716,8 @@ static struct ata_port_operations opti82c46x_port_ops = {
 static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq)
 {
        struct legacy_data *ld = &legacy_data[nr_legacy_host];
-       struct ata_probe_ent ae;
+       struct ata_host *host;
+       struct ata_port *ap;
        struct platform_device *pdev;
        struct ata_port_operations *ops = &legacy_port_ops;
        void __iomem *io_addr, *ctrl_addr;
@@ -791,24 +799,23 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
        if (ops == &legacy_port_ops && (autospeed & mask))
                ops = &simple_port_ops;
 
-       memset(&ae, 0, sizeof(struct ata_probe_ent));
-       INIT_LIST_HEAD(&ae.node);
-       ae.dev = &pdev->dev;
-       ae.port_ops = ops;
-       ae.sht = &legacy_sht;
-       ae.n_ports = 1;
-       ae.pio_mask = pio_modes;
-       ae.irq = irq;
-       ae.irq_flags = 0;
-       ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST|iordy;
-       ae.port[0].cmd_addr = io_addr;
-       ae.port[0].altstatus_addr = ctrl_addr;
-       ae.port[0].ctl_addr = ctrl_addr;
-       ata_std_ports(&ae.port[0]);
-       ae.private_data = ld;
-
-       ret = -ENODEV;
-       if (!ata_device_add(&ae))
+       ret = -ENOMEM;
+       host = ata_host_alloc(&pdev->dev, 1);
+       if (!host)
+               goto fail;
+       ap = host->ports[0];
+
+       ap->ops = ops;
+       ap->pio_mask = pio_modes;
+       ap->flags |= ATA_FLAG_SLAVE_POSS | iordy;
+       ap->ioaddr.cmd_addr = io_addr;
+       ap->ioaddr.altstatus_addr = ctrl_addr;
+       ap->ioaddr.ctl_addr = ctrl_addr;
+       ata_std_ports(&ap->ioaddr);
+       ap->private_data = ld;
+
+       ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
+       if (ret)
                goto fail;
 
        legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
index 6dd7c4ef3e66bbd93832a2b4e36398a36f5756e2..d9b94a1b6954ed384b3d351858cd91f4a7baed70 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/ata.h>
 
 #define DRV_NAME       "pata_marvell"
-#define DRV_VERSION    "0.1.1"
+#define DRV_VERSION    "0.1.4"
 
 /**
  *     marvell_pre_reset       -       check for 40/80 pin
@@ -52,22 +52,23 @@ static int marvell_pre_reset(struct ata_port *ap)
        if ((pdev->device == 0x6145) && (ap->port_no == 0) &&
            (!(devices & 0x10)))        /* PATA enable ? */
                return -ENOENT;
+       return ata_std_prereset(ap);
+}
 
+static int marvell_cable_detect(struct ata_port *ap)
+{
        /* Cable type */
        switch(ap->port_no)
        {
        case 0:
                if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1)
-                       ap->cbl = ATA_CBL_PATA40;
-               else
-                       ap->cbl = ATA_CBL_PATA80;
-               break;
-
+                       return ATA_CBL_PATA40;
+               return ATA_CBL_PATA80;
        case 1: /* Legacy SATA port */
-               ap->cbl = ATA_CBL_SATA;
-               break;
+               return ATA_CBL_SATA;
        }
-       return ata_std_prereset(ap);
+       BUG();
+       return 0;       /* Our BUG macro needs the right markup */
 }
 
 /**
@@ -123,6 +124,7 @@ static const struct ata_port_operations marvell_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = marvell_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = marvell_cable_detect,
 
        /* BMDMA handling is PCI ATA format, use helpers */
        .bmdma_setup            = ata_bmdma_setup,
index 882c36eaf2935ce8e1184c56cc915b699e2aee61..9587a89f9683d98d46b4e359441b35dc598c11a9 100644 (file)
@@ -24,7 +24,7 @@
 
 
 #define DRV_NAME       "mpc52xx_ata"
-#define DRV_VERSION    "0.1.0"
+#define DRV_VERSION    "0.1.0ac2"
 
 
 /* Private structures used by the driver */
@@ -297,38 +297,37 @@ static struct ata_port_operations mpc52xx_ata_port_ops = {
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = mpc52xx_ata_error_handler,
+       .cable_detect           = ata_cable_40wire,
        .qc_prep                = ata_qc_prep,
        .qc_issue               = ata_qc_issue_prot,
        .data_xfer              = ata_data_xfer,
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
        .port_start             = ata_port_start,
 };
 
-static struct ata_probe_ent mpc52xx_ata_probe_ent = {
-       .port_ops       = &mpc52xx_ata_port_ops,
-       .sht            = &mpc52xx_ata_sht,
-       .n_ports        = 1,
-       .pio_mask       = 0x1f,         /* Up to PIO4 */
-       .mwdma_mask     = 0x00,         /* No MWDMA   */
-       .udma_mask      = 0x00,         /* No UDMA    */
-       .port_flags     = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
-       .irq_flags      = 0,
-};
-
 static int __devinit
 mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
 {
-       struct ata_probe_ent *ae = &mpc52xx_ata_probe_ent;
-       struct ata_ioports *aio = &ae->port[0];
-       int rv;
-
-       INIT_LIST_HEAD(&ae->node);
-       ae->dev = dev;
-       ae->irq = priv->ata_irq;
-
+       struct ata_host *host;
+       struct ata_port *ap;
+       struct ata_ioports *aio;
+       int rc;
+
+       host = ata_host_alloc(dev, 1);
+       if (!host)
+               return -ENOMEM;
+
+       ap = host->ports[0];
+       ap->flags               |= ATA_FLAG_SLAVE_POSS;
+       ap->pio_mask            = 0x1f; /* Up to PIO4 */
+       ap->mwdma_mask          = 0x00; /* No MWDMA   */
+       ap->udma_mask           = 0x00; /* No UDMA    */
+       ap->ops                 = &mpc52xx_ata_port_ops;
+       host->private_data      = priv;
+
+       aio = &ap->ioaddr;
        aio->cmd_addr           = NULL; /* Don't have a classic reg block */
        aio->altstatus_addr     = &priv->ata_regs->tf_control;
        aio->ctl_addr           = &priv->ata_regs->tf_control;
@@ -343,11 +342,9 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
        aio->status_addr        = &priv->ata_regs->tf_command;
        aio->command_addr       = &priv->ata_regs->tf_command;
 
-       ae->private_data = priv;
-
-       rv = ata_device_add(ae);
-
-       return rv ? 0 : -EINVAL;
+       /* activate host */
+       return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0,
+                                &mpc52xx_ata_sht);
 }
 
 static struct mpc52xx_ata_priv *
index 4abe45ac19a2c121c03655875dd63b951c2c6d35..987c5fafab087e72b1490c30ca9983d0bb506f3b 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_mpiix"
-#define DRV_VERSION "0.7.5"
+#define DRV_VERSION "0.7.6"
 
 enum {
        IDETIM = 0x6C,          /* IDE control register */
@@ -53,7 +53,6 @@ static int mpiix_pre_reset(struct ata_port *ap)
 
        if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
                return -ENOENT;
-       ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 }
 
@@ -185,12 +184,12 @@ static struct ata_port_operations mpiix_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = mpiix_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = mpiix_qc_issue_prot,
        .data_xfer      = ata_data_xfer,
 
-       .irq_handler    = ata_interrupt,
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
        .irq_ack        = ata_irq_ack,
@@ -201,8 +200,9 @@ static struct ata_port_operations mpiix_port_ops = {
 static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        /* Single threaded by the PCI probe logic */
-       static struct ata_probe_ent probe;
        static int printed_version;
+       struct ata_host *host;
+       struct ata_port *ap;
        void __iomem *cmd_addr, *ctl_addr;
        u16 idetim;
        int irq;
@@ -210,6 +210,10 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
 
+       host = ata_host_alloc(&dev->dev, 1);
+       if (!host)
+               return -ENOMEM;
+
        /* MPIIX has many functions which can be turned on or off according
           to other devices present. Make sure IDE is enabled before we try
           and use it */
@@ -238,27 +242,21 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
           without BARs set fools the setup.  #2 If you pci_disable_device
           the MPIIX your box goes castors up */
 
-       INIT_LIST_HEAD(&probe.node);
-       probe.dev = pci_dev_to_dev(dev);
-       probe.port_ops = &mpiix_port_ops;
-       probe.sht = &mpiix_sht;
-       probe.pio_mask = 0x1F;
-       probe.irq_flags = IRQF_SHARED;
-       probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
-       probe.n_ports = 1;
+       ap = host->ports[0];
+       ap->ops = &mpiix_port_ops;
+       ap->pio_mask = 0x1F;
+       ap->flags |= ATA_FLAG_SLAVE_POSS;
 
-       probe.irq = irq;
-       probe.port[0].cmd_addr = cmd_addr;
-       probe.port[0].ctl_addr = ctl_addr;
-       probe.port[0].altstatus_addr = ctl_addr;
+       ap->ioaddr.cmd_addr = cmd_addr;
+       ap->ioaddr.ctl_addr = ctl_addr;
+       ap->ioaddr.altstatus_addr = ctl_addr;
 
        /* Let libata fill in the port details */
-       ata_std_ports(&probe.port[0]);
+       ata_std_ports(&ap->ioaddr);
 
-       /* Now add the port that is active */
-       if (ata_device_add(&probe))
-               return 0;
-       return -ENODEV;
+       /* activate host */
+       return ata_host_activate(host, irq, ata_interrupt, IRQF_SHARED,
+                                &mpiix_sht);
 }
 
 static const struct pci_device_id mpiix[] = {
index 38f99b38a5ea97a861e1a8cb2d1d27f324ea38cc..dbba5b77d79c907e0444a89a1732848cab277891 100644 (file)
 #include <linux/ata.h>
 
 #define DRV_NAME       "pata_netcell"
-#define DRV_VERSION    "0.1.6"
-
-/**
- *     netcell_probe_init      -       check for 40/80 pin
- *     @ap: Port
- *
- *     Cables are handled by the RAID controller. Report 80 pin.
- */
-
-static int netcell_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA80;
-       return ata_std_prereset(ap);
-}
-
-/**
- *     netcell_probe_reset - Probe specified port on PATA host controller
- *     @ap: Port to probe
- *
- *     LOCKING:
- *     None (inherited from caller).
- */
-
-static void netcell_error_handler(struct ata_port *ap)
-{
-       return ata_bmdma_drive_eh(ap, netcell_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
+#define DRV_VERSION    "0.1.7"
 
 /* No PIO or DMA methods needed for this device */
 
@@ -81,8 +55,9 @@ static const struct ata_port_operations netcell_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = netcell_error_handler,
+       .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_80wire,
 
        /* BMDMA handling is PCI ATA format, use helpers */
        .bmdma_setup            = ata_bmdma_setup,
index 9944a28daa9c681874413ea23f8d95a938dc678a..078aeda9cf8d81eacea9e824adec6f199d683a52 100644 (file)
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_ns87410"
-#define DRV_VERSION "0.4.3"
+#define DRV_VERSION "0.4.6"
 
 /**
  *     ns87410_pre_reset               -       probe begin
  *     @ap: ATA port
  *
- *     Set up cable type and use generic probe init
+ *     Check enabled ports
  */
 
 static int ns87410_pre_reset(struct ata_port *ap)
@@ -47,7 +47,6 @@ static int ns87410_pre_reset(struct ata_port *ap)
 
        if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
                return -ENOENT;
-       ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 }
 
@@ -177,6 +176,7 @@ static struct ata_port_operations ns87410_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ns87410_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ns87410_qc_issue_prot,
index da68cd19efd612cfc5f5bde902b98605ab23683f..dea4690340d1ed291cfd58c011d4f40ab55c11a1 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/ata.h>
 
 #define DRV_NAME       "pata_oldpiix"
-#define DRV_VERSION    "0.5.4"
+#define DRV_VERSION    "0.5.5"
 
 /**
  *     oldpiix_pre_reset               -       probe begin
@@ -44,7 +44,6 @@ static int oldpiix_pre_reset(struct ata_port *ap)
 
        if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
                return -ENOENT;
-       ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 }
 
@@ -65,7 +64,7 @@ static void oldpiix_pata_error_handler(struct ata_port *ap)
 /**
  *     oldpiix_set_piomode - Initialize host controller PATA PIO timings
  *     @ap: Port whose timings we are configuring
- *     @adev: um
+ *     @adev: Device whose timings we are configuring
  *
  *     Set PIO mode for device, in host controller PCI config space.
  *
@@ -255,6 +254,7 @@ static const struct ata_port_operations oldpiix_pata_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = oldpiix_pata_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_40wire,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
index 3fd3a35c2241bf1015189e25db264389480ef128..13b63e21838d9ff94c0be60051c5a6e1190e78ee 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_opti"
-#define DRV_VERSION "0.2.8"
+#define DRV_VERSION "0.2.9"
 
 enum {
        READ_REG        = 0,    /* index of Read cycle timing register */
@@ -61,8 +61,6 @@ static int opti_pre_reset(struct ata_port *ap)
 
        if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
                return -ENOENT;
-
-       ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 }
 
@@ -198,6 +196,7 @@ static struct ata_port_operations opti_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = opti_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index 9764907e8a134e20a238478bab1f932d9f224c0e..b70e04c144dfa591ec6afe925b9b9acaa756b118 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_optidma"
-#define DRV_VERSION "0.2.4"
+#define DRV_VERSION "0.3.2"
 
 enum {
        READ_REG        = 0,    /* index of Read cycle timing register */
@@ -62,7 +62,6 @@ static int optidma_pre_reset(struct ata_port *ap)
        if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
                return -ENOENT;
 
-       ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 }
 
@@ -115,7 +114,7 @@ static void optidma_lock(struct ata_port *ap)
 }
 
 /**
- *     optidma_set_mode        -       set mode data
+ *     optidma_mode_setup      -       set mode data
  *     @ap: ATA interface
  *     @adev: ATA device
  *     @mode: Mode to set
@@ -128,7 +127,7 @@ static void optidma_lock(struct ata_port *ap)
  *     IRQ here we depend on the host set locking to avoid catastrophe.
  */
 
-static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+static void optidma_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 mode)
 {
        struct ata_device *pair = ata_dev_pair(adev);
        int pio = adev->pio_mode - XFER_PIO_0;
@@ -202,7 +201,7 @@ static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
 }
 
 /**
- *     optiplus_set_mode       -       DMA setup for Firestar Plus
+ *     optiplus_mode_setup     -       DMA setup for Firestar Plus
  *     @ap: ATA port
  *     @adev: device
  *     @mode: desired mode
@@ -213,7 +212,7 @@ static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
  *     one
  */
 
-static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+static void optiplus_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 mode)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u8 udcfg;
@@ -225,7 +224,7 @@ static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 m
        pci_read_config_byte(pdev, 0x44, &udcfg);
        if (mode <= XFER_UDMA_0) {
                udcfg &= ~(1 << unit);
-               optidma_set_mode(ap, adev, adev->dma_mode);
+               optidma_mode_setup(ap, adev, adev->dma_mode);
        } else {
                udcfg |=  (1 << unit);
                if (ap->port_no) {
@@ -253,7 +252,7 @@ static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 m
 
 static void optidma_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
 {
-       optidma_set_mode(ap, adev, adev->pio_mode);
+       optidma_mode_setup(ap, adev, adev->pio_mode);
 }
 
 /**
@@ -268,7 +267,7 @@ static void optidma_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
 
 static void optidma_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
 {
-       optidma_set_mode(ap, adev, adev->dma_mode);
+       optidma_mode_setup(ap, adev, adev->dma_mode);
 }
 
 /**
@@ -283,7 +282,7 @@ static void optidma_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
 
 static void optiplus_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
 {
-       optiplus_set_mode(ap, adev, adev->pio_mode);
+       optiplus_mode_setup(ap, adev, adev->pio_mode);
 }
 
 /**
@@ -298,7 +297,7 @@ static void optiplus_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
 
 static void optiplus_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
 {
-       optiplus_set_mode(ap, adev, adev->dma_mode);
+       optiplus_mode_setup(ap, adev, adev->dma_mode);
 }
 
 /**
@@ -322,26 +321,29 @@ static u8 optidma_make_bits43(struct ata_device *adev)
 }
 
 /**
- *     optidma_post_set_mode   -       finalize PCI setup
+ *     optidma_set_mode        -       mode setup
  *     @ap: port to set up
  *
- *     Finalise the configuration by writing the nibble of extra bits
- *     of data into the chip.
+ *     Use the standard setup to tune the chipset and then finalise the
+ *     configuration by writing the nibble of extra bits of data into
+ *     the chip.
  */
 
-static void optidma_post_set_mode(struct ata_port *ap)
+static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed)
 {
        u8 r;
        int nybble = 4 * ap->port_no;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-
-       pci_read_config_byte(pdev, 0x43, &r);
-
-       r &= (0x0F << nybble);
-       r |= (optidma_make_bits43(&ap->device[0]) +
-            (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
-
-       pci_write_config_byte(pdev, 0x43, r);
+       int rc  = ata_do_set_mode(ap, r_failed);
+       if (rc == 0) {
+               pci_read_config_byte(pdev, 0x43, &r);
+
+               r &= (0x0F << nybble);
+               r |= (optidma_make_bits43(&ap->device[0]) +
+                    (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
+               pci_write_config_byte(pdev, 0x43, r);
+       }
+       return rc;
 }
 
 static struct scsi_host_template optidma_sht = {
@@ -381,7 +383,8 @@ static struct ata_port_operations optidma_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
        .error_handler  = optidma_error_handler,
-       .post_set_mode  = optidma_post_set_mode,
+       .set_mode       = optidma_set_mode,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -416,7 +419,8 @@ static struct ata_port_operations optiplus_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
        .error_handler  = optidma_error_handler,
-       .post_set_mode  = optidma_post_set_mode,
+       .set_mode       = optidma_set_mode,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index 103720f873c8f31d8384b0f54b5b97975c2ad3bb..75dc84797ff322eb9b9ffce033c2581dc5f5f4c2 100644 (file)
@@ -42,7 +42,7 @@
 
 
 #define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.3.0"
+#define DRV_VERSION "0.3.1"
 
 /*
  *     Private data structure to glue stuff together
@@ -54,6 +54,39 @@ struct ata_pcmcia_info {
        dev_node_t      node;
 };
 
+/**
+ *     pcmcia_set_mode -       PCMCIA specific mode setup
+ *     @ap: Port
+ *     @r_failed_dev: Return pointer for failed device
+ *
+ *     Perform the tuning and setup of the devices and timings, which
+ *     for PCMCIA is the same as any other controller. We wrap it however
+ *     as we need to spot hardware with incorrect or missing master/slave
+ *     decode, which alas is embarrassingly common in the PC world
+ */
+
+static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+       struct ata_device *master = &ap->device[0];
+       struct ata_device *slave = &ap->device[1];
+
+       if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
+               return ata_do_set_mode(ap, r_failed_dev);
+
+       if (memcmp(master->id + ATA_ID_FW_REV,  slave->id + ATA_ID_FW_REV,
+                          ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0)
+       {
+               /* Suspicious match, but could be two cards from
+                  the same vendor - check serial */
+               if (memcmp(master->id + ATA_ID_SERNO, slave->id + ATA_ID_SERNO,
+                          ATA_ID_SERNO_LEN) == 0 && master->id[ATA_ID_SERNO] >> 8) {
+                       ata_dev_printk(slave, KERN_WARNING, "is a ghost device, ignoring.\n");
+                       ata_dev_disable(slave);
+               }
+       }
+       return ata_do_set_mode(ap, r_failed_dev);
+}
+
 static struct scsi_host_template pcmcia_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -73,6 +106,7 @@ static struct scsi_host_template pcmcia_sht = {
 };
 
 static struct ata_port_operations pcmcia_port_ops = {
+       .set_mode       = pcmcia_set_mode,
        .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
@@ -84,13 +118,13 @@ static struct ata_port_operations pcmcia_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
 
        .data_xfer      = ata_data_xfer_noirq,
 
-       .irq_handler    = ata_interrupt,
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
        .irq_ack        = ata_irq_ack,
@@ -111,7 +145,8 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
 static int pcmcia_init_one(struct pcmcia_device *pdev)
 {
-       struct ata_probe_ent ae;
+       struct ata_host *host;
+       struct ata_port *ap;
        struct ata_pcmcia_info *info;
        tuple_t tuple;
        struct {
@@ -255,24 +290,24 @@ next_entry:
         *      Having done the PCMCIA plumbing the ATA side is relatively
         *      sane.
         */
-
-       memset(&ae, 0, sizeof(struct ata_probe_ent));
-       INIT_LIST_HEAD(&ae.node);
-       ae.dev = &pdev->dev;
-       ae.port_ops = &pcmcia_port_ops;
-       ae.sht = &pcmcia_sht;
-       ae.n_ports = 1;
-       ae.pio_mask = 1;                /* ISA so PIO 0 cycles */
-       ae.irq = pdev->irq.AssignedIRQ;
-       ae.irq_flags = IRQF_SHARED;
-       ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
-       ae.port[0].cmd_addr = io_addr;
-       ae.port[0].altstatus_addr = ctl_addr;
-       ae.port[0].ctl_addr = ctl_addr;
-       ata_std_ports(&ae.port[0]);
-
-       ret = -ENODEV;
-       if (ata_device_add(&ae) == 0)
+       ret = -ENOMEM;
+       host = ata_host_alloc(&pdev->dev, 1);
+       if (!host)
+               goto failed;
+       ap = host->ports[0];
+
+       ap->ops = &pcmcia_port_ops;
+       ap->pio_mask = 1;               /* ISA so PIO 0 cycles */
+       ap->flags |= ATA_FLAG_SLAVE_POSS;
+       ap->ioaddr.cmd_addr = io_addr;
+       ap->ioaddr.altstatus_addr = ctl_addr;
+       ap->ioaddr.ctl_addr = ctl_addr;
+       ata_std_ports(&ap->ioaddr);
+
+       /* activate */
+       ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
+                               IRQF_SHARED, &pcmcia_sht);
+       if (ret)
                goto failed;
 
        info->ndev = 1;
index 93bcdadb7be3a17c8ff82f00dc5a7425cf3c9d26..a61cbc110688d1bf97859666aaa5fc7462cf7d2c 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_pdc2027x"
-#define DRV_VERSION    "0.8"
+#define DRV_VERSION    "0.9"
 #undef PDC_DEBUG
 
 #ifdef PDC_DEBUG
@@ -66,8 +66,10 @@ static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *e
 static void pdc2027x_error_handler(struct ata_port *ap);
 static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev);
 static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
-static void pdc2027x_post_set_mode(struct ata_port *ap);
 static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc);
+static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask);
+static int pdc2027x_cable_detect(struct ata_port *ap);
+static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed);
 
 /*
  * ATA Timing Tables based on 133MHz controller clock.
@@ -146,6 +148,7 @@ static struct scsi_host_template pdc2027x_sht = {
 
 static struct ata_port_operations pdc2027x_pata100_ops = {
        .port_disable           = ata_port_disable,
+       .mode_filter            = ata_pci_default_filter,
 
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
@@ -166,8 +169,8 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = pdc2027x_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = pdc2027x_cable_detect,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -179,7 +182,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
        .port_disable           = ata_port_disable,
        .set_piomode            = pdc2027x_set_piomode,
        .set_dmamode            = pdc2027x_set_dmamode,
-       .post_set_mode          = pdc2027x_post_set_mode,
+       .set_mode               = pdc2027x_set_mode,
+       .mode_filter            = pdc2027x_mode_filter,
 
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
@@ -200,8 +204,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = pdc2027x_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = pdc2027x_cable_detect,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -212,7 +216,6 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
 static struct ata_port_info pdc2027x_port_info[] = {
        /* PDC_UDMA_100 */
        {
-               .sht            = &pdc2027x_sht,
                .flags          = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
                                  ATA_FLAG_MMIO,
                .pio_mask       = 0x1f, /* pio0-4 */
@@ -222,7 +225,6 @@ static struct ata_port_info pdc2027x_port_info[] = {
        },
        /* PDC_UDMA_133 */
        {
-               .sht            = &pdc2027x_sht,
                .flags          = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
                                  ATA_FLAG_MMIO,
                .pio_mask       = 0x1f, /* pio0-4 */
@@ -261,7 +263,7 @@ static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *ade
 }
 
 /**
- *     pdc2027x_pata_cbl_detect - Probe host controller cable detect info
+ *     pdc2027x_pata_cable_detect - Probe host controller cable detect info
  *     @ap: Port for which cable detect info is desired
  *
  *     Read 80c cable indicator from Promise extended register.
@@ -270,7 +272,7 @@ static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *ade
  *     LOCKING:
  *     None (inherited from caller).
  */
-static void pdc2027x_cbl_detect(struct ata_port *ap)
+static int pdc2027x_cable_detect(struct ata_port *ap)
 {
        u32 cgcr;
 
@@ -281,13 +283,10 @@ static void pdc2027x_cbl_detect(struct ata_port *ap)
 
        PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no);
 
-       ap->cbl = ATA_CBL_PATA80;
-       return;
-
+       return ATA_CBL_PATA80;
 cbl40:
        printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no);
-       ap->cbl = ATA_CBL_PATA40;
-       ap->udma_mask &= ATA_UDMA_MASK_40C;
+       return ATA_CBL_PATA40;
 }
 
 /**
@@ -314,7 +313,6 @@ static int pdc2027x_prereset(struct ata_port *ap)
        /* Check whether port enabled */
        if (!pdc2027x_port_enabled(ap))
                return -ENOENT;
-       pdc2027x_cbl_detect(ap);
        return ata_std_prereset(ap);
 }
 
@@ -333,6 +331,32 @@ static void pdc2027x_error_handler(struct ata_port *ap)
        ata_bmdma_drive_eh(ap, pdc2027x_prereset, ata_std_softreset, NULL, ata_std_postreset);
 }
 
+/**
+ *     pdc2720x_mode_filter    -       mode selection filter
+ *     @adev: ATA device
+ *     @mask: list of modes proposed
+ *
+ *     Block UDMA on devices that cause trouble with this controller.
+ */
+
+static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+       unsigned char model_num[ATA_ID_PROD_LEN + 1];
+       struct ata_device *pair = ata_dev_pair(adev);
+
+       if (adev->class != ATA_DEV_ATA || adev->devno == 0 || pair == NULL)
+               return ata_pci_default_filter(adev, mask);
+
+       /* Check for slave of a Maxtor at UDMA6 */
+       ata_id_c_string(pair->id, model_num, ATA_ID_PROD,
+                         ATA_ID_PROD_LEN + 1);
+       /* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */
+       if(strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6)
+               mask &= ~ (1 << (6 + ATA_SHIFT_UDMA));
+
+       return ata_pci_default_filter(adev, mask);
+}
+
 /**
  *     pdc2027x_set_piomode - Initialize host controller PATA PIO timings
  *     @ap: Port to configure
@@ -444,17 +468,22 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 }
 
 /**
- *     pdc2027x_post_set_mode - Set the timing registers back to correct values.
+ *     pdc2027x_set_mode - Set the timing registers back to correct values.
  *     @ap: Port to configure
+ *     @r_failed: Returned device for failure
  *
  *     The pdc2027x hardware will look at "SET FEATURES" and change the timing registers
  *     automatically. The values set by the hardware might be incorrect, under 133Mhz PLL.
  *     This function overwrites the possibly incorrect values set by the hardware to be correct.
  */
-static void pdc2027x_post_set_mode(struct ata_port *ap)
+static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
 {
        int i;
 
+       i = ata_do_set_mode(ap, r_failed);
+       if (i < 0)
+               return i;
+
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                struct ata_device *dev = &ap->device[i];
 
@@ -476,6 +505,7 @@ static void pdc2027x_post_set_mode(struct ata_port *ap)
                        }
                }
        }
+       return 0;
 }
 
 /**
@@ -521,12 +551,12 @@ static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc)
 
 /**
  * pdc_read_counter - Read the ctr counter
- * @probe_ent: for the port address
+ * @host: target ATA host
  */
 
-static long pdc_read_counter(struct ata_probe_ent *probe_ent)
+static long pdc_read_counter(struct ata_host *host)
 {
-       void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+       void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
        long counter;
        int retry = 1;
        u32 bccrl, bccrh, bccrlv, bccrhv;
@@ -564,12 +594,12 @@ retry:
  * adjust_pll - Adjust the PLL input clock in Hz.
  *
  * @pdc_controller: controller specific information
- * @probe_ent: For the port address
+ * @host: target ATA host
  * @pll_clock: The input of PLL in HZ
  */
-static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx)
+static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int board_idx)
 {
-       void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+       void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
        u16 pll_ctl;
        long pll_clock_khz = pll_clock / 1000;
        long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ;
@@ -649,19 +679,19 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi
 
 /**
  * detect_pll_input_clock - Detect the PLL input clock in Hz.
- * @probe_ent: for the port address
+ * @host: target ATA host
  * Ex. 16949000 on 33MHz PCI bus for pdc20275.
  *     Half of the PCI clock.
  */
-static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
+static long pdc_detect_pll_input_clock(struct ata_host *host)
 {
-       void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+       void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
        u32 scr;
        long start_count, end_count;
        long pll_clock;
 
        /* Read current counter value */
-       start_count = pdc_read_counter(probe_ent);
+       start_count = pdc_read_counter(host);
 
        /* Start the test mode */
        scr = readl(mmio_base + PDC_SYS_CTL);
@@ -673,7 +703,7 @@ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
        mdelay(100);
 
        /* Read the counter values again */
-       end_count = pdc_read_counter(probe_ent);
+       end_count = pdc_read_counter(host);
 
        /* Stop the test mode */
        scr = readl(mmio_base + PDC_SYS_CTL);
@@ -692,11 +722,10 @@ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
 
 /**
  * pdc_hardware_init - Initialize the hardware.
- * @pdev: instance of pci_dev found
- * @pdc_controller: controller specific information
- * @pe:  for the port address
+ * @host: target ATA host
+ * @board_idx: board identifier
  */
-static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, unsigned int board_idx)
+static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
 {
        long pll_clock;
 
@@ -706,15 +735,15 @@ static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, uns
         * Ex. 25MHz or 40MHz, we have to adjust the cycle_time.
         * The pdc20275 controller employs PLL circuit to help correct timing registers setting.
         */
-       pll_clock = pdc_detect_pll_input_clock(pe);
+       pll_clock = pdc_detect_pll_input_clock(host);
 
        if (pll_clock < 0) /* counter overflow? Try again. */
-               pll_clock = pdc_detect_pll_input_clock(pe);
+               pll_clock = pdc_detect_pll_input_clock(host);
 
-       dev_printk(KERN_INFO, &pdev->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
+       dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
 
        /* Adjust PLL control register */
-       pdc_adjust_pll(pe, pll_clock, board_idx);
+       pdc_adjust_pll(host, pll_clock, board_idx);
 
        return 0;
 }
@@ -746,8 +775,7 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
  * Called when an instance of PCI adapter is inserted.
  * This function checks whether the hardware is supported,
  * initialize hardware and register an instance of ata_host to
- * libata by providing struct ata_probe_ent and ata_device_add().
- * (implements struct pci_driver.probe() )
+ * libata.  (implements struct pci_driver.probe() )
  *
  * @pdev: instance of pci_dev found
  * @ent:  matching entry in the id_tbl[]
@@ -756,14 +784,21 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
 {
        static int printed_version;
        unsigned int board_idx = (unsigned int) ent->driver_data;
-
-       struct ata_probe_ent *probe_ent;
+       const struct ata_port_info *ppi[] =
+               { &pdc2027x_port_info[board_idx], NULL };
+       struct ata_host *host;
        void __iomem *mmio_base;
        int rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* alloc host */
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+       if (!host)
+               return -ENOMEM;
+
+       /* acquire resources and fill host */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -771,6 +806,7 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
        rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);
        if (rc)
                return rc;
+       host->iomap = pcim_iomap_table(pdev);
 
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
@@ -780,46 +816,22 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
        if (rc)
                return rc;
 
-       /* Prepare the probe entry */
-       probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
-               return -ENOMEM;
-
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
-
-       probe_ent->sht          = pdc2027x_port_info[board_idx].sht;
-       probe_ent->port_flags   = pdc2027x_port_info[board_idx].flags;
-       probe_ent->pio_mask     = pdc2027x_port_info[board_idx].pio_mask;
-       probe_ent->mwdma_mask   = pdc2027x_port_info[board_idx].mwdma_mask;
-       probe_ent->udma_mask    = pdc2027x_port_info[board_idx].udma_mask;
-       probe_ent->port_ops     = pdc2027x_port_info[board_idx].port_ops;
+       mmio_base = host->iomap[PDC_MMIO_BAR];
 
-               probe_ent->irq = pdev->irq;
-               probe_ent->irq_flags = IRQF_SHARED;
-       probe_ent->iomap = pcim_iomap_table(pdev);
+       pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0);
+       host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000;
+       pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0);
+       host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008;
 
-       mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
-
-       pdc_ata_setup_port(&probe_ent->port[0], mmio_base + 0x17c0);
-       probe_ent->port[0].bmdma_addr = mmio_base + 0x1000;
-       pdc_ata_setup_port(&probe_ent->port[1], mmio_base + 0x15c0);
-       probe_ent->port[1].bmdma_addr = mmio_base + 0x1008;
-
-       probe_ent->n_ports = 2;
-
-       pci_set_master(pdev);
        //pci_enable_intx(pdev);
 
        /* initialize adapter */
-       if (pdc_hardware_init(pdev, probe_ent, board_idx) != 0)
+       if (pdc_hardware_init(host, board_idx) != 0)
                return -EIO;
 
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
+       pci_set_master(pdev);
+       return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+                                &pdc2027x_sht);
 }
 
 /**
index 0a149339891395d6264f7c3f1b01be7dde85cb84..ee636beb05e132f7da4ca127d569702c5eb4d6fc 100644 (file)
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_pdc202xx_old"
-#define DRV_VERSION "0.4.0"
+#define DRV_VERSION "0.4.2"
 
-/**
- *     pdc2024x_pre_reset              -       probe begin
- *     @ap: ATA port
- *
- *     Set up cable type and use generic probe init
- */
-
-static int pdc2024x_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA40;
-       return ata_std_prereset(ap);
-}
-
-
-static void pdc2024x_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, pdc2024x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-
-static int pdc2026x_pre_reset(struct ata_port *ap)
+static int pdc2026x_cable_detect(struct ata_port *ap)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u16 cis;
 
        pci_read_config_word(pdev, 0x50, &cis);
        if (cis & (1 << (10 + ap->port_no)))
-               ap->cbl = ATA_CBL_PATA80;
-       else
-               ap->cbl = ATA_CBL_PATA40;
-
-       return ata_std_prereset(ap);
-}
-
-static void pdc2026x_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, pdc2026x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+               return ATA_CBL_PATA80;
+       return ATA_CBL_PATA40;
 }
 
 /**
@@ -244,7 +216,6 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
 
 /**
  *     pdc2026x_dev_config     -       device setup hook
- *     @ap: ATA port
  *     @adev: newly found device
  *
  *     Perform chip specific early setup. We need to lock the transfer
@@ -252,7 +223,7 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
  *     barf.
  */
 
-static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev)
+static void pdc2026x_dev_config(struct ata_device *adev)
 {
        adev->max_sectors = 256;
 }
@@ -292,8 +263,9 @@ static struct ata_port_operations pdc2024x_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = pdc2024x_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -326,8 +298,9 @@ static struct ata_port_operations pdc2026x_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = pdc2026x_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = pdc2026x_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = pdc2026x_bmdma_start,
index 4b82a5435a4ebfc1f558afa89bf088bb9d4dc565..a0a650c7f272042ae71458259fc1566aa66e91a9 100644 (file)
@@ -80,13 +80,13 @@ static struct ata_port_operations pata_platform_port_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_unknown,
 
        .qc_prep                = ata_qc_prep,
        .qc_issue               = ata_qc_issue_prot,
 
        .data_xfer              = ata_data_xfer_noirq,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -135,7 +135,8 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
 static int __devinit pata_platform_probe(struct platform_device *pdev)
 {
        struct resource *io_res, *ctl_res;
-       struct ata_probe_ent ae;
+       struct ata_host *host;
+       struct ata_port *ap;
        unsigned int mmio;
 
        /*
@@ -175,44 +176,41 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
        /*
         * Now that that's out of the way, wire up the port..
         */
-       memset(&ae, 0, sizeof(struct ata_probe_ent));
-       INIT_LIST_HEAD(&ae.node);
-       ae.dev = &pdev->dev;
-       ae.port_ops = &pata_platform_port_ops;
-       ae.sht = &pata_platform_sht;
-       ae.n_ports = 1;
-       ae.pio_mask = pio_mask;
-       ae.irq = platform_get_irq(pdev, 0);
-       ae.irq_flags = 0;
-       ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+       host = ata_host_alloc(&pdev->dev, 1);
+       if (!host)
+               return -ENOMEM;
+       ap = host->ports[0];
+
+       ap->ops = &pata_platform_port_ops;
+       ap->pio_mask = pio_mask;
+       ap->flags |= ATA_FLAG_SLAVE_POSS;
 
        /*
         * Handle the MMIO case
         */
        if (mmio) {
-               ae.port[0].cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
+               ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
                                io_res->end - io_res->start + 1);
-               ae.port[0].ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
+               ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
                                ctl_res->end - ctl_res->start + 1);
        } else {
-               ae.port[0].cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
+               ap->ioaddr.cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
                                io_res->end - io_res->start + 1);
-               ae.port[0].ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
+               ap->ioaddr.ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
                                ctl_res->end - ctl_res->start + 1);
        }
-       if (!ae.port[0].cmd_addr || !ae.port[0].ctl_addr) {
+       if (!ap->ioaddr.cmd_addr || !ap->ioaddr.ctl_addr) {
                dev_err(&pdev->dev, "failed to map IO/CTL base\n");
                return -ENOMEM;
        }
 
-       ae.port[0].altstatus_addr = ae.port[0].ctl_addr;
+       ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
 
-       pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data);
+       pata_platform_setup_port(&ap->ioaddr, pdev->dev.platform_data);
 
-       if (unlikely(ata_device_add(&ae) == 0))
-               return -ENODEV;
-
-       return 0;
+       /* activate */
+       return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
+                                0, &pata_platform_sht);
 }
 
 /**
index c3810012f3f4af7d873ecd120fda194974528dae..27685ce63ceb27a92f8780c6c1c6aca48aa5745d 100644 (file)
@@ -183,13 +183,13 @@ static struct ata_port_operations qdi6500_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = qdi_qc_issue_prot,
 
        .data_xfer      = qdi_data_xfer,
 
-       .irq_handler    = ata_interrupt,
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
        .irq_ack        = ata_irq_ack,
@@ -211,13 +211,13 @@ static struct ata_port_operations qdi6580_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = qdi_qc_issue_prot,
 
        .data_xfer      = qdi_data_xfer,
 
-       .irq_handler    = ata_interrupt,
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
        .irq_ack        = ata_irq_ack,
@@ -238,8 +238,9 @@ static struct ata_port_operations qdi6580_port_ops = {
 
 static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
 {
-       struct ata_probe_ent ae;
        struct platform_device *pdev;
+       struct ata_host *host;
+       struct ata_port *ap;
        void __iomem *io_addr, *ctl_addr;
        int ret;
 
@@ -257,34 +258,31 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
        if (!io_addr || !ctl_addr)
                goto fail;
 
-       memset(&ae, 0, sizeof(struct ata_probe_ent));
-       INIT_LIST_HEAD(&ae.node);
-       ae.dev = &pdev->dev;
+       ret = -ENOMEM;
+       host = ata_host_alloc(&pdev->dev, 1);
+       if (!host)
+               goto fail;
+       ap = host->ports[0];
 
        if (type == 6580) {
-               ae.port_ops = &qdi6580_port_ops;
-               ae.pio_mask = 0x1F;
-               ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+               ap->ops = &qdi6580_port_ops;
+               ap->pio_mask = 0x1F;
+               ap->flags |= ATA_FLAG_SLAVE_POSS;
        } else {
-               ae.port_ops = &qdi6500_port_ops;
-               ae.pio_mask = 0x07;     /* Actually PIO3 !IORDY is possible */
-               ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
-                               ATA_FLAG_NO_IORDY;
+               ap->ops = &qdi6500_port_ops;
+               ap->pio_mask = 0x07;    /* Actually PIO3 !IORDY is possible */
+               ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
        }
 
-       ae.sht = &qdi_sht;
-       ae.n_ports = 1;
-       ae.irq = irq;
-       ae.irq_flags = 0;
-       ae.port[0].cmd_addr = io_addr;
-       ae.port[0].altstatus_addr = ctl_addr;
-       ae.port[0].ctl_addr = ctl_addr;
-       ata_std_ports(&ae.port[0]);
+       ap->ioaddr.cmd_addr = io_addr;
+       ap->ioaddr.altstatus_addr = ctl_addr;
+       ap->ioaddr.ctl_addr = ctl_addr;
+       ata_std_ports(&ap->ioaddr);
 
        /*
         *      Hook in a private data structure per channel
         */
-       ae.private_data = &qdi_data[nr_qdi_host];
+       ap->private_data = &qdi_data[nr_qdi_host];
 
        qdi_data[nr_qdi_host].timing = port;
        qdi_data[nr_qdi_host].fast = fast;
@@ -292,8 +290,9 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
 
        printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io);
 
-       ret = -ENODEV;
-       if (!ata_device_add(&ae))
+       /* activate */
+       ret = ata_host_activate(host, irq, ata_interrupt, 0, &qdi_sht);
+       if (ret)
                goto fail;
 
        qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
index 9a9132c9e3317a034ab0f402cc45ae1f6289ac39..1c54673e008d0a0d2f5e7c3f821ac260d162522d 100644 (file)
 #include <linux/ata.h>
 
 #define DRV_NAME       "pata_radisys"
-#define DRV_VERSION    "0.4.1"
-
-/**
- *     radisys_probe_init              -       probe begin
- *     @ap: ATA port
- *
- *     Set up cable type and use generic probe init
- */
-
-static int radisys_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA80;
-       return ata_std_prereset(ap);
-}
-
-
-/**
- *     radisys_pata_error_handler - Probe specified port on PATA host controller
- *     @ap: Port to probe
- *     @classes:
- *
- *     LOCKING:
- *     None (inherited from caller).
- */
-
-static void radisys_pata_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, radisys_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
+#define DRV_VERSION    "0.4.4"
 
 /**
  *     radisys_set_piomode - Initialize host controller PATA PIO timings
- *     @ap: Port whose timings we are configuring
- *     @adev: um
+ *     @ap: ATA port
+ *     @adev: Device whose timings we are configuring
  *
  *     Set PIO mode for device, in host controller PCI config space.
  *
@@ -248,8 +220,9 @@ static const struct ata_port_operations radisys_pata_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = radisys_pata_error_handler,
+       .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_unknown,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
index f522daa2a6aa3c274befa168bca47fd2cd620643..85c45290eeee9972c1c59b27737d43f03a6b9b5b 100644 (file)
 #define DRV_VERSION    "0.2.3"
 
 
-/**
- *     rz1000_prereset         -       probe begin
- *     @ap: ATA port
- *
- *     Set up cable type and use generics
- */
-
-static int rz1000_prereset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_PATA40;
-       return ata_std_prereset(ap);
-}
-
-/**
- *     rz1000_error_handler            -       probe reset
- *     @ap: ATA port
- *
- *     Perform the ATA standard reset sequence
- */
-
-static void rz1000_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, rz1000_prereset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
 /**
  *     rz1000_set_mode         -       mode setting function
  *     @ap: ATA interface
@@ -122,8 +97,9 @@ static struct ata_port_operations rz1000_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = rz1000_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .irq_handler    = ata_interrupt,
        .irq_clear      = ata_bmdma_irq_clear,
index 93b3ed0f9e8ac9a448102073535e51f04cdceacb..66e8ff467c8d1b7771ce282627070dc0a2e4d05f 100644 (file)
@@ -216,6 +216,7 @@ static struct ata_port_operations sc1200_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index f3ed141fdc0ea59554473ea2030bdb5fd9160f1d..5df354d573e8183c5174b8049bbf69b9860b7fb8 100644 (file)
@@ -1016,7 +1016,6 @@ static const struct ata_port_operations scc_pata_ops = {
        .error_handler          = scc_error_handler,
        .post_internal_cmd      = scc_bmdma_stop,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = scc_bmdma_irq_clear,
        .irq_on                 = scc_irq_on,
        .irq_ack                = scc_irq_ack,
@@ -1027,7 +1026,6 @@ static const struct ata_port_operations scc_pata_ops = {
 
 static struct ata_port_info scc_port_info[] = {
        {
-               .sht            = &scc_sht,
                .flags          = ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x00,
@@ -1040,10 +1038,10 @@ static struct ata_port_info scc_port_info[] = {
  *     scc_reset_controller - initialize SCC PATA controller.
  */
 
-static int scc_reset_controller(struct ata_probe_ent *probe_ent)
+static int scc_reset_controller(struct ata_host *host)
 {
-       void __iomem *ctrl_base = probe_ent->iomap[SCC_CTRL_BAR];
-       void __iomem *bmid_base = probe_ent->iomap[SCC_BMID_BAR];
+       void __iomem *ctrl_base = host->iomap[SCC_CTRL_BAR];
+       void __iomem *bmid_base = host->iomap[SCC_BMID_BAR];
        void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
        void __iomem *mode_port = ctrl_base + SCC_CTL_MODEREG;
        void __iomem *ecmode_port = ctrl_base + SCC_CTL_ECMODE;
@@ -1104,17 +1102,15 @@ static void scc_setup_ports (struct ata_ioports *ioaddr, void __iomem *base)
        ioaddr->command_addr = ioaddr->cmd_addr + SCC_REG_CMD;
 }
 
-static int scc_host_init(struct ata_probe_ent *probe_ent)
+static int scc_host_init(struct ata_host *host)
 {
-       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+       struct pci_dev *pdev = to_pci_dev(host->dev);
        int rc;
 
-       rc = scc_reset_controller(probe_ent);
+       rc = scc_reset_controller(host);
        if (rc)
                return rc;
 
-       probe_ent->n_ports = 1;
-
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
                return rc;
@@ -1122,7 +1118,7 @@ static int scc_host_init(struct ata_probe_ent *probe_ent)
        if (rc)
                return rc;
 
-       scc_setup_ports(&probe_ent->port[0], probe_ent->iomap[SCC_BMID_BAR]);
+       scc_setup_ports(&host->ports[0]->ioaddr, host->iomap[SCC_BMID_BAR]);
 
        pci_set_master(pdev);
 
@@ -1145,14 +1141,18 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
        unsigned int board_idx = (unsigned int) ent->driver_data;
+       const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL };
        struct device *dev = &pdev->dev;
-       struct ata_probe_ent *probe_ent;
        int rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
+       host = ata_port_alloc_pinfo(&pdev->dev, ppi, 1);
+       if (!host)
+               return -ENOMEM;
+
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -1162,33 +1162,14 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                pcim_pin_device(pdev);
        if (rc)
                return rc;
+       host->iomap = pcim_iomap_table(pdev);
 
-       probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (!probe_ent)
-               return -ENOMEM;
-
-       probe_ent->dev = dev;
-       INIT_LIST_HEAD(&probe_ent->node);
-
-       probe_ent->sht          = scc_port_info[board_idx].sht;
-       probe_ent->port_flags   = scc_port_info[board_idx].flags;
-       probe_ent->pio_mask     = scc_port_info[board_idx].pio_mask;
-       probe_ent->udma_mask    = scc_port_info[board_idx].udma_mask;
-       probe_ent->port_ops     = scc_port_info[board_idx].port_ops;
-
-       probe_ent->irq = pdev->irq;
-       probe_ent->irq_flags = IRQF_SHARED;
-       probe_ent->iomap = pcim_iomap_table(pdev);
-
-       rc = scc_host_init(probe_ent);
+       rc = scc_host_init(host);
        if (rc)
                return rc;
 
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(dev, probe_ent);
-       return 0;
+       return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+                                &scc_sht);
 }
 
 static struct pci_driver scc_pci_driver = {
index 598eef810a74ab605001bb48e1191d42b7a99e4a..3956ef26936d3005d601f9ad231effb3be89b83a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * ata-serverworks.c   - Serverworks PATA for new ATA layer
+ * pata_serverworks.c  - Serverworks PATA for new ATA layer
  *                       (C) 2005 Red Hat Inc
  *                       Alan Cox <alan@redhat.com>
  *
@@ -137,14 +137,14 @@ static struct sv_cable_table cable_detect[] = {
 };
 
 /**
- *     serverworks_pre_reset           -       cable detection
+ *     serverworks_cable_detect        -       cable detection
  *     @ap: ATA port
  *
  *     Perform cable detection according to the device and subvendor
  *     identifications
  */
 
-static int serverworks_pre_reset(struct ata_port *ap) {
+static int serverworks_cable_detect(struct ata_port *ap) {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        struct sv_cable_table *cb = cable_detect;
 
@@ -152,8 +152,7 @@ static int serverworks_pre_reset(struct ata_port *ap) {
                if (cb->device == pdev->device &&
                    (cb->subvendor == pdev->subsystem_vendor ||
                      cb->subvendor == PCI_ANY_ID)) {
-                       ap->cbl = cb->cable_detect(ap);
-                       return ata_std_prereset(ap);
+                       return cb->cable_detect(ap);
                }
                cb++;
        }
@@ -162,11 +161,6 @@ static int serverworks_pre_reset(struct ata_port *ap) {
        return -1;      /* kill compiler warning */
 }
 
-static void serverworks_error_handler(struct ata_port *ap)
-{
-       return ata_bmdma_drive_eh(ap, serverworks_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
 /**
  *     serverworks_is_csb      -       Check for CSB or OSB
  *     @pdev: PCI device to check
@@ -191,31 +185,31 @@ static u8 serverworks_is_csb(struct pci_dev *pdev)
 
 /**
  *     serverworks_osb4_filter -       mode selection filter
- *     @ap: ATA interface
  *     @adev: ATA device
+ *     @mask: Mask of proposed modes
  *
  *     Filter the offered modes for the device to apply controller
  *     specific rules. OSB4 requires no UDMA for disks due to a FIFO
  *     bug we hit.
  */
 
-static unsigned long serverworks_osb4_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long serverworks_osb4_filter(struct ata_device *adev, unsigned long mask)
 {
        if (adev->class == ATA_DEV_ATA)
                mask &= ~ATA_MASK_UDMA;
-       return ata_pci_default_filter(ap, adev, mask);
+       return ata_pci_default_filter(adev, mask);
 }
 
 
 /**
  *     serverworks_csb_filter  -       mode selection filter
- *     @ap: ATA interface
  *     @adev: ATA device
+ *     @mask: Mask of proposed modes
  *
  *     Check the blacklist and disable UDMA5 if matched
  */
 
-static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned long mask)
 {
        const char *p;
        char model_num[ATA_ID_PROD_LEN + 1];
@@ -223,7 +217,7 @@ static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct at
 
        /* Disk, UDMA */
        if (adev->class != ATA_DEV_ATA)
-               return ata_pci_default_filter(ap, adev, mask);
+               return ata_pci_default_filter(adev, mask);
 
        /* Actually do need to check */
        ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
@@ -232,7 +226,7 @@ static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct at
                if (!strcmp(p, model_num))
                        mask &= ~(0x1F << ATA_SHIFT_UDMA);
        }
-       return ata_pci_default_filter(ap, adev, mask);
+       return ata_pci_default_filter(adev, mask);
 }
 
 
@@ -339,8 +333,9 @@ static struct ata_port_operations serverworks_osb4_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = serverworks_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = serverworks_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -374,8 +369,9 @@ static struct ata_port_operations serverworks_csb_port_ops = {
 
        .freeze         = ata_bmdma_freeze,
        .thaw           = ata_bmdma_thaw,
-       .error_handler  = serverworks_error_handler,
+       .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = serverworks_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index dab2889a556f4ab28305bfaf985f7cf7107c5f6a..6770820cfca9c74c08f8e7e9eb8759429be6b624 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_sil680"
-#define DRV_VERSION "0.4.5"
+#define DRV_VERSION "0.4.6"
 
 /**
  *     sil680_selreg           -       return register base
@@ -91,12 +91,6 @@ static int sil680_cable_detect(struct ata_port *ap) {
                return ATA_CBL_PATA40;
 }
 
-static int sil680_pre_reset(struct ata_port *ap)
-{
-       ap->cbl = sil680_cable_detect(ap);
-       return ata_std_prereset(ap);
-}
-
 /**
  *     sil680_bus_reset        -       reset the SIL680 bus
  *     @ap: ATA port to reset
@@ -119,7 +113,7 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes)
 
 static void sil680_error_handler(struct ata_port *ap)
 {
-       ata_bmdma_drive_eh(ap, sil680_pre_reset, sil680_bus_reset, NULL, ata_std_postreset);
+       ata_bmdma_drive_eh(ap, ata_std_prereset, sil680_bus_reset, NULL, ata_std_postreset);
 }
 
 /**
@@ -257,6 +251,7 @@ static struct ata_port_operations sil680_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = sil680_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = sil680_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index 8dc3bc4f5863dc33ea1832083ef3a6325d896b1f..a3fbcee6fb330185ebf97ba10ecf9cb711862530 100644 (file)
@@ -35,7 +35,7 @@
 #include "sis.h"
 
 #define DRV_NAME       "pata_sis"
-#define DRV_VERSION    "0.5.0"
+#define DRV_VERSION    "0.5.1"
 
 struct sis_chipset {
        u16 device;                     /* PCI host ID */
@@ -86,106 +86,55 @@ static int sis_port_base(struct ata_device *adev)
 }
 
 /**
- *     sis_133_pre_reset       -       check for 40/80 pin
+ *     sis_133_cable_detect    -       check for 40/80 pin
  *     @ap: Port
  *
  *     Perform cable detection for the later UDMA133 capable
  *     SiS chipset.
  */
 
-static int sis_133_pre_reset(struct ata_port *ap)
+static int sis_133_cable_detect(struct ata_port *ap)
 {
-       static const struct pci_bits sis_enable_bits[] = {
-               { 0x4aU, 1U, 0x02UL, 0x02UL },  /* port 0 */
-               { 0x4aU, 1U, 0x04UL, 0x04UL },  /* port 1 */
-       };
-
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u16 tmp;
 
-       if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
-               return -ENOENT;
-
        /* The top bit of this register is the cable detect bit */
        pci_read_config_word(pdev, 0x50 + 2 * ap->port_no, &tmp);
        if ((tmp & 0x8000) && !sis_short_ata40(pdev))
-               ap->cbl = ATA_CBL_PATA40;
-       else
-               ap->cbl = ATA_CBL_PATA80;
-
-       return ata_std_prereset(ap);
+               return ATA_CBL_PATA40;
+       return ATA_CBL_PATA80;
 }
 
 /**
- *     sis_error_handler - Probe specified port on PATA host controller
- *     @ap: Port to probe
- *
- *     LOCKING:
- *     None (inherited from caller).
- */
-
-static void sis_133_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, sis_133_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-
-/**
- *     sis_66_pre_reset        -       check for 40/80 pin
+ *     sis_66_cable_detect     -       check for 40/80 pin
  *     @ap: Port
  *
  *     Perform cable detection on the UDMA66, UDMA100 and early UDMA133
  *     SiS IDE controllers.
  */
 
-static int sis_66_pre_reset(struct ata_port *ap)
+static int sis_66_cable_detect(struct ata_port *ap)
 {
-       static const struct pci_bits sis_enable_bits[] = {
-               { 0x4aU, 1U, 0x02UL, 0x02UL },  /* port 0 */
-               { 0x4aU, 1U, 0x04UL, 0x04UL },  /* port 1 */
-       };
-
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u8 tmp;
 
-       if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
-               ata_port_disable(ap);
-               ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
-               return 0;
-       }
        /* Older chips keep cable detect in bits 4/5 of reg 0x48 */
        pci_read_config_byte(pdev, 0x48, &tmp);
        tmp >>= ap->port_no;
        if ((tmp & 0x10) && !sis_short_ata40(pdev))
-               ap->cbl = ATA_CBL_PATA40;
-       else
-               ap->cbl = ATA_CBL_PATA80;
-
-       return ata_std_prereset(ap);
+               return ATA_CBL_PATA40;
+       return ATA_CBL_PATA80;
 }
 
-/**
- *     sis_66_error_handler - Probe specified port on PATA host controller
- *     @ap: Port to probe
- *     @classes:
- *
- *     LOCKING:
- *     None (inherited from caller).
- */
-
-static void sis_66_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, sis_66_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
 
 /**
- *     sis_old_pre_reset               -       probe begin
+ *     sis_pre_reset           -       probe begin
  *     @ap: ATA port
  *
  *     Set up cable type and use generic probe init
  */
 
-static int sis_old_pre_reset(struct ata_port *ap)
+static int sis_pre_reset(struct ata_port *ap)
 {
        static const struct pci_bits sis_enable_bits[] = {
                { 0x4aU, 1U, 0x02UL, 0x02UL },  /* port 0 */
@@ -194,27 +143,23 @@ static int sis_old_pre_reset(struct ata_port *ap)
 
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
-       if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
-               ata_port_disable(ap);
-               ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
-               return 0;
-       }
-       ap->cbl = ATA_CBL_PATA40;
+       if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
+               return -ENOENT;
        return ata_std_prereset(ap);
 }
 
 
 /**
- *     sis_old_error_handler - Probe specified port on PATA host controller
+ *     sis_error_handler - Probe specified port on PATA host controller
  *     @ap: Port to probe
  *
  *     LOCKING:
  *     None (inherited from caller).
  */
 
-static void sis_old_error_handler(struct ata_port *ap)
+static void sis_error_handler(struct ata_port *ap)
 {
-       ata_bmdma_drive_eh(ap, sis_old_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+       ata_bmdma_drive_eh(ap, sis_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
 }
 
 /**
@@ -494,7 +439,7 @@ static void sis_133_early_set_dmamode (struct ata_port *ap, struct ata_device *a
        int drive_pci = sis_port_base(adev);
        u16 timing;
 
-       const u16 udma_bits[]  = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
+       static const u16 udma_bits[]  = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
 
        pci_read_config_word(pdev, drive_pci, &timing);
 
@@ -531,8 +476,8 @@ static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev)
        u32 reg54;
 
        /* bits 4- cycle time 8 - cvs time */
-       const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 };
-       const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 };
+       static const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 };
+       static const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 };
 
        /* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */
        pci_read_config_dword(pdev, 0x54, &reg54);
@@ -595,8 +540,9 @@ static const struct ata_port_operations sis_133_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = sis_133_error_handler,
+       .error_handler          = sis_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = sis_133_cable_detect,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
@@ -628,8 +574,9 @@ static const struct ata_port_operations sis_133_early_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = sis_66_error_handler,
+       .error_handler          = sis_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = sis_66_cable_detect,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
@@ -661,9 +608,9 @@ static const struct ata_port_operations sis_100_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = sis_66_error_handler,
+       .error_handler          = sis_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-
+       .cable_detect           = sis_66_cable_detect,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
@@ -692,10 +639,11 @@ static const struct ata_port_operations sis_66_ops = {
        .check_status           = ata_check_status,
        .exec_command           = ata_exec_command,
        .dev_select             = ata_std_dev_select,
+       .cable_detect           = sis_66_cable_detect,
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = sis_66_error_handler,
+       .error_handler          = sis_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
 
        .bmdma_setup            = ata_bmdma_setup,
@@ -728,8 +676,9 @@ static const struct ata_port_operations sis_old_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = sis_old_error_handler,
+       .error_handler          = sis_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_40wire,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
index b681441cfcb96a96a17ed5492d6c985961427d07..da9e22b257532f10fb7e930117b379426b956fea 100644 (file)
@@ -58,7 +58,6 @@ static int sl82c105_pre_reset(struct ata_port *ap)
 
        if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
                return -ENOENT;
-       ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 }
 
@@ -238,6 +237,7 @@ static struct ata_port_operations sl82c105_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = sl82c105_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = sl82c105_bmdma_start,
index 71418f2a0cdb702408fde99a2203ddb1441106c9..e618ffd6e944b392ac35458ee5cd3dc7c73fc264 100644 (file)
@@ -43,7 +43,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_triflex"
-#define DRV_VERSION "0.2.7"
+#define DRV_VERSION "0.2.8"
 
 /**
  *     triflex_prereset                -       probe begin
@@ -63,7 +63,6 @@ static int triflex_prereset(struct ata_port *ap)
 
        if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
                return -ENOENT;
-       ap->cbl = ATA_CBL_PATA40;
        return ata_std_prereset(ap);
 }
 
@@ -214,6 +213,7 @@ static struct ata_port_operations triflex_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = triflex_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = triflex_bmdma_start,
index 946ade0e1f1b3e7a43a7a09ec5a2406afde85834..96b71791d2f48edc8109d606a7a7d76c074df51b 100644 (file)
@@ -62,7 +62,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_via"
-#define DRV_VERSION "0.2.1"
+#define DRV_VERSION "0.3.1"
 
 /*
  *     The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
@@ -135,16 +135,23 @@ static const struct via_isa_bridge {
  */
 
 static int via_cable_detect(struct ata_port *ap) {
+       const struct via_isa_bridge *config = ap->host->private_data;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u32 ata66;
 
+       /* Early chips are 40 wire */
+       if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
+               return ATA_CBL_PATA40;
+       /* UDMA 66 chips have only drive side logic */
+       else if((config->flags & VIA_UDMA) < VIA_UDMA_100)
+               return ATA_CBL_PATA_UNK;
+       /* UDMA 100 or later */
        pci_read_config_dword(pdev, 0x50, &ata66);
        /* Check both the drive cable reporting bits, we might not have
           two drives */
        if (ata66 & (0x10100000 >> (16 * ap->port_no)))
                return ATA_CBL_PATA80;
-       else
-               return ATA_CBL_PATA40;
+       return ATA_CBL_PATA40;
 }
 
 static int via_pre_reset(struct ata_port *ap)
@@ -156,22 +163,10 @@ static int via_pre_reset(struct ata_port *ap)
                        { 0x40, 1, 0x02, 0x02 },
                        { 0x40, 1, 0x01, 0x01 }
                };
-
                struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-
                if (!pci_test_config_bits(pdev, &via_enable_bits[ap->port_no]))
                        return -ENOENT;
        }
-
-       if ((config->flags & VIA_UDMA) >= VIA_UDMA_100)
-               ap->cbl = via_cable_detect(ap);
-       /* The UDMA66 series has no cable detect so do drive side detect */
-       else if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
-               ap->cbl = ATA_CBL_PATA40;
-       else
-               ap->cbl = ATA_CBL_PATA_UNK;
-
-
        return ata_std_prereset(ap);
 }
 
@@ -327,6 +322,7 @@ static struct ata_port_operations via_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = via_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = via_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -362,6 +358,7 @@ static struct ata_port_operations via_port_ops_noirq = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = via_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = via_cable_detect,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index 6c111035fc84da35b2ffa7e4bcf42fcb4951a960..cc4ad271afb58be4b21010216efd3146c8ddb9df 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
@@ -36,7 +35,7 @@ static int probe_winbond = 1;
 static int probe_winbond;
 #endif
 
-static spinlock_t winbond_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(winbond_lock);
 
 static void winbond_writecfg(unsigned long port, u8 reg, u8 val)
 {
@@ -152,13 +151,13 @@ static struct ata_port_operations winbond_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
 
        .data_xfer      = winbond_data_xfer,
 
-       .irq_handler    = ata_interrupt,
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
        .irq_ack        = ata_irq_ack,
@@ -179,11 +178,9 @@ static struct ata_port_operations winbond_port_ops = {
 
 static __init int winbond_init_one(unsigned long port)
 {
-       struct ata_probe_ent ae;
        struct platform_device *pdev;
-       int ret;
        u8 reg;
-       int i;
+       int i, rc;
 
        reg = winbond_readcfg(port, 0x81);
        reg |= 0x80;    /* jumpered mode off */
@@ -202,58 +199,56 @@ static __init int winbond_init_one(unsigned long port)
 
        for (i = 0; i < 2 ; i ++) {
                unsigned long cmd_port = 0x1F0 - (0x80 * i);
+               struct ata_host *host;
+               struct ata_port *ap;
                void __iomem *cmd_addr, *ctl_addr;
 
-               if (reg & (1 << i)) {
-                       /*
-                        *      Fill in a probe structure first of all
-                        */
-
-                       pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
-                       if (IS_ERR(pdev))
-                               return PTR_ERR(pdev);
-
-                       cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
-                       ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
-                       if (!cmd_addr || !ctl_addr) {
-                               platform_device_unregister(pdev);
-                               return -ENOMEM;
-                       }
-
-                       memset(&ae, 0, sizeof(struct ata_probe_ent));
-                       INIT_LIST_HEAD(&ae.node);
-                       ae.dev = &pdev->dev;
-
-                       ae.port_ops = &winbond_port_ops;
-                       ae.pio_mask = 0x1F;
-
-                       ae.sht = &winbond_sht;
-
-                       ae.n_ports = 1;
-                       ae.irq = 14 + i;
-                       ae.irq_flags = 0;
-                       ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
-                       ae.port[0].cmd_addr = cmd_addr;
-                       ae.port[0].altstatus_addr = ctl_addr;
-                       ae.port[0].ctl_addr = ctl_addr;
-                       ata_std_ports(&ae.port[0]);
-                       /*
-                        *      Hook in a private data structure per channel
-                        */
-                       ae.private_data = &winbond_data[nr_winbond_host];
-                       winbond_data[nr_winbond_host].config = port;
-                       winbond_data[nr_winbond_host].platform_dev = pdev;
-
-                       ret = ata_device_add(&ae);
-                       if (ret == 0) {
-                               platform_device_unregister(pdev);
-                               return -ENODEV;
-                       }
-                       winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev);
-               }
+               if (!(reg & (1 << i)))
+                       continue;
+
+               pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
+               if (IS_ERR(pdev))
+                       return PTR_ERR(pdev);
+
+               rc = -ENOMEM;
+               host = ata_host_alloc(&pdev->dev, 1);
+               if (!host)
+                       goto err_unregister;
+
+               rc = -ENOMEM;
+               cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
+               ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+               if (!cmd_addr || !ctl_addr)
+                       goto err_unregister;
+
+               ap = host->ports[0];
+               ap->ops = &winbond_port_ops;
+               ap->pio_mask = 0x1F;
+               ap->flags |= ATA_FLAG_SLAVE_POSS;
+               ap->ioaddr.cmd_addr = cmd_addr;
+               ap->ioaddr.altstatus_addr = ctl_addr;
+               ap->ioaddr.ctl_addr = ctl_addr;
+               ata_std_ports(&ap->ioaddr);
+
+               /* hook in a private data structure per channel */
+               host->private_data = &winbond_data[nr_winbond_host];
+               winbond_data[nr_winbond_host].config = port;
+               winbond_data[nr_winbond_host].platform_dev = pdev;
+
+               /* activate */
+               rc = ata_host_activate(host, 14 + i, ata_interrupt, 0,
+                                      &winbond_sht);
+               if (rc)
+                       goto err_unregister;
+
+               winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev);
        }
 
        return 0;
+
+ err_unregister:
+       platform_device_unregister(pdev);
+       return rc;
 }
 
 /**
index 5dd3ca8b5f29fb273303810d488c318d80ce7287..52b69530ab29d768b8d71cebc15e5a5fa2b61341 100644 (file)
@@ -52,9 +52,9 @@
 /* macro to calculate base address for ADMA regs */
 #define ADMA_REGS(base,port_no)                ((base) + 0x80 + ((port_no) * 0x20))
 
-/* macro to obtain addresses from ata_host */
-#define ADMA_HOST_REGS(host,port_no) \
-       ADMA_REGS((host)->iomap[ADMA_MMIO_BAR], port_no)
+/* macro to obtain addresses from ata_port */
+#define ADMA_PORT_REGS(ap) \
+       ADMA_REGS((ap)->host->iomap[ADMA_MMIO_BAR], ap->port_no)
 
 enum {
        ADMA_MMIO_BAR           = 4,
@@ -128,7 +128,6 @@ struct adma_port_priv {
 
 static int adma_ata_init_one (struct pci_dev *pdev,
                                const struct pci_device_id *ent);
-static irqreturn_t adma_intr (int irq, void *dev_instance);
 static int adma_port_start(struct ata_port *ap);
 static void adma_host_stop(struct ata_host *host);
 static void adma_port_stop(struct ata_port *ap);
@@ -172,7 +171,6 @@ static const struct ata_port_operations adma_ata_ops = {
        .qc_issue               = adma_qc_issue,
        .eng_timeout            = adma_eng_timeout,
        .data_xfer              = ata_data_xfer,
-       .irq_handler            = adma_intr,
        .irq_clear              = adma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -186,7 +184,6 @@ static const struct ata_port_operations adma_ata_ops = {
 static struct ata_port_info adma_port_info[] = {
        /* board_1841_idx */
        {
-               .sht            = &adma_ata_sht,
                .flags          = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
                                  ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
                                  ATA_FLAG_PIO_POLLING,
@@ -229,8 +226,10 @@ static void adma_irq_clear(struct ata_port *ap)
        /* nothing */
 }
 
-static void adma_reset_engine(void __iomem *chan)
+static void adma_reset_engine(struct ata_port *ap)
 {
+       void __iomem *chan = ADMA_PORT_REGS(ap);
+
        /* reset ADMA to idle state */
        writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
        udelay(2);
@@ -241,14 +240,14 @@ static void adma_reset_engine(void __iomem *chan)
 static void adma_reinit_engine(struct ata_port *ap)
 {
        struct adma_port_priv *pp = ap->private_data;
-       void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+       void __iomem *chan = ADMA_PORT_REGS(ap);
 
        /* mask/clear ATA interrupts */
        writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
        ata_check_status(ap);
 
        /* reset the ADMA engine */
-       adma_reset_engine(chan);
+       adma_reset_engine(ap);
 
        /* set in-FIFO threshold to 0x100 */
        writew(0x100, chan + ADMA_FIFO_IN);
@@ -268,7 +267,7 @@ static void adma_reinit_engine(struct ata_port *ap)
 
 static inline void adma_enter_reg_mode(struct ata_port *ap)
 {
-       void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+       void __iomem *chan = ADMA_PORT_REGS(ap);
 
        writew(aPIOMD4, chan + ADMA_CONTROL);
        readb(chan + ADMA_STATUS);      /* flush */
@@ -415,7 +414,7 @@ static void adma_qc_prep(struct ata_queued_cmd *qc)
 static inline void adma_packet_start(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+       void __iomem *chan = ADMA_PORT_REGS(ap);
 
        VPRINTK("ENTER, ap %p\n", ap);
 
@@ -453,7 +452,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host)
                struct ata_port *ap = host->ports[port_no];
                struct adma_port_priv *pp;
                struct ata_queued_cmd *qc;
-               void __iomem *chan = ADMA_HOST_REGS(host, port_no);
+               void __iomem *chan = ADMA_PORT_REGS(ap);
                u8 status = readb(chan + ADMA_STATUS);
 
                if (status == 0)
@@ -575,7 +574,7 @@ static int adma_port_start(struct ata_port *ap)
 
 static void adma_port_stop(struct ata_port *ap)
 {
-       adma_reset_engine(ADMA_HOST_REGS(ap->host, ap->port_no));
+       adma_reset_engine(ap);
 }
 
 static void adma_host_stop(struct ata_host *host)
@@ -583,21 +582,19 @@ static void adma_host_stop(struct ata_host *host)
        unsigned int port_no;
 
        for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
-               adma_reset_engine(ADMA_HOST_REGS(host, port_no));
+               adma_reset_engine(host->ports[port_no]);
 }
 
-static void adma_host_init(unsigned int chip_id,
-                               struct ata_probe_ent *probe_ent)
+static void adma_host_init(struct ata_host *host, unsigned int chip_id)
 {
        unsigned int port_no;
-       void __iomem *mmio_base = probe_ent->iomap[ADMA_MMIO_BAR];
 
        /* enable/lock aGO operation */
-       writeb(7, mmio_base + ADMA_MODE_LOCK);
+       writeb(7, host->iomap[ADMA_MMIO_BAR] + ADMA_MODE_LOCK);
 
        /* reset the ADMA logic */
        for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
-               adma_reset_engine(ADMA_REGS(mmio_base, port_no));
+               adma_reset_engine(host->ports[port_no]);
 }
 
 static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
@@ -623,14 +620,21 @@ static int adma_ata_init_one(struct pci_dev *pdev,
                             const struct pci_device_id *ent)
 {
        static int printed_version;
-       struct ata_probe_ent *probe_ent = NULL;
-       void __iomem *mmio_base;
        unsigned int board_idx = (unsigned int) ent->driver_data;
+       const struct ata_port_info *ppi[] = { &adma_port_info[board_idx], NULL };
+       struct ata_host *host;
+       void __iomem *mmio_base;
        int rc, port_no;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* alloc host */
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, ADMA_PORTS);
+       if (!host)
+               return -ENOMEM;
+
+       /* acquire resources and fill host */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -641,46 +645,23 @@ static int adma_ata_init_one(struct pci_dev *pdev,
        rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME);
        if (rc)
                return rc;
-       mmio_base = pcim_iomap_table(pdev)[ADMA_MMIO_BAR];
+       host->iomap = pcim_iomap_table(pdev);
+       mmio_base = host->iomap[ADMA_MMIO_BAR];
 
        rc = adma_set_dma_masks(pdev, mmio_base);
        if (rc)
                return rc;
 
-       probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
-               return -ENOMEM;
-
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
-
-       probe_ent->sht          = adma_port_info[board_idx].sht;
-       probe_ent->port_flags   = adma_port_info[board_idx].flags;
-       probe_ent->pio_mask     = adma_port_info[board_idx].pio_mask;
-       probe_ent->mwdma_mask   = adma_port_info[board_idx].mwdma_mask;
-       probe_ent->udma_mask    = adma_port_info[board_idx].udma_mask;
-       probe_ent->port_ops     = adma_port_info[board_idx].port_ops;
-
-       probe_ent->irq          = pdev->irq;
-       probe_ent->irq_flags    = IRQF_SHARED;
-       probe_ent->n_ports      = ADMA_PORTS;
-       probe_ent->iomap        = pcim_iomap_table(pdev);
-
-       for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
-               adma_ata_setup_port(&probe_ent->port[port_no],
+       for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
+               adma_ata_setup_port(&host->ports[port_no]->ioaddr,
                                    ADMA_ATA_REGS(mmio_base, port_no));
-       }
-
-       pci_set_master(pdev);
 
        /* initialize adapter */
-       adma_host_init(board_idx, probe_ent);
+       adma_host_init(host, board_idx);
 
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
+       pci_set_master(pdev);
+       return ata_host_activate(host, pdev->irq, adma_intr, IRQF_SHARED,
+                                &adma_ata_sht);
 }
 
 static int __init adma_ata_init(void)
index 1e21688bfcf2f4992fd493de5299e5beb679b7c7..f099a1d83a000b7bb02dacc145259c59334c765e 100644 (file)
@@ -488,11 +488,11 @@ static void inic_error_handler(struct ata_port *ap)
 static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
 {
        /* make DMA engine forget about the failed command */
-       if (qc->err_mask)
+       if (qc->flags & ATA_QCFLAG_FAILED)
                inic_reset_port(inic_port_base(qc->ap));
 }
 
-static void inic_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void inic_dev_config(struct ata_device *dev)
 {
        /* inic can only handle upto LBA28 max sectors */
        if (dev->max_sectors > ATA_MAX_SECTORS)
@@ -559,7 +559,6 @@ static struct ata_port_operations inic_port_ops = {
        .bmdma_stop             = inic_bmdma_stop,
        .bmdma_status           = inic_bmdma_status,
 
-       .irq_handler            = inic_interrupt,
        .irq_clear              = inic_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -580,7 +579,6 @@ static struct ata_port_operations inic_port_ops = {
 };
 
 static struct ata_port_info inic_port_info = {
-       .sht                    = &inic_sht,
        /* For some reason, ATA_PROT_ATAPI is broken on this
         * controller, and no, PIO_POLLING does't fix it.  It somehow
         * manages to report the wrong ireason and ignoring ireason
@@ -642,7 +640,9 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
        void __iomem *mmio_base = host->iomap[MMIO_BAR];
        int rc;
 
-       ata_pci_device_do_resume(pdev);
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
 
        if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
                rc = init_controller(mmio_base, hpriv->cached_hctl);
@@ -659,8 +659,8 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
 static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
-       struct ata_port_info *pinfo = &inic_port_info;
-       struct ata_probe_ent *probe_ent;
+       const struct ata_port_info *ppi[] = { &inic_port_info, NULL };
+       struct ata_host *host;
        struct inic_host_priv *hpriv;
        void __iomem * const *iomap;
        int i, rc;
@@ -668,6 +668,15 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* alloc host */
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, NR_PORTS);
+       hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+       if (!host || !hpriv)
+               return -ENOMEM;
+
+       host->private_data = hpriv;
+
+       /* acquire resources and fill host */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -675,7 +684,22 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
        if (rc)
                return rc;
-       iomap = pcim_iomap_table(pdev);
+       host->iomap = iomap = pcim_iomap_table(pdev);
+
+       for (i = 0; i < NR_PORTS; i++) {
+               struct ata_ioports *port = &host->ports[i]->ioaddr;
+               void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
+
+               port->cmd_addr = iomap[2 * i];
+               port->altstatus_addr =
+               port->ctl_addr = (void __iomem *)
+                       ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
+               port->scr_addr = port_base + PORT_SCR;
+
+               ata_std_ports(port);
+       }
+
+       hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
 
        /* Set dma_mask.  This devices doesn't support 64bit addressing. */
        rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
@@ -692,43 +716,6 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                return rc;
        }
 
-       probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-       hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
-       if (!probe_ent || !hpriv)
-               return -ENOMEM;
-
-       probe_ent->dev = &pdev->dev;
-       INIT_LIST_HEAD(&probe_ent->node);
-
-       probe_ent->sht                  = pinfo->sht;
-       probe_ent->port_flags           = pinfo->flags;
-       probe_ent->pio_mask             = pinfo->pio_mask;
-       probe_ent->mwdma_mask           = pinfo->mwdma_mask;
-       probe_ent->udma_mask            = pinfo->udma_mask;
-       probe_ent->port_ops             = pinfo->port_ops;
-       probe_ent->n_ports              = NR_PORTS;
-
-       probe_ent->irq = pdev->irq;
-       probe_ent->irq_flags = IRQF_SHARED;
-
-       probe_ent->iomap = iomap;
-
-       for (i = 0; i < NR_PORTS; i++) {
-               struct ata_ioports *port = &probe_ent->port[i];
-               void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
-
-               port->cmd_addr = iomap[2 * i];
-               port->altstatus_addr =
-               port->ctl_addr = (void __iomem *)
-                       ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
-               port->scr_addr = port_base + PORT_SCR;
-
-               ata_std_ports(port);
-       }
-
-       probe_ent->private_data = hpriv;
-       hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
-
        rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
        if (rc) {
                dev_printk(KERN_ERR, &pdev->dev,
@@ -737,13 +724,8 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        pci_set_master(pdev);
-
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(&pdev->dev, probe_ent);
-
-       return 0;
+       return ata_host_activate(host, pdev->irq, inic_interrupt, IRQF_SHARED,
+                                &inic_sht);
 }
 
 static const struct pci_device_id inic_pci_tbl[] = {
index a65ba636aaa8eeb0ddb66b160f4a5749409c1106..cb9b9ac12b4c1cf3689757bafe9be68f46f59ab5 100644 (file)
@@ -253,10 +253,7 @@ enum {
 #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
 
 enum {
-       /* Our DMA boundary is determined by an ePRD being unable to handle
-        * anything larger than 64KB
-        */
-       MV_DMA_BOUNDARY         = 0xffffU,
+       MV_DMA_BOUNDARY         = 0xffffffffU,
 
        EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
 
@@ -350,7 +347,6 @@ static void mv_port_stop(struct ata_port *ap);
 static void mv_qc_prep(struct ata_queued_cmd *qc);
 static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
 static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t mv_interrupt(int irq, void *dev_instance);
 static void mv_eng_timeout(struct ata_port *ap);
 static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 
@@ -384,10 +380,10 @@ static struct scsi_host_template mv_sht = {
        .queuecommand           = ata_scsi_queuecmd,
        .can_queue              = MV_USE_Q_DEPTH,
        .this_id                = ATA_SHT_THIS_ID,
-       .sg_tablesize           = MV_MAX_SG_CT / 2,
+       .sg_tablesize           = MV_MAX_SG_CT,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
-       .use_clustering         = ATA_SHT_USE_CLUSTERING,
+       .use_clustering         = 1,
        .proc_name              = DRV_NAME,
        .dma_boundary           = MV_DMA_BOUNDARY,
        .slave_configure        = ata_scsi_slave_config,
@@ -405,6 +401,7 @@ static const struct ata_port_operations mv5_ops = {
        .dev_select             = ata_std_dev_select,
 
        .phy_reset              = mv_phy_reset,
+       .cable_detect           = ata_cable_sata,
 
        .qc_prep                = mv_qc_prep,
        .qc_issue               = mv_qc_issue,
@@ -412,7 +409,6 @@ static const struct ata_port_operations mv5_ops = {
 
        .eng_timeout            = mv_eng_timeout,
 
-       .irq_handler            = mv_interrupt,
        .irq_clear              = mv_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -434,6 +430,7 @@ static const struct ata_port_operations mv6_ops = {
        .dev_select             = ata_std_dev_select,
 
        .phy_reset              = mv_phy_reset,
+       .cable_detect           = ata_cable_sata,
 
        .qc_prep                = mv_qc_prep,
        .qc_issue               = mv_qc_issue,
@@ -441,7 +438,6 @@ static const struct ata_port_operations mv6_ops = {
 
        .eng_timeout            = mv_eng_timeout,
 
-       .irq_handler            = mv_interrupt,
        .irq_clear              = mv_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -463,6 +459,7 @@ static const struct ata_port_operations mv_iie_ops = {
        .dev_select             = ata_std_dev_select,
 
        .phy_reset              = mv_phy_reset,
+       .cable_detect           = ata_cable_sata,
 
        .qc_prep                = mv_qc_prep_iie,
        .qc_issue               = mv_qc_issue,
@@ -470,7 +467,6 @@ static const struct ata_port_operations mv_iie_ops = {
 
        .eng_timeout            = mv_eng_timeout,
 
-       .irq_handler            = mv_interrupt,
        .irq_clear              = mv_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -484,35 +480,30 @@ static const struct ata_port_operations mv_iie_ops = {
 
 static const struct ata_port_info mv_port_info[] = {
        {  /* chip_504x */
-               .sht            = &mv_sht,
                .flags          = MV_COMMON_FLAGS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 */
                .port_ops       = &mv5_ops,
        },
        {  /* chip_508x */
-               .sht            = &mv_sht,
                .flags          = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 */
                .port_ops       = &mv5_ops,
        },
        {  /* chip_5080 */
-               .sht            = &mv_sht,
                .flags          = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 */
                .port_ops       = &mv5_ops,
        },
        {  /* chip_604x */
-               .sht            = &mv_sht,
                .flags          = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 */
                .port_ops       = &mv6_ops,
        },
        {  /* chip_608x */
-               .sht            = &mv_sht,
                .flags          = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
                                   MV_FLAG_DUAL_HC),
                .pio_mask       = 0x1f, /* pio0-4 */
@@ -520,14 +511,12 @@ static const struct ata_port_info mv_port_info[] = {
                .port_ops       = &mv6_ops,
        },
        {  /* chip_6042 */
-               .sht            = &mv_sht,
                .flags          = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 */
                .port_ops       = &mv_iie_ops,
        },
        {  /* chip_7042 */
-               .sht            = &mv_sht,
                .flags          = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 */
@@ -551,6 +540,9 @@ static const struct pci_device_id mv_pci_tbl[] = {
 
        { PCI_VDEVICE(TTI, 0x2310), chip_7042 },
 
+       /* add Marvell 7042 support */
+       { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
+
        { }                     /* terminate list */
 };
 
@@ -585,6 +577,39 @@ static const struct mv_hw_ops mv6xxx_ops = {
 static int msi;              /* Use PCI msi; either zero (off, default) or non-zero */
 
 
+/* move to PCI layer or libata core? */
+static int pci_go_64(struct pci_dev *pdev)
+{
+       int rc;
+
+       if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+               rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+               if (rc) {
+                       rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+                       if (rc) {
+                               dev_printk(KERN_ERR, &pdev->dev,
+                                          "64-bit DMA enable failed\n");
+                               return rc;
+                       }
+               }
+       } else {
+               rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               if (rc) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit DMA enable failed\n");
+                       return rc;
+               }
+               rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+               if (rc) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit consistent DMA enable failed\n");
+                       return rc;
+               }
+       }
+
+       return rc;
+}
+
 /*
  * Functions
  */
@@ -798,20 +823,18 @@ static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
 {
        unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-       if (0xffffffffU != ofs) {
+       if (0xffffffffU != ofs)
                return readl(mv_ap_base(ap) + ofs);
-       } else {
+       else
                return (u32) ofs;
-       }
 }
 
 static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
        unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-       if (0xffffffffU != ofs) {
+       if (0xffffffffU != ofs)
                writelfl(val, mv_ap_base(ap) + ofs);
-       }
 }
 
 static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
@@ -959,38 +982,30 @@ static void mv_port_stop(struct ata_port *ap)
  *      LOCKING:
  *      Inherited from caller.
  */
-static void mv_fill_sg(struct ata_queued_cmd *qc)
+static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
 {
        struct mv_port_priv *pp = qc->ap->private_data;
-       unsigned int i = 0;
+       unsigned int n_sg = 0;
        struct scatterlist *sg;
+       struct mv_sg *mv_sg;
 
+       mv_sg = pp->sg_tbl;
        ata_for_each_sg(sg, qc) {
-               dma_addr_t addr;
-               u32 sg_len, len, offset;
-
-               addr = sg_dma_address(sg);
-               sg_len = sg_dma_len(sg);
-
-               while (sg_len) {
-                       offset = addr & MV_DMA_BOUNDARY;
-                       len = sg_len;
-                       if ((offset + sg_len) > 0x10000)
-                               len = 0x10000 - offset;
+               dma_addr_t addr = sg_dma_address(sg);
+               u32 sg_len = sg_dma_len(sg);
 
-                       pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff);
-                       pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
-                       pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff);
+               mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
+               mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
+               mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff);
 
-                       sg_len -= len;
-                       addr += len;
+               if (ata_sg_is_last(sg, qc))
+                       mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
 
-                       if (!sg_len && ata_sg_is_last(sg, qc))
-                               pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
-
-                       i++;
-               }
+               mv_sg++;
+               n_sg++;
        }
+
+       return n_sg;
 }
 
 static inline unsigned mv_inc_q_index(unsigned index)
@@ -1320,17 +1335,15 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
        int shift, port, port0, hard_port, handled;
        unsigned int err_mask;
 
-       if (hc == 0) {
+       if (hc == 0)
                port0 = 0;
-       } else {
+       else
                port0 = MV_PORTS_PER_HC;
-       }
 
        /* we'll need the HC success int register in most cases */
        hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
-       if (hc_irq_cause) {
+       if (hc_irq_cause)
                writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
-       }
 
        VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
                hc,relevant,hc_irq_cause);
@@ -1425,9 +1438,8 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
        /* check the cases where we either have nothing pending or have read
         * a bogus register value which can indicate HW removal or PCI fault
         */
-       if (!irq_stat || (0xffffffffU == irq_stat)) {
+       if (!irq_stat || (0xffffffffU == irq_stat))
                return IRQ_NONE;
-       }
 
        n_hcs = mv_get_hc_count(host->ports[0]->flags);
        spin_lock(&host->lock);
@@ -1952,7 +1964,6 @@ comreset_retry:
                ata_port_disable(ap);
                return;
        }
-       ap->cbl = ATA_CBL_SATA;
 
        /* even after SStatus reflects that device is ready,
         * it seems to take a while for link to be fully
@@ -2077,9 +2088,10 @@ static void mv_port_init(struct ata_ioports *port,  void __iomem *port_mmio)
                readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
 }
 
-static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
-                     unsigned int board_idx)
+static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
 {
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       struct mv_host_priv *hpriv = host->private_data;
        u8 rev_id;
        u32 hp_flags = hpriv->hp_flags;
 
@@ -2177,8 +2189,8 @@ static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
 
 /**
  *      mv_init_host - Perform some early initialization of the host.
- *     @pdev: host PCI device
- *      @probe_ent: early data struct representing the host
+ *     @host: ATA host to initialize
+ *      @board_idx: controller index
  *
  *      If possible, do an early global reset of the host.  Then do
  *      our port init and clear/unmask all/relevant host interrupts.
@@ -2186,24 +2198,23 @@ static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
-                       unsigned int board_idx)
+static int mv_init_host(struct ata_host *host, unsigned int board_idx)
 {
        int rc = 0, n_hc, port, hc;
-       void __iomem *mmio = probe_ent->iomap[MV_PRIMARY_BAR];
-       struct mv_host_priv *hpriv = probe_ent->private_data;
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = host->private_data;
 
        /* global interrupt mask */
        writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
 
-       rc = mv_chip_id(pdev, hpriv, board_idx);
+       rc = mv_chip_id(host, board_idx);
        if (rc)
                goto done;
 
-       n_hc = mv_get_hc_count(probe_ent->port_flags);
-       probe_ent->n_ports = MV_PORTS_PER_HC * n_hc;
+       n_hc = mv_get_hc_count(host->ports[0]->flags);
 
-       for (port = 0; port < probe_ent->n_ports; port++)
+       for (port = 0; port < host->n_ports; port++)
                hpriv->ops->read_preamp(hpriv, port, mmio);
 
        rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
@@ -2214,7 +2225,7 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
        hpriv->ops->reset_bus(pdev, mmio);
        hpriv->ops->enable_leds(hpriv, mmio);
 
-       for (port = 0; port < probe_ent->n_ports; port++) {
+       for (port = 0; port < host->n_ports; port++) {
                if (IS_60XX(hpriv)) {
                        void __iomem *port_mmio = mv_port_base(mmio, port);
 
@@ -2227,9 +2238,9 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
                hpriv->ops->phy_errata(hpriv, mmio, port);
        }
 
-       for (port = 0; port < probe_ent->n_ports; port++) {
+       for (port = 0; port < host->n_ports; port++) {
                void __iomem *port_mmio = mv_port_base(mmio, port);
-               mv_port_init(&probe_ent->port[port], port_mmio);
+               mv_port_init(&host->ports[port]->ioaddr, port_mmio);
        }
 
        for (hc = 0; hc < n_hc; hc++) {
@@ -2268,17 +2279,17 @@ done:
 
 /**
  *      mv_print_info - Dump key info to kernel log for perusal.
- *      @probe_ent: early data struct representing the host
+ *      @host: ATA host to print info about
  *
  *      FIXME: complete this.
  *
  *      LOCKING:
  *      Inherited from caller.
  */
-static void mv_print_info(struct ata_probe_ent *probe_ent)
+static void mv_print_info(struct ata_host *host)
 {
-       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-       struct mv_host_priv *hpriv = probe_ent->private_data;
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       struct mv_host_priv *hpriv = host->private_data;
        u8 rev_id, scc;
        const char *scc_s;
 
@@ -2297,7 +2308,7 @@ static void mv_print_info(struct ata_probe_ent *probe_ent)
 
        dev_printk(KERN_INFO, &pdev->dev,
               "%u slots %u ports %s mode IRQ via %s\n",
-              (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports,
+              (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
               scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
 }
 
@@ -2312,50 +2323,42 @@ static void mv_print_info(struct ata_probe_ent *probe_ent)
 static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version = 0;
-       struct device *dev = &pdev->dev;
-       struct ata_probe_ent *probe_ent;
-       struct mv_host_priv *hpriv;
        unsigned int board_idx = (unsigned int)ent->driver_data;
-       int rc;
+       const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
+       struct ata_host *host;
+       struct mv_host_priv *hpriv;
+       int n_ports, rc;
 
        if (!printed_version++)
                dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* allocate host */
+       n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+       hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+       if (!host || !hpriv)
+               return -ENOMEM;
+       host->private_data = hpriv;
+
+       /* acquire resources */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
-       pci_set_master(pdev);
 
        rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
        if (rc == -EBUSY)
                pcim_pin_device(pdev);
        if (rc)
                return rc;
+       host->iomap = pcim_iomap_table(pdev);
 
-       probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
-               return -ENOMEM;
-
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
-
-       hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
-       if (!hpriv)
-               return -ENOMEM;
-
-       probe_ent->sht = mv_port_info[board_idx].sht;
-       probe_ent->port_flags = mv_port_info[board_idx].flags;
-       probe_ent->pio_mask = mv_port_info[board_idx].pio_mask;
-       probe_ent->udma_mask = mv_port_info[board_idx].udma_mask;
-       probe_ent->port_ops = mv_port_info[board_idx].port_ops;
-
-       probe_ent->irq = pdev->irq;
-       probe_ent->irq_flags = IRQF_SHARED;
-       probe_ent->iomap = pcim_iomap_table(pdev);
-       probe_ent->private_data = hpriv;
+       rc = pci_go_64(pdev);
+       if (rc)
+               return rc;
 
        /* initialize adapter */
-       rc = mv_init_host(pdev, probe_ent, board_idx);
+       rc = mv_init_host(host, board_idx);
        if (rc)
                return rc;
 
@@ -2364,13 +2367,11 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                pci_intx(pdev, 1);
 
        mv_dump_pci_cfg(pdev, 0x68);
-       mv_print_info(probe_ent);
+       mv_print_info(host);
 
-       if (ata_device_add(probe_ent) == 0)
-               return -ENODEV;
-
-       devm_kfree(dev, probe_ent);
-       return 0;
+       pci_set_master(pdev);
+       return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
+                                &mv_sht);
 }
 
 static int __init mv_init(void)
index 9d9670a9b117e67d3689b8f5b2a1aa4b586f9ac6..02169740ed245dd2bddc51f9297edf790b07768e 100644 (file)
@@ -260,6 +260,7 @@ static int nv_adma_port_resume(struct ata_port *ap);
 static void nv_adma_error_handler(struct ata_port *ap);
 static void nv_adma_host_stop(struct ata_host *host);
 static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 
 enum nv_host_type
 {
@@ -368,7 +369,6 @@ static const struct ata_port_operations nv_generic_ops = {
        .error_handler          = nv_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
        .data_xfer              = ata_data_xfer,
-       .irq_handler            = nv_generic_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -395,7 +395,6 @@ static const struct ata_port_operations nv_nf2_ops = {
        .error_handler          = nv_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
        .data_xfer              = ata_data_xfer,
-       .irq_handler            = nv_nf2_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -422,7 +421,6 @@ static const struct ata_port_operations nv_ck804_ops = {
        .error_handler          = nv_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
        .data_xfer              = ata_data_xfer,
-       .irq_handler            = nv_ck804_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -435,7 +433,7 @@ static const struct ata_port_operations nv_ck804_ops = {
 static const struct ata_port_operations nv_adma_ops = {
        .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
-       .tf_read                = ata_tf_read,
+       .tf_read                = nv_adma_tf_read,
        .check_atapi_dma        = nv_adma_check_atapi_dma,
        .exec_command           = ata_exec_command,
        .check_status           = ata_check_status,
@@ -451,7 +449,6 @@ static const struct ata_port_operations nv_adma_ops = {
        .error_handler          = nv_adma_error_handler,
        .post_internal_cmd      = nv_adma_post_internal_cmd,
        .data_xfer              = ata_data_xfer,
-       .irq_handler            = nv_adma_interrupt,
        .irq_clear              = nv_adma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -476,6 +473,7 @@ static struct ata_port_info nv_port_info[] = {
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
                .port_ops       = &nv_generic_ops,
+               .irq_handler    = nv_generic_interrupt,
        },
        /* nforce2/3 */
        {
@@ -486,6 +484,7 @@ static struct ata_port_info nv_port_info[] = {
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
                .port_ops       = &nv_nf2_ops,
+               .irq_handler    = nv_nf2_interrupt,
        },
        /* ck804 */
        {
@@ -496,6 +495,7 @@ static struct ata_port_info nv_port_info[] = {
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
                .port_ops       = &nv_ck804_ops,
+               .irq_handler    = nv_ck804_interrupt,
        },
        /* ADMA */
        {
@@ -507,6 +507,7 @@ static struct ata_port_info nv_port_info[] = {
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
                .port_ops       = &nv_adma_ops,
+               .irq_handler    = nv_adma_interrupt,
        },
 };
 
@@ -667,6 +668,18 @@ static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc)
        return !(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE);
 }
 
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+       /* Since commands where a result TF is requested are not
+          executed in ADMA mode, the only time this function will be called
+          in ADMA mode will be if a command fails. In this case we
+          don't care about going into register mode with ADMA commands
+          pending, as the commands will all shortly be aborted anyway. */
+       nv_adma_register_mode(ap);
+
+       ata_tf_read(ap, tf);
+}
+
 static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
 {
        unsigned int idx = 0;
@@ -738,19 +751,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
                return 1;
        }
 
-       if (flags & NV_CPB_RESP_DONE) {
+       if (likely(flags & NV_CPB_RESP_DONE)) {
                struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
                VPRINTK("CPB flags done, flags=0x%x\n", flags);
                if (likely(qc)) {
-                       /* Grab the ATA port status for non-NCQ commands.
-                          For NCQ commands the current status may have nothing to do with
-                          the command just completed. */
-                       if (qc->tf.protocol != ATA_PROT_NCQ) {
-                               u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4));
-                               qc->err_mask |= ac_err_mask(ata_status);
-                       }
-                       DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num,
-                               qc->err_mask);
+                       DPRINTK("Completing qc from tag %d\n",cpb_num);
                        ata_qc_complete(qc);
                } else {
                        struct ata_eh_info *ehi = &ap->eh_info;
@@ -1074,14 +1079,14 @@ static int nv_adma_port_resume(struct ata_port *ap)
 }
 #endif
 
-static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
+static void nv_adma_setup_port(struct ata_port *ap)
 {
-       void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR];
-       struct ata_ioports *ioport = &probe_ent->port[port];
+       void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+       struct ata_ioports *ioport = &ap->ioaddr;
 
        VPRINTK("ENTER\n");
 
-       mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE;
+       mmio += NV_ADMA_PORT + ap->port_no * NV_ADMA_PORT_SIZE;
 
        ioport->cmd_addr        = mmio;
        ioport->data_addr       = mmio + (ATA_REG_DATA * 4);
@@ -1098,9 +1103,9 @@ static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int por
        ioport->ctl_addr        = mmio + 0x20;
 }
 
-static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
+static int nv_adma_host_init(struct ata_host *host)
 {
-       struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+       struct pci_dev *pdev = to_pci_dev(host->dev);
        unsigned int i;
        u32 tmp32;
 
@@ -1115,8 +1120,8 @@ static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
 
        pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
 
-       for (i = 0; i < probe_ent->n_ports; i++)
-               nv_adma_setup_port(probe_ent, i);
+       for (i = 0; i < host->n_ports; i++)
+               nv_adma_setup_port(host->ports[i]);
 
        return 0;
 }
@@ -1167,9 +1172,11 @@ static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
        struct nv_adma_port_priv *pp = qc->ap->private_data;
 
        /* ADMA engine can only be used for non-ATAPI DMA commands,
-          or interrupt-driven no-data commands. */
+          or interrupt-driven no-data commands, where a result taskfile
+          is not required. */
        if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
-          (qc->tf.flags & ATA_TFLAG_POLLING))
+          (qc->tf.flags & ATA_TFLAG_POLLING) ||
+          (qc->flags & ATA_QCFLAG_RESULT_TF))
                return 1;
 
        if((qc->flags & ATA_QCFLAG_DMAMAP) ||
@@ -1473,14 +1480,13 @@ static void nv_adma_error_handler(struct ata_port *ap)
 static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version = 0;
-       struct ata_port_info *ppi[2];
-       struct ata_probe_ent *probe_ent;
+       const struct ata_port_info *ppi[2];
+       struct ata_host *host;
        struct nv_host_priv *hpriv;
        int rc;
        u32 bar;
        void __iomem *base;
        unsigned long type = ent->driver_data;
-       int mask_set = 0;
 
         // Make sure this is a SATA controller by counting the number of bars
         // (NVIDIA SATA controllers will always have six bars).  Otherwise,
@@ -1496,50 +1502,38 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc) {
-               pcim_pin_device(pdev);
-               return rc;
-       }
-
-       if(type >= CK804 && adma_enabled) {
+       /* determine type and allocate host */
+       if (type >= CK804 && adma_enabled) {
                dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n");
                type = ADMA;
-               if(!pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
-                  !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
-                       mask_set = 1;
-       }
-
-       if(!mask_set) {
-               rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-               if (rc)
-                       return rc;
-               rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-               if (rc)
-                       return rc;
        }
 
-       rc = -ENOMEM;
+       ppi[0] = ppi[1] = &nv_port_info[type];
+       rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
+       if (rc)
+               return rc;
 
        hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
        if (!hpriv)
                return -ENOMEM;
+       hpriv->type = type;
+       host->private_data = hpriv;
 
-       ppi[0] = ppi[1] = &nv_port_info[type];
-       probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-       if (!probe_ent)
-               return -ENOMEM;
-
-       if (!pcim_iomap(pdev, NV_MMIO_BAR, 0))
-               return -EIO;
-       probe_ent->iomap = pcim_iomap_table(pdev);
+       /* set 64bit dma masks, may fail */
+       if (type == ADMA) {
+               if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0)
+                       pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+       }
 
-       probe_ent->private_data = hpriv;
-       hpriv->type = type;
+       /* request and iomap NV_MMIO_BAR */
+       rc = pcim_iomap_regions(pdev, 1 << NV_MMIO_BAR, DRV_NAME);
+       if (rc)
+               return rc;
 
-       base = probe_ent->iomap[NV_MMIO_BAR];
-       probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
-       probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
+       /* configure SCR access */
+       base = host->iomap[NV_MMIO_BAR];
+       host->ports[0]->ioaddr.scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
+       host->ports[1]->ioaddr.scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
 
        /* enable SATA space for CK804 */
        if (type >= CK804) {
@@ -1550,20 +1544,16 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
        }
 
-       pci_set_master(pdev);
-
+       /* init ADMA */
        if (type == ADMA) {
-               rc = nv_adma_host_init(probe_ent);
+               rc = nv_adma_host_init(host);
                if (rc)
                        return rc;
        }
 
-       rc = ata_device_add(probe_ent);
-       if (rc != NV_PORTS)
-               return -ENODEV;
-
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
+       pci_set_master(pdev);
+       return ata_host_activate(host, pdev->irq, ppi[0]->irq_handler,
+                                IRQF_SHARED, ppi[0]->sht);
 }
 
 static void nv_remove_one (struct pci_dev *pdev)
index 2339813ce9f646caf678172bbb85e045d157f2c7..f56549b90aa63e3d4849dcef9e491dc519ebacfb 100644 (file)
 #include "sata_promise.h"
 
 #define DRV_NAME       "sata_promise"
-#define DRV_VERSION    "2.00"
+#define DRV_VERSION    "2.05"
 
 
 enum {
+       PDC_MAX_PORTS           = 4,
        PDC_MMIO_BAR            = 3,
 
        /* register offsets */
@@ -70,14 +71,31 @@ enum {
        PDC_TBG_MODE            = 0x41C, /* TBG mode (not SATAII) */
        PDC_SLEW_CTL            = 0x470, /* slew rate control reg (not SATAII) */
 
-       PDC_ERR_MASK            = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
-                                 (1<<8) | (1<<9) | (1<<10),
+       /* PDC_GLOBAL_CTL bit definitions */
+       PDC_PH_ERR              = (1 <<  8), /* PCI error while loading packet */
+       PDC_SH_ERR              = (1 <<  9), /* PCI error while loading S/G table */
+       PDC_DH_ERR              = (1 << 10), /* PCI error while loading data */
+       PDC2_HTO_ERR            = (1 << 12), /* host bus timeout */
+       PDC2_ATA_HBA_ERR        = (1 << 13), /* error during SATA DATA FIS transmission */
+       PDC2_ATA_DMA_CNT_ERR    = (1 << 14), /* DMA DATA FIS size differs from S/G count */
+       PDC_OVERRUN_ERR         = (1 << 19), /* S/G byte count larger than HD requires */
+       PDC_UNDERRUN_ERR        = (1 << 20), /* S/G byte count less than HD requires */
+       PDC_DRIVE_ERR           = (1 << 21), /* drive error */
+       PDC_PCI_SYS_ERR         = (1 << 22), /* PCI system error */
+       PDC1_PCI_PARITY_ERR     = (1 << 23), /* PCI parity error (from SATA150 driver) */
+       PDC1_ERR_MASK           = PDC1_PCI_PARITY_ERR,
+       PDC2_ERR_MASK           = PDC2_HTO_ERR | PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR,
+       PDC_ERR_MASK            = (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC_OVERRUN_ERR
+                                  | PDC_UNDERRUN_ERR | PDC_DRIVE_ERR | PDC_PCI_SYS_ERR
+                                  | PDC1_ERR_MASK | PDC2_ERR_MASK),
 
        board_2037x             = 0,    /* FastTrak S150 TX2plus */
-       board_20319             = 1,    /* FastTrak S150 TX4 */
-       board_20619             = 2,    /* FastTrak TX4000 */
-       board_2057x             = 3,    /* SATAII150 Tx2plus */
-       board_40518             = 4,    /* SATAII150 Tx4 */
+       board_2037x_pata        = 1,    /* FastTrak S150 TX2plus PATA port */
+       board_20319             = 2,    /* FastTrak S150 TX4 */
+       board_20619             = 3,    /* FastTrak TX4000 */
+       board_2057x             = 4,    /* SATAII150 Tx2plus */
+       board_2057x_pata        = 5,    /* SATAII150 Tx2plus */
+       board_40518             = 6,    /* SATAII150 Tx4 */
 
        PDC_HAS_PATA            = (1 << 1), /* PDC20375/20575 has PATA */
 
@@ -100,8 +118,10 @@ enum {
                                  ATA_FLAG_MMIO |
                                  ATA_FLAG_PIO_POLLING,
 
-       /* hp->flags bits */
-       PDC_FLAG_GEN_II         = (1 << 0),
+       /* ap->flags bits */
+       PDC_FLAG_GEN_II         = (1 << 24),
+       PDC_FLAG_SATA_PATA      = (1 << 25), /* supports SATA + PATA */
+       PDC_FLAG_4_PORTS        = (1 << 26), /* 4 ports */
 };
 
 
@@ -110,28 +130,25 @@ struct pdc_port_priv {
        dma_addr_t              pkt_dma;
 };
 
-struct pdc_host_priv {
-       unsigned long           flags;
-       unsigned long           port_flags[ATA_MAX_PORTS];
-};
-
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc_interrupt (int irq, void *dev_instance);
-static int pdc_port_start(struct ata_port *ap);
+static int pdc_common_port_start(struct ata_port *ap);
+static int pdc_sata_port_start(struct ata_port *ap);
 static void pdc_qc_prep(struct ata_queued_cmd *qc);
 static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
-static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc);
+static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc);
 static void pdc_irq_clear(struct ata_port *ap);
 static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
 static void pdc_freeze(struct ata_port *ap);
 static void pdc_thaw(struct ata_port *ap);
-static void pdc_error_handler(struct ata_port *ap);
+static void pdc_pata_error_handler(struct ata_port *ap);
+static void pdc_sata_error_handler(struct ata_port *ap);
 static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
-
+static int pdc_pata_cable_detect(struct ata_port *ap);
+static int pdc_sata_cable_detect(struct ata_port *ap);
 
 static struct scsi_host_template pdc_ata_sht = {
        .module                 = THIS_MODULE,
@@ -164,17 +181,17 @@ static const struct ata_port_operations pdc_sata_ops = {
        .qc_issue               = pdc_qc_issue_prot,
        .freeze                 = pdc_freeze,
        .thaw                   = pdc_thaw,
-       .error_handler          = pdc_error_handler,
+       .error_handler          = pdc_sata_error_handler,
        .post_internal_cmd      = pdc_post_internal_cmd,
+       .cable_detect           = pdc_sata_cable_detect,
        .data_xfer              = ata_data_xfer,
-       .irq_handler            = pdc_interrupt,
        .irq_clear              = pdc_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
 
        .scr_read               = pdc_sata_scr_read,
        .scr_write              = pdc_sata_scr_write,
-       .port_start             = pdc_port_start,
+       .port_start             = pdc_sata_port_start,
 };
 
 /* First-generation chips need a more restrictive ->check_atapi_dma op */
@@ -185,23 +202,23 @@ static const struct ata_port_operations pdc_old_sata_ops = {
        .check_status           = ata_check_status,
        .exec_command           = pdc_exec_command_mmio,
        .dev_select             = ata_std_dev_select,
-       .check_atapi_dma        = pdc_old_check_atapi_dma,
+       .check_atapi_dma        = pdc_old_sata_check_atapi_dma,
 
        .qc_prep                = pdc_qc_prep,
        .qc_issue               = pdc_qc_issue_prot,
        .freeze                 = pdc_freeze,
        .thaw                   = pdc_thaw,
-       .error_handler          = pdc_error_handler,
+       .error_handler          = pdc_sata_error_handler,
        .post_internal_cmd      = pdc_post_internal_cmd,
+       .cable_detect           = pdc_sata_cable_detect,
        .data_xfer              = ata_data_xfer,
-       .irq_handler            = pdc_interrupt,
        .irq_clear              = pdc_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
 
        .scr_read               = pdc_sata_scr_read,
        .scr_write              = pdc_sata_scr_write,
-       .port_start             = pdc_port_start,
+       .port_start             = pdc_sata_port_start,
 };
 
 static const struct ata_port_operations pdc_pata_ops = {
@@ -217,32 +234,41 @@ static const struct ata_port_operations pdc_pata_ops = {
        .qc_issue               = pdc_qc_issue_prot,
        .freeze                 = pdc_freeze,
        .thaw                   = pdc_thaw,
-       .error_handler          = pdc_error_handler,
+       .error_handler          = pdc_pata_error_handler,
        .post_internal_cmd      = pdc_post_internal_cmd,
+       .cable_detect           = pdc_pata_cable_detect,
        .data_xfer              = ata_data_xfer,
-       .irq_handler            = pdc_interrupt,
        .irq_clear              = pdc_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
 
-       .port_start             = pdc_port_start,
+       .port_start             = pdc_common_port_start,
 };
 
 static const struct ata_port_info pdc_port_info[] = {
        /* board_2037x */
        {
-               .sht            = &pdc_ata_sht,
-               .flags          = PDC_COMMON_FLAGS,
+               .flags          = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+                                 PDC_FLAG_SATA_PATA,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &pdc_old_sata_ops,
        },
 
+       /* board_2037x_pata */
+       {
+               .flags          = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .port_ops       = &pdc_pata_ops,
+       },
+
        /* board_20319 */
        {
-               .sht            = &pdc_ata_sht,
-               .flags          = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+               .flags          = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+                                 PDC_FLAG_4_PORTS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
@@ -251,8 +277,8 @@ static const struct ata_port_info pdc_port_info[] = {
 
        /* board_20619 */
        {
-               .sht            = &pdc_ata_sht,
-               .flags          = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+               .flags          = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
+                                 PDC_FLAG_4_PORTS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
@@ -261,18 +287,28 @@ static const struct ata_port_info pdc_port_info[] = {
 
        /* board_2057x */
        {
-               .sht            = &pdc_ata_sht,
-               .flags          = PDC_COMMON_FLAGS,
+               .flags          = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+                                 PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &pdc_sata_ops,
        },
 
+       /* board_2057x_pata */
+       {
+               .flags          = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+                                 PDC_FLAG_GEN_II,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .port_ops       = &pdc_pata_ops,
+       },
+
        /* board_40518 */
        {
-               .sht            = &pdc_ata_sht,
-               .flags          = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+               .flags          = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+                                 PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
@@ -313,18 +349,12 @@ static struct pci_driver pdc_ata_pci_driver = {
 };
 
 
-static int pdc_port_start(struct ata_port *ap)
+static int pdc_common_port_start(struct ata_port *ap)
 {
        struct device *dev = ap->host->dev;
-       struct pdc_host_priv *hp = ap->host->private_data;
        struct pdc_port_priv *pp;
        int rc;
 
-       /* fix up port flags and cable type for SATA+PATA chips */
-       ap->flags |= hp->port_flags[ap->port_no];
-       if (ap->flags & ATA_FLAG_SATA)
-               ap->cbl = ATA_CBL_SATA;
-
        rc = ata_port_start(ap);
        if (rc)
                return rc;
@@ -339,8 +369,19 @@ static int pdc_port_start(struct ata_port *ap)
 
        ap->private_data = pp;
 
+       return 0;
+}
+
+static int pdc_sata_port_start(struct ata_port *ap)
+{
+       int rc;
+
+       rc = pdc_common_port_start(ap);
+       if (rc)
+               return rc;
+
        /* fix up PHYMODE4 align timing */
-       if ((hp->flags & PDC_FLAG_GEN_II) && sata_scr_valid(ap)) {
+       if (ap->flags & PDC_FLAG_GEN_II) {
                void __iomem *mmio = (void __iomem *) ap->ioaddr.scr_addr;
                unsigned int tmp;
 
@@ -374,23 +415,25 @@ static void pdc_reset_port(struct ata_port *ap)
        readl(mmio);    /* flush */
 }
 
-static void pdc_pata_cbl_detect(struct ata_port *ap)
+static int pdc_pata_cable_detect(struct ata_port *ap)
 {
        u8 tmp;
        void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
 
        tmp = readb(mmio);
+       if (tmp & 0x01)
+               return ATA_CBL_PATA40;
+       return ATA_CBL_PATA80;
+}
 
-       if (tmp & 0x01) {
-               ap->cbl = ATA_CBL_PATA40;
-               ap->udma_mask &= ATA_UDMA_MASK_40C;
-       } else
-               ap->cbl = ATA_CBL_PATA80;
+static int pdc_sata_cable_detect(struct ata_port *ap)
+{
+       return ATA_CBL_SATA;
 }
 
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
 {
-       if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
+       if (sc_reg > SCR_CONTROL)
                return 0xffffffffU;
        return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
 }
@@ -399,7 +442,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
 static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
                               u32 val)
 {
-       if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
+       if (sc_reg > SCR_CONTROL)
                return;
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
 }
@@ -555,52 +598,79 @@ static void pdc_thaw(struct ata_port *ap)
        readl(mmio + PDC_CTLSTAT); /* flush */
 }
 
-static int pdc_pre_reset(struct ata_port *ap)
-{
-       if (!sata_scr_valid(ap))
-               pdc_pata_cbl_detect(ap);
-       return ata_std_prereset(ap);
-}
-
-static void pdc_error_handler(struct ata_port *ap)
+static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset)
 {
-       ata_reset_fn_t hardreset;
-
        if (!(ap->pflags & ATA_PFLAG_FROZEN))
                pdc_reset_port(ap);
 
-       hardreset = NULL;
-       if (sata_scr_valid(ap))
-               hardreset = sata_std_hardreset;
-
        /* perform recovery */
-       ata_do_eh(ap, pdc_pre_reset, ata_std_softreset, hardreset,
+       ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
                  ata_std_postreset);
 }
 
+static void pdc_pata_error_handler(struct ata_port *ap)
+{
+       pdc_common_error_handler(ap, NULL);
+}
+
+static void pdc_sata_error_handler(struct ata_port *ap)
+{
+       pdc_common_error_handler(ap, sata_std_hardreset);
+}
+
 static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
 
-       if (qc->flags & ATA_QCFLAG_FAILED)
-               qc->err_mask |= AC_ERR_OTHER;
-
        /* make DMA engine forget about the failed command */
-       if (qc->err_mask)
+       if (qc->flags & ATA_QCFLAG_FAILED)
                pdc_reset_port(ap);
 }
 
+static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
+                          u32 port_status, u32 err_mask)
+{
+       struct ata_eh_info *ehi = &ap->eh_info;
+       unsigned int ac_err_mask = 0;
+
+       ata_ehi_clear_desc(ehi);
+       ata_ehi_push_desc(ehi, "port_status 0x%08x", port_status);
+       port_status &= err_mask;
+
+       if (port_status & PDC_DRIVE_ERR)
+               ac_err_mask |= AC_ERR_DEV;
+       if (port_status & (PDC_OVERRUN_ERR | PDC_UNDERRUN_ERR))
+               ac_err_mask |= AC_ERR_HSM;
+       if (port_status & (PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR))
+               ac_err_mask |= AC_ERR_ATA_BUS;
+       if (port_status & (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC2_HTO_ERR
+                          | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
+               ac_err_mask |= AC_ERR_HOST_BUS;
+
+       if (sata_scr_valid(ap))
+               ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+
+       qc->err_mask |= ac_err_mask;
+
+       pdc_reset_port(ap);
+}
+
 static inline unsigned int pdc_host_intr( struct ata_port *ap,
                                           struct ata_queued_cmd *qc)
 {
        unsigned int handled = 0;
-       u32 tmp;
-       void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+       u32 port_status, err_mask;
 
-       tmp = readl(mmio);
-       if (tmp & PDC_ERR_MASK) {
-               qc->err_mask |= AC_ERR_DEV;
-               pdc_reset_port(ap);
+       err_mask = PDC_ERR_MASK;
+       if (ap->flags & PDC_FLAG_GEN_II)
+               err_mask &= ~PDC1_ERR_MASK;
+       else
+               err_mask &= ~PDC2_ERR_MASK;
+       port_status = readl(port_mmio + PDC_GLOBAL_CTL);
+       if (unlikely(port_status & err_mask)) {
+               pdc_error_intr(ap, qc, port_status, err_mask);
+               return 1;
        }
 
        switch (qc->tf.protocol) {
@@ -767,44 +837,40 @@ static int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
        return pio;
 }
 
-static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc)
+static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc)
 {
-       struct ata_port *ap = qc->ap;
-
        /* First generation chips cannot use ATAPI DMA on SATA ports */
-       if (sata_scr_valid(ap))
-               return 1;
-       return pdc_check_atapi_dma(qc);
+       return 1;
 }
 
-static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base,
-                              void __iomem *scr_addr)
+static void pdc_ata_setup_port(struct ata_port *ap,
+                              void __iomem *base, void __iomem *scr_addr)
 {
-       port->cmd_addr          = base;
-       port->data_addr         = base;
-       port->feature_addr      =
-       port->error_addr        = base + 0x4;
-       port->nsect_addr        = base + 0x8;
-       port->lbal_addr         = base + 0xc;
-       port->lbam_addr         = base + 0x10;
-       port->lbah_addr         = base + 0x14;
-       port->device_addr       = base + 0x18;
-       port->command_addr      =
-       port->status_addr       = base + 0x1c;
-       port->altstatus_addr    =
-       port->ctl_addr          = base + 0x38;
-       port->scr_addr          = scr_addr;
+       ap->ioaddr.cmd_addr             = base;
+       ap->ioaddr.data_addr            = base;
+       ap->ioaddr.feature_addr         =
+       ap->ioaddr.error_addr           = base + 0x4;
+       ap->ioaddr.nsect_addr           = base + 0x8;
+       ap->ioaddr.lbal_addr            = base + 0xc;
+       ap->ioaddr.lbam_addr            = base + 0x10;
+       ap->ioaddr.lbah_addr            = base + 0x14;
+       ap->ioaddr.device_addr          = base + 0x18;
+       ap->ioaddr.command_addr         =
+       ap->ioaddr.status_addr          = base + 0x1c;
+       ap->ioaddr.altstatus_addr       =
+       ap->ioaddr.ctl_addr             = base + 0x38;
+       ap->ioaddr.scr_addr             = scr_addr;
 }
 
 
-static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+static void pdc_host_init(struct ata_host *host)
 {
-       void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
-       struct pdc_host_priv *hp = pe->private_data;
+       void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+       int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II;
        int hotplug_offset;
        u32 tmp;
 
-       if (hp->flags & PDC_FLAG_GEN_II)
+       if (is_gen2)
                hotplug_offset = PDC2_SATA_PLUG_CSR;
        else
                hotplug_offset = PDC_SATA_PLUG_CSR;
@@ -818,7 +884,7 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
        /* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */
        tmp = readl(mmio + PDC_FLASH_CTL);
        tmp |= 0x02000; /* bit 13 (enable bmr burst) */
-       if (!(hp->flags & PDC_FLAG_GEN_II))
+       if (!is_gen2)
                tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */
        writel(tmp, mmio + PDC_FLASH_CTL);
 
@@ -831,7 +897,7 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
        writel(tmp | 0xff0000, mmio + hotplug_offset);
 
        /* don't initialise TBG or SLEW on 2nd generation chips */
-       if (hp->flags & PDC_FLAG_GEN_II)
+       if (is_gen2)
                return;
 
        /* reduce TBG clock to 133 Mhz. */
@@ -853,16 +919,16 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
-       struct ata_probe_ent *probe_ent;
-       struct pdc_host_priv *hp;
+       const struct ata_port_info *pi = &pdc_port_info[ent->driver_data];
+       const struct ata_port_info *ppi[PDC_MAX_PORTS];
+       struct ata_host *host;
        void __iomem *base;
-       unsigned int board_idx = (unsigned int) ent->driver_data;
-       int rc;
-       u8 tmp;
+       int n_ports, i, rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* enable and acquire resources */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -872,89 +938,49 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                pcim_pin_device(pdev);
        if (rc)
                return rc;
+       base = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
 
-       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-       if (rc)
-               return rc;
-       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-       if (rc)
-               return rc;
-
-       probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
-               return -ENOMEM;
+       /* determine port configuration and setup host */
+       n_ports = 2;
+       if (pi->flags & PDC_FLAG_4_PORTS)
+               n_ports = 4;
+       for (i = 0; i < n_ports; i++)
+               ppi[i] = pi;
 
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
+       if (pi->flags & PDC_FLAG_SATA_PATA) {
+               u8 tmp = readb(base + PDC_FLASH_CTL+1);
+               if (!(tmp & 0x80)) {
+                       ppi[n_ports++] = pi + 1;
+                       dev_printk(KERN_INFO, &pdev->dev, "PATA port found\n");
+               }
+       }
 
-       hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL);
-       if (hp == NULL)
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+       if (!host) {
+               dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");
                return -ENOMEM;
-
-       probe_ent->private_data = hp;
-
-       probe_ent->sht          = pdc_port_info[board_idx].sht;
-       probe_ent->port_flags   = pdc_port_info[board_idx].flags;
-       probe_ent->pio_mask     = pdc_port_info[board_idx].pio_mask;
-       probe_ent->mwdma_mask   = pdc_port_info[board_idx].mwdma_mask;
-       probe_ent->udma_mask    = pdc_port_info[board_idx].udma_mask;
-       probe_ent->port_ops     = pdc_port_info[board_idx].port_ops;
-
-               probe_ent->irq = pdev->irq;
-               probe_ent->irq_flags = IRQF_SHARED;
-       probe_ent->iomap = pcim_iomap_table(pdev);
-
-       base = probe_ent->iomap[PDC_MMIO_BAR];
-
-       pdc_ata_setup_port(&probe_ent->port[0], base + 0x200, base + 0x400);
-       pdc_ata_setup_port(&probe_ent->port[1], base + 0x280, base + 0x500);
-
-       /* notice 4-port boards */
-       switch (board_idx) {
-       case board_40518:
-               hp->flags |= PDC_FLAG_GEN_II;
-               /* Fall through */
-       case board_20319:
-                       probe_ent->n_ports = 4;
-               pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, base + 0x600);
-               pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, base + 0x700);
-               break;
-       case board_2057x:
-               hp->flags |= PDC_FLAG_GEN_II;
-               /* Fall through */
-       case board_2037x:
-               /* TX2plus boards also have a PATA port */
-               tmp = readb(base + PDC_FLASH_CTL+1);
-               if (!(tmp & 0x80)) {
-                       probe_ent->n_ports = 3;
-                       pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
-                       hp->port_flags[2] = ATA_FLAG_SLAVE_POSS;
-                       printk(KERN_INFO DRV_NAME " PATA port found\n");
-               } else
-                       probe_ent->n_ports = 2;
-               hp->port_flags[0] = ATA_FLAG_SATA;
-               hp->port_flags[1] = ATA_FLAG_SATA;
-               break;
-       case board_20619:
-               probe_ent->n_ports = 4;
-               pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
-               pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, NULL);
-               break;
-       default:
-               BUG();
-               break;
        }
+       host->iomap = pcim_iomap_table(pdev);
 
-       pci_set_master(pdev);
+       for (i = 0; i < host->n_ports; i++)
+               pdc_ata_setup_port(host->ports[i],
+                                  base + 0x200 + i * 0x80,
+                                  base + 0x400 + i * 0x100);
 
        /* initialize adapter */
-       pdc_host_init(board_idx, probe_ent);
+       pdc_host_init(host);
 
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               return rc;
+       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               return rc;
 
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
+       /* start host, request IRQ and attach */
+       pci_set_master(pdev);
+       return ata_host_activate(host, pdev->irq, pdc_interrupt, IRQF_SHARED,
+                                &pdc_ata_sht);
 }
 
 
index 8786b45f291b8d62af9ddb6fd3bc585d7c659201..f5a05de0093de45156a02c01542fa97b592f6f4c 100644 (file)
@@ -114,7 +114,6 @@ struct qs_port_priv {
 static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t qs_intr (int irq, void *dev_instance);
 static int qs_port_start(struct ata_port *ap);
 static void qs_host_stop(struct ata_host *host);
 static void qs_phy_reset(struct ata_port *ap);
@@ -158,7 +157,6 @@ static const struct ata_port_operations qs_ata_ops = {
        .qc_issue               = qs_qc_issue,
        .data_xfer              = ata_data_xfer,
        .eng_timeout            = qs_eng_timeout,
-       .irq_handler            = qs_intr,
        .irq_clear              = qs_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -173,7 +171,6 @@ static const struct ata_port_operations qs_ata_ops = {
 static const struct ata_port_info qs_port_info[] = {
        /* board_2068_idx */
        {
-               .sht            = &qs_ata_sht,
                .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_SATA_RESET |
                                  //FIXME ATA_FLAG_SRST |
@@ -530,16 +527,16 @@ static void qs_host_stop(struct ata_host *host)
        writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
 }
 
-static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+static void qs_host_init(struct ata_host *host, unsigned int chip_id)
 {
-       void __iomem *mmio_base = pe->iomap[QS_MMIO_BAR];
+       void __iomem *mmio_base = host->iomap[QS_MMIO_BAR];
        unsigned int port_no;
 
        writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
        writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
 
        /* reset each channel in turn */
-       for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+       for (port_no = 0; port_no < host->n_ports; ++port_no) {
                u8 __iomem *chan = mmio_base + (port_no * 0x4000);
                writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1);
                writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
@@ -547,7 +544,7 @@ static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
        }
        writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
 
-       for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+       for (port_no = 0; port_no < host->n_ports; ++port_no) {
                u8 __iomem *chan = mmio_base + (port_no * 0x4000);
                /* set FIFO depths to same settings as Windows driver */
                writew(32, chan + QS_CFC_HUFT);
@@ -607,14 +604,20 @@ static int qs_ata_init_one(struct pci_dev *pdev,
                                const struct pci_device_id *ent)
 {
        static int printed_version;
-       struct ata_probe_ent *probe_ent;
-       void __iomem * const *iomap;
        unsigned int board_idx = (unsigned int) ent->driver_data;
+       const struct ata_port_info *ppi[] = { &qs_port_info[board_idx], NULL };
+       struct ata_host *host;
        int rc, port_no;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* alloc host */
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, QS_PORTS);
+       if (!host)
+               return -ENOMEM;
+
+       /* acquire resources and fill host */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -625,47 +628,24 @@ static int qs_ata_init_one(struct pci_dev *pdev,
        rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME);
        if (rc)
                return rc;
-       iomap = pcim_iomap_table(pdev);
+       host->iomap = pcim_iomap_table(pdev);
 
-       rc = qs_set_dma_masks(pdev, iomap[QS_MMIO_BAR]);
+       rc = qs_set_dma_masks(pdev, host->iomap[QS_MMIO_BAR]);
        if (rc)
                return rc;
 
-       probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
-               return -ENOMEM;
-
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
-
-       probe_ent->sht          = qs_port_info[board_idx].sht;
-       probe_ent->port_flags   = qs_port_info[board_idx].flags;
-       probe_ent->pio_mask     = qs_port_info[board_idx].pio_mask;
-       probe_ent->mwdma_mask   = qs_port_info[board_idx].mwdma_mask;
-       probe_ent->udma_mask    = qs_port_info[board_idx].udma_mask;
-       probe_ent->port_ops     = qs_port_info[board_idx].port_ops;
-
-       probe_ent->irq          = pdev->irq;
-       probe_ent->irq_flags    = IRQF_SHARED;
-       probe_ent->iomap        = iomap;
-       probe_ent->n_ports      = QS_PORTS;
-
-       for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
+       for (port_no = 0; port_no < host->n_ports; ++port_no) {
                void __iomem *chan =
-                       probe_ent->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
-               qs_ata_setup_port(&probe_ent->port[port_no], chan);
+                       host->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
+               qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan);
        }
 
-       pci_set_master(pdev);
-
        /* initialize adapter */
-       qs_host_init(board_idx, probe_ent);
+       qs_host_init(host, board_idx);
 
-       if (ata_device_add(probe_ent) != QS_PORTS)
-               return -EIO;
-
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
+       pci_set_master(pdev);
+       return ata_host_activate(host, pdev->irq, qs_intr, IRQF_SHARED,
+                                &qs_ata_sht);
 }
 
 static int __init qs_ata_init(void)
index 917b7ea4ef7c203b0bd4ebc5abd83aad5ceb4420..0a1e417f309c5342aaaf763fa2ddc595e414fed7 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_sil"
-#define DRV_VERSION    "2.1"
+#define DRV_VERSION    "2.2"
 
 enum {
        SIL_MMIO_BAR            = 5,
@@ -114,11 +114,10 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 #ifdef CONFIG_PM
 static int sil_pci_device_resume(struct pci_dev *pdev);
 #endif
-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
+static void sil_dev_config(struct ata_device *dev);
 static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static void sil_post_set_mode (struct ata_port *ap);
-static irqreturn_t sil_interrupt(int irq, void *dev_instance);
+static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
 static void sil_freeze(struct ata_port *ap);
 static void sil_thaw(struct ata_port *ap);
 
@@ -197,7 +196,7 @@ static const struct ata_port_operations sil_ops = {
        .check_status           = ata_check_status,
        .exec_command           = ata_exec_command,
        .dev_select             = ata_std_dev_select,
-       .post_set_mode          = sil_post_set_mode,
+       .set_mode               = sil_set_mode,
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
        .bmdma_stop             = ata_bmdma_stop,
@@ -209,7 +208,6 @@ static const struct ata_port_operations sil_ops = {
        .thaw                   = sil_thaw,
        .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-       .irq_handler            = sil_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -221,7 +219,6 @@ static const struct ata_port_operations sil_ops = {
 static const struct ata_port_info sil_port_info[] = {
        /* sil_3112 */
        {
-               .sht            = &sil_sht,
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
@@ -230,7 +227,6 @@ static const struct ata_port_info sil_port_info[] = {
        },
        /* sil_3112_no_sata_irq */
        {
-               .sht            = &sil_sht,
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
                                  SIL_FLAG_NO_SATA_IRQ,
                .pio_mask       = 0x1f,                 /* pio0-4 */
@@ -240,7 +236,6 @@ static const struct ata_port_info sil_port_info[] = {
        },
        /* sil_3512 */
        {
-               .sht            = &sil_sht,
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
@@ -249,7 +244,6 @@ static const struct ata_port_info sil_port_info[] = {
        },
        /* sil_3114 */
        {
-               .sht            = &sil_sht,
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
@@ -297,7 +291,16 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
        return cache_line;
 }
 
-static void sil_post_set_mode (struct ata_port *ap)
+/**
+ *     sil_set_mode            -       wrap set_mode functions
+ *     @ap: port to set up
+ *     @r_failed: returned device when we fail
+ *
+ *     Wrap the libata method for device setup as after the setup we need
+ *     to inspect the results and do some configuration work
+ */
+
+static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed)
 {
        struct ata_host *host = ap->host;
        struct ata_device *dev;
@@ -305,6 +308,11 @@ static void sil_post_set_mode (struct ata_port *ap)
        void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
        u32 tmp, dev_mode[2];
        unsigned int i;
+       int rc;
+       
+       rc = ata_do_set_mode(ap, r_failed);
+       if (rc)
+               return rc;
 
        for (i = 0; i < 2; i++) {
                dev = &ap->device[i];
@@ -323,6 +331,7 @@ static void sil_post_set_mode (struct ata_port *ap)
        tmp |= (dev_mode[1] << 4);
        writel(tmp, addr);
        readl(addr);    /* flush */
+       return 0;
 }
 
 static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
@@ -521,7 +530,6 @@ static void sil_thaw(struct ata_port *ap)
 
 /**
  *     sil_dev_config - Apply device/host-specific errata fixups
- *     @ap: Port containing device to be examined
  *     @dev: Device to be examined
  *
  *     After the IDENTIFY [PACKET] DEVICE step is complete, and a
@@ -548,8 +556,9 @@ static void sil_thaw(struct ata_port *ap)
  *     appreciated.
  *     - But then again UDMA5 is hardly anything to complain about
  */
-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void sil_dev_config(struct ata_device *dev)
 {
+       struct ata_port *ap = dev->ap;
        int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
        unsigned int n, quirks = 0;
        unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -583,10 +592,10 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
        }
 }
 
-static void sil_init_controller(struct pci_dev *pdev,
-                               int n_ports, unsigned long port_flags,
-                               void __iomem *mmio_base)
+static void sil_init_controller(struct ata_host *host)
 {
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
        u8 cls;
        u32 tmp;
        int i;
@@ -596,7 +605,7 @@ static void sil_init_controller(struct pci_dev *pdev,
        if (cls) {
                cls >>= 3;
                cls++;  /* cls = (line_size/8)+1 */
-               for (i = 0; i < n_ports; i++)
+               for (i = 0; i < host->n_ports; i++)
                        writew(cls << 8 | cls,
                               mmio_base + sil_port[i].fifo_cfg);
        } else
@@ -604,10 +613,10 @@ static void sil_init_controller(struct pci_dev *pdev,
                           "cache line size not set.  Driver may not function\n");
 
        /* Apply R_ERR on DMA activate FIS errata workaround */
-       if (port_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+       if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) {
                int cnt;
 
-               for (i = 0, cnt = 0; i < n_ports; i++) {
+               for (i = 0, cnt = 0; i < host->n_ports; i++) {
                        tmp = readl(mmio_base + sil_port[i].sfis_cfg);
                        if ((tmp & 0x3) != 0x01)
                                continue;
@@ -620,7 +629,7 @@ static void sil_init_controller(struct pci_dev *pdev,
                }
        }
 
-       if (n_ports == 4) {
+       if (host->n_ports == 4) {
                /* flip the magic "make 4 ports work" bit */
                tmp = readl(mmio_base + sil_port[2].bmdma);
                if ((tmp & SIL_INTR_STEERING) == 0)
@@ -632,15 +641,26 @@ static void sil_init_controller(struct pci_dev *pdev,
 static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
-       struct device *dev = &pdev->dev;
-       struct ata_probe_ent *probe_ent;
+       int board_id = ent->driver_data;
+       const struct ata_port_info *ppi[] = { &sil_port_info[board_id], NULL };
+       struct ata_host *host;
        void __iomem *mmio_base;
-       int rc;
+       int n_ports, rc;
        unsigned int i;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* allocate host */
+       n_ports = 2;
+       if (board_id == sil_3114)
+               n_ports = 4;
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+       if (!host)
+               return -ENOMEM;
+
+       /* acquire resources and fill host */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -650,6 +670,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                pcim_pin_device(pdev);
        if (rc)
                return rc;
+       host->iomap = pcim_iomap_table(pdev);
 
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
@@ -658,45 +679,25 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
-               return -ENOMEM;
+       mmio_base = host->iomap[SIL_MMIO_BAR];
 
-       INIT_LIST_HEAD(&probe_ent->node);
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
-       probe_ent->sht = sil_port_info[ent->driver_data].sht;
-       probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2;
-       probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask;
-       probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask;
-       probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
-               probe_ent->irq = pdev->irq;
-               probe_ent->irq_flags = IRQF_SHARED;
-       probe_ent->port_flags = sil_port_info[ent->driver_data].flags;
-
-       probe_ent->iomap = pcim_iomap_table(pdev);
-
-       mmio_base = probe_ent->iomap[SIL_MMIO_BAR];
-
-       for (i = 0; i < probe_ent->n_ports; i++) {
-               probe_ent->port[i].cmd_addr = mmio_base + sil_port[i].tf;
-               probe_ent->port[i].altstatus_addr =
-               probe_ent->port[i].ctl_addr = mmio_base + sil_port[i].ctl;
-               probe_ent->port[i].bmdma_addr = mmio_base + sil_port[i].bmdma;
-               probe_ent->port[i].scr_addr = mmio_base + sil_port[i].scr;
-               ata_std_ports(&probe_ent->port[i]);
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+
+               ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
+               ioaddr->altstatus_addr =
+               ioaddr->ctl_addr = mmio_base + sil_port[i].ctl;
+               ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
+               ioaddr->scr_addr = mmio_base + sil_port[i].scr;
+               ata_std_ports(ioaddr);
        }
 
-       sil_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
-                           mmio_base);
+       /* initialize and activate */
+       sil_init_controller(host);
 
        pci_set_master(pdev);
-
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(dev, probe_ent);
-       return 0;
+       return ata_host_activate(host, pdev->irq, sil_interrupt, IRQF_SHARED,
+                                &sil_sht);
 }
 
 #ifdef CONFIG_PM
@@ -709,8 +710,7 @@ static int sil_pci_device_resume(struct pci_dev *pdev)
        if (rc)
                return rc;
 
-       sil_init_controller(pdev, host->n_ports, host->ports[0]->flags,
-                           host->iomap[SIL_MMIO_BAR]);
+       sil_init_controller(host);
        ata_host_resume(host);
 
        return 0;
index 5614df8c1ce2809bed166aa3b0f70d63e112819f..e6223ba667daca271a19e1c541470d80463c2a9a 100644 (file)
@@ -323,7 +323,7 @@ struct sil24_port_priv {
        struct ata_taskfile tf;                 /* Cached taskfile registers */
 };
 
-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
+static void sil24_dev_config(struct ata_device *dev);
 static u8 sil24_check_status(struct ata_port *ap);
 static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
 static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
@@ -331,7 +331,6 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
 static void sil24_irq_clear(struct ata_port *ap);
-static irqreturn_t sil24_interrupt(int irq, void *dev_instance);
 static void sil24_freeze(struct ata_port *ap);
 static void sil24_thaw(struct ata_port *ap);
 static void sil24_error_handler(struct ata_port *ap);
@@ -401,7 +400,6 @@ static const struct ata_port_operations sil24_ops = {
        .qc_prep                = sil24_qc_prep,
        .qc_issue               = sil24_qc_issue,
 
-       .irq_handler            = sil24_interrupt,
        .irq_clear              = sil24_irq_clear,
        .irq_on                 = ata_dummy_irq_on,
        .irq_ack                = ata_dummy_irq_ack,
@@ -424,10 +422,9 @@ static const struct ata_port_operations sil24_ops = {
 #define SIL24_NPORTS2FLAG(nports)      ((((unsigned)(nports) - 1) & 0x3) << 30)
 #define SIL24_FLAG2NPORTS(flag)                ((((flag) >> 30) & 0x3) + 1)
 
-static struct ata_port_info sil24_port_info[] = {
+static const struct ata_port_info sil24_port_info[] = {
        /* sil_3124 */
        {
-               .sht            = &sil24_sht,
                .flags          = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
                                  SIL24_FLAG_PCIX_IRQ_WOC,
                .pio_mask       = 0x1f,                 /* pio0-4 */
@@ -437,7 +434,6 @@ static struct ata_port_info sil24_port_info[] = {
        },
        /* sil_3132 */
        {
-               .sht            = &sil24_sht,
                .flags          = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
@@ -446,7 +442,6 @@ static struct ata_port_info sil24_port_info[] = {
        },
        /* sil_3131/sil_3531 */
        {
-               .sht            = &sil24_sht,
                .flags          = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
@@ -462,9 +457,9 @@ static int sil24_tag(int tag)
        return tag;
 }
 
-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void sil24_dev_config(struct ata_device *dev)
 {
-       void __iomem *port = ap->ioaddr.cmd_addr;
+       void __iomem *port = dev->ap->ioaddr.cmd_addr;
 
        if (dev->cdb_len == 16)
                writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -924,11 +919,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
 
-       if (qc->flags & ATA_QCFLAG_FAILED)
-               qc->err_mask |= AC_ERR_OTHER;
-
        /* make DMA engine forget about the failed command */
-       if (qc->err_mask)
+       if (qc->flags & ATA_QCFLAG_FAILED)
                sil24_init_port(ap);
 }
 
@@ -964,11 +956,10 @@ static int sil24_port_start(struct ata_port *ap)
        return 0;
 }
 
-static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
-                                 unsigned long port_flags,
-                                 void __iomem *host_base,
-                                 void __iomem *port_base)
+static void sil24_init_controller(struct ata_host *host)
 {
+       void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
+       void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
        u32 tmp;
        int i;
 
@@ -979,7 +970,7 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
        writel(0, host_base + HOST_CTRL);
 
        /* init ports */
-       for (i = 0; i < n_ports; i++) {
+       for (i = 0; i < host->n_ports; i++) {
                void __iomem *port = port_base + i * PORT_REGS_SIZE;
 
                /* Initial PHY setting */
@@ -993,12 +984,12 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
                                                PORT_CS_PORT_RST,
                                                PORT_CS_PORT_RST, 10, 100);
                        if (tmp & PORT_CS_PORT_RST)
-                               dev_printk(KERN_ERR, &pdev->dev,
+                               dev_printk(KERN_ERR, host->dev,
                                           "failed to clear port RST\n");
                }
 
                /* Configure IRQ WoC */
-               if (port_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+               if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC)
                        writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
                else
                        writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
@@ -1026,18 +1017,17 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
 static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version = 0;
-       struct device *dev = &pdev->dev;
-       unsigned int board_id = (unsigned int)ent->driver_data;
-       struct ata_port_info *pinfo = &sil24_port_info[board_id];
-       struct ata_probe_ent *probe_ent;
-       void __iomem *host_base;
-       void __iomem *port_base;
+       struct ata_port_info pi = sil24_port_info[ent->driver_data];
+       const struct ata_port_info *ppi[] = { &pi, NULL };
+       void __iomem * const *iomap;
+       struct ata_host *host;
        int i, rc;
        u32 tmp;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* acquire resources */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -1047,33 +1037,36 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                                DRV_NAME);
        if (rc)
                return rc;
+       iomap = pcim_iomap_table(pdev);
 
-       /* allocate & init probe_ent */
-       probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (!probe_ent)
-               return -ENOMEM;
+       /* apply workaround for completion IRQ loss on PCI-X errata */
+       if (pi.flags & SIL24_FLAG_PCIX_IRQ_WOC) {
+               tmp = readl(iomap[SIL24_HOST_BAR] + HOST_CTRL);
+               if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
+                       dev_printk(KERN_INFO, &pdev->dev,
+                                  "Applying completion IRQ loss on PCI-X "
+                                  "errata fix\n");
+               else
+                       pi.flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
+       }
 
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
+       /* allocate and fill host */
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi,
+                                   SIL24_FLAG2NPORTS(ppi[0]->flags));
+       if (!host)
+               return -ENOMEM;
+       host->iomap = iomap;
 
-       probe_ent->sht          = pinfo->sht;
-       probe_ent->port_flags   = pinfo->flags;
-       probe_ent->pio_mask     = pinfo->pio_mask;
-       probe_ent->mwdma_mask   = pinfo->mwdma_mask;
-       probe_ent->udma_mask    = pinfo->udma_mask;
-       probe_ent->port_ops     = pinfo->port_ops;
-       probe_ent->n_ports      = SIL24_FLAG2NPORTS(pinfo->flags);
+       for (i = 0; i < host->n_ports; i++) {
+               void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE;
 
-       probe_ent->irq = pdev->irq;
-       probe_ent->irq_flags = IRQF_SHARED;
-       probe_ent->iomap = pcim_iomap_table(pdev);
+               host->ports[i]->ioaddr.cmd_addr = port;
+               host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL;
 
-       host_base = probe_ent->iomap[SIL24_HOST_BAR];
-       port_base = probe_ent->iomap[SIL24_PORT_BAR];
+               ata_std_ports(&host->ports[i]->ioaddr);
+       }
 
-       /*
-        * Configure the device
-        */
+       /* configure and activate the device */
        if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
                rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
                if (rc) {
@@ -1099,36 +1092,11 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
-       /* Apply workaround for completion IRQ loss on PCI-X errata */
-       if (probe_ent->port_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
-               tmp = readl(host_base + HOST_CTRL);
-               if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
-                       dev_printk(KERN_INFO, &pdev->dev,
-                                  "Applying completion IRQ loss on PCI-X "
-                                  "errata fix\n");
-               else
-                       probe_ent->port_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
-       }
-
-       for (i = 0; i < probe_ent->n_ports; i++) {
-               void __iomem *port = port_base + i * PORT_REGS_SIZE;
-
-               probe_ent->port[i].cmd_addr = port;
-               probe_ent->port[i].scr_addr = port + PORT_SCONTROL;
-
-               ata_std_ports(&probe_ent->port[i]);
-       }
-
-       sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
-                             host_base, port_base);
+       sil24_init_controller(host);
 
        pci_set_master(pdev);
-
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(dev, probe_ent);
-       return 0;
+       return ata_host_activate(host, pdev->irq, sil24_interrupt, IRQF_SHARED,
+                                &sil24_sht);
 }
 
 #ifdef CONFIG_PM
@@ -1136,7 +1104,6 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
        void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
-       void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
@@ -1146,8 +1113,7 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)
        if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
                writel(HOST_CTRL_GLOBAL_RST, host_base + HOST_CTRL);
 
-       sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags,
-                             host_base, port_base);
+       sil24_init_controller(host);
 
        ata_host_resume(host);
 
index a787f0d4a5baeea3d9da9f2c63dd025e9f078d92..d8ee062e82fce91fafc91348296bc3ec75e930b9 100644 (file)
@@ -121,7 +121,6 @@ static const struct ata_port_operations sis_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -131,7 +130,6 @@ static const struct ata_port_operations sis_ops = {
 };
 
 static struct ata_port_info sis_port_info = {
-       .sht            = &sis_sht,
        .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
        .pio_mask       = 0x1f,
        .mwdma_mask     = 0x7,
@@ -256,12 +254,13 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
 static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
-       struct ata_probe_ent *probe_ent = NULL;
-       int rc;
+       struct ata_port_info pi = sis_port_info;
+       const struct ata_port_info *ppi[2] = { &pi, &pi };
+       struct ata_host *host;
        u32 genctl, val;
-       struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi };
        u8 pmr;
        u8 port2_start = 0x20;
+       int rc;
 
        if (!printed_version++)
                dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
@@ -270,19 +269,6 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc) {
-               pcim_pin_device(pdev);
-               return rc;
-       }
-
-       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-       if (rc)
-               return rc;
-       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-       if (rc)
-               return rc;
-
        /* check and see if the SCRs are in IO space or PCI cfg space */
        pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
        if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
@@ -349,30 +335,26 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                break;
        }
 
-       probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-       if (!probe_ent)
-               return -ENOMEM;
+       rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
+       if (rc)
+               return rc;
 
-       if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) {
+       if (!(pi.flags & SIS_FLAG_CFGSCR)) {
                void __iomem *mmio;
 
-               mmio = pcim_iomap(pdev, SIS_SCR_PCI_BAR, 0);
-               if (!mmio)
-                       return -ENOMEM;
+               rc = pcim_iomap_regions(pdev, 1 << SIS_SCR_PCI_BAR, DRV_NAME);
+               if (rc)
+                       return rc;
+               mmio = host->iomap[SIS_SCR_PCI_BAR];
 
-               probe_ent->port[0].scr_addr = mmio;
-               probe_ent->port[1].scr_addr = mmio + port2_start;
+               host->ports[0]->ioaddr.scr_addr = mmio;
+               host->ports[1]->ioaddr.scr_addr = mmio + port2_start;
        }
 
        pci_set_master(pdev);
        pci_intx(pdev, 1);
-
-       if (!ata_device_add(probe_ent))
-               return -EIO;
-
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
-
+       return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+                                &sis_sht);
 }
 
 static int __init sis_init(void)
index b121195cc598c6a9f4dccd6bbe21580e187ad7c9..cc07aac10e8ce37a0ee818f5ec982b3fc602c509 100644 (file)
@@ -56,7 +56,9 @@
 #define DRV_VERSION    "2.1"
 
 enum {
-       K2_FLAG_NO_ATAPI_DMA            = (1 << 29),
+       /* ap->flags bits */
+       K2_FLAG_SATA_8_PORTS            = (1 << 24),
+       K2_FLAG_NO_ATAPI_DMA            = (1 << 25),
 
        /* Taskfile registers offsets */
        K2_SATA_TF_CMD_OFFSET           = 0x00,
@@ -90,17 +92,6 @@ enum {
        board_svw8                      = 1,
 };
 
-static const struct k2_board_info {
-       unsigned int            n_ports;
-       unsigned long           port_flags;
-} k2_board_info[] = {
-       /* board_svw4 */
-       { 4, K2_FLAG_NO_ATAPI_DMA },
-
-       /* board_svw8 */
-       { 8, K2_FLAG_NO_ATAPI_DMA },
-};
-
 static u8 k2_stat_check_status(struct ata_port *ap);
 
 
@@ -354,7 +345,6 @@ static const struct ata_port_operations k2_sata_ops = {
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -363,6 +353,28 @@ static const struct ata_port_operations k2_sata_ops = {
        .port_start             = ata_port_start,
 };
 
+static const struct ata_port_info k2_port_info[] = {
+       /* board_svw4 */
+       {
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA,
+               .pio_mask       = 0x1f,
+               .mwdma_mask     = 0x07,
+               .udma_mask      = 0x7f,
+               .port_ops       = &k2_sata_ops,
+       },
+       /* board_svw8 */
+       {
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA |
+                                 K2_FLAG_SATA_8_PORTS,
+               .pio_mask       = 0x1f,
+               .mwdma_mask     = 0x07,
+               .udma_mask      = 0x7f,
+               .port_ops       = &k2_sata_ops,
+       },
+};
+
 static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
 {
        port->cmd_addr          = base + K2_SATA_TF_CMD_OFFSET;
@@ -386,17 +398,24 @@ static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
 static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
-       struct device *dev = &pdev->dev;
-       struct ata_probe_ent *probe_ent;
+       const struct ata_port_info *ppi[] =
+               { &k2_port_info[ent->driver_data], NULL };
+       struct ata_host *host;
        void __iomem *mmio_base;
-       const struct k2_board_info *board_info =
-                       &k2_board_info[ent->driver_data];
-       int rc;
-       int i;
+       int n_ports, i, rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* allocate host */
+       n_ports = 4;
+       if (ppi[0]->flags & K2_FLAG_SATA_8_PORTS)
+               n_ports = 8;
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+       if (!host)
+               return -ENOMEM;
+
        /*
         * If this driver happens to only be useful on Apple's K2, then
         * we should check that here as it has a normal Serverworks ID
@@ -404,6 +423,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
+
        /*
         * Check if we have resources mapped at all (second function may
         * have been disabled by firmware)
@@ -417,6 +437,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                pcim_pin_device(pdev);
        if (rc)
                return rc;
+       host->iomap = pcim_iomap_table(pdev);
+       mmio_base = host->iomap[5];
+
+       /* different controllers have different number of ports - currently 4 or 8 */
+       /* All ports are on the same function. Multi-function device is no
+        * longer available. This should not be seen in any system. */
+       for (i = 0; i < host->n_ports; i++)
+               k2_sata_setup_port(&host->ports[i]->ioaddr,
+                                  mmio_base + i * K2_SATA_PORT_OFFSET);
 
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
@@ -425,38 +454,6 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        if (rc)
                return rc;
 
-       probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
-               return -ENOMEM;
-
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
-
-       probe_ent->sht = &k2_sata_sht;
-       probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                               ATA_FLAG_MMIO | board_info->port_flags;
-       probe_ent->port_ops = &k2_sata_ops;
-       probe_ent->n_ports = 4;
-       probe_ent->irq = pdev->irq;
-       probe_ent->irq_flags = IRQF_SHARED;
-       probe_ent->iomap = pcim_iomap_table(pdev);
-
-       /* We don't care much about the PIO/UDMA masks, but the core won't like us
-        * if we don't fill these
-        */
-       probe_ent->pio_mask = 0x1f;
-       probe_ent->mwdma_mask = 0x7;
-       probe_ent->udma_mask = 0x7f;
-
-       mmio_base = probe_ent->iomap[5];
-
-       /* different controllers have different number of ports - currently 4 or 8 */
-       /* All ports are on the same function. Multi-function device is no
-        * longer available. This should not be seen in any system. */
-       for (i = 0; i < board_info->n_ports; i++)
-               k2_sata_setup_port(&probe_ent->port[i],
-                                  mmio_base + i * K2_SATA_PORT_OFFSET);
-
        /* Clear a magic bit in SCR1 according to Darwin, those help
         * some funky seagate drives (though so far, those were already
         * set by the firmware on the machines I had access to)
@@ -469,12 +466,8 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
 
        pci_set_master(pdev);
-
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(dev, probe_ent);
-       return 0;
+       return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+                                &k2_sata_sht);
 }
 
 /* 0x240 is device ID for Apple K2 device
index 1a081c3a8c06a24b3cd4ba51e6d643435ed2ca21..3a4f44559d0ae556176ac908c89989487ba75654 100644 (file)
@@ -151,24 +151,23 @@ struct pdc_host_priv {
 
 
 static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance);
 static void pdc_eng_timeout(struct ata_port *ap);
 static void pdc_20621_phy_reset (struct ata_port *ap);
 static int pdc_port_start(struct ata_port *ap);
 static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
 static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
+static unsigned int pdc20621_dimm_init(struct ata_host *host);
+static int pdc20621_detect_dimm(struct ata_host *host);
+static unsigned int pdc20621_i2c_read(struct ata_host *host,
                                      u32 device, u32 subaddr, u32 *pdata);
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
+static int pdc20621_prog_dimm0(struct ata_host *host);
+static unsigned int pdc20621_prog_dimm_global(struct ata_host *host);
 #ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
+static void pdc20621_get_from_dimm(struct ata_host *host,
                                   void *psource, u32 offset, u32 size);
 #endif
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
+static void pdc20621_put_to_dimm(struct ata_host *host,
                                 void *psource, u32 offset, u32 size);
 static void pdc20621_irq_clear(struct ata_port *ap);
 static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
@@ -204,7 +203,6 @@ static const struct ata_port_operations pdc_20621_ops = {
        .qc_issue               = pdc20621_qc_issue_prot,
        .data_xfer              = ata_data_xfer,
        .eng_timeout            = pdc_eng_timeout,
-       .irq_handler            = pdc20621_interrupt,
        .irq_clear              = pdc20621_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -214,7 +212,6 @@ static const struct ata_port_operations pdc_20621_ops = {
 static const struct ata_port_info pdc_port_info[] = {
        /* board_20621 */
        {
-               .sht            = &pdc_sata_sht,
                .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_SRST | ATA_FLAG_MMIO |
                                  ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
@@ -882,15 +879,15 @@ static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base)
 
 
 #ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
+static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
                                   u32 offset, u32 size)
 {
        u32 window_size;
        u16 idx;
        u8 page_mask;
        long dist;
-       void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
-       void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
+       void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+       void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
 
        /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
@@ -937,15 +934,15 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
 #endif
 
 
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
+static void pdc20621_put_to_dimm(struct ata_host *host, void *psource,
                                 u32 offset, u32 size)
 {
        u32 window_size;
        u16 idx;
        u8 page_mask;
        long dist;
-       void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
-       void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
+       void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+       void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
 
        /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
@@ -987,10 +984,10 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
 }
 
 
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
+static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device,
                                      u32 subaddr, u32 *pdata)
 {
-       void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+       void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
        u32 i2creg  = 0;
        u32 status;
        u32 count =0;
@@ -1023,17 +1020,17 @@ static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
 }
 
 
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
+static int pdc20621_detect_dimm(struct ata_host *host)
 {
        u32 data=0 ;
-       if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+       if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
                             PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
                if (data == 100)
                        return 100;
        } else
                return 0;
 
-       if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
+       if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
                if(data <= 0x75)
                        return 133;
        } else
@@ -1043,13 +1040,13 @@ static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
 }
 
 
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
+static int pdc20621_prog_dimm0(struct ata_host *host)
 {
        u32 spd0[50];
        u32 data = 0;
        int size, i;
        u8 bdimmsize;
-       void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+       void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
        static const struct {
                unsigned int reg;
                unsigned int ofs;
@@ -1072,7 +1069,7 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
        mmio += PDC_CHIP0_OFS;
 
        for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
-               pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+               pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
                                  pdc_i2c_read_data[i].reg,
                                  &spd0[pdc_i2c_read_data[i].ofs]);
 
@@ -1108,11 +1105,11 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
 }
 
 
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
+static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
 {
        u32 data, spd0;
        int error, i;
-       void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+       void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
 
        /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
@@ -1129,7 +1126,7 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
        readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
 
        /* Turn on for ECC */
-       pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+       pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
                          PDC_DIMM_SPD_TYPE, &spd0);
        if (spd0 == 0x02) {
                data |= (0x01 << 16);
@@ -1156,7 +1153,7 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
 }
 
 
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
+static unsigned int pdc20621_dimm_init(struct ata_host *host)
 {
        int speed, size, length;
        u32 addr,spd0,pci_status;
@@ -1166,7 +1163,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
        u32 ticks=0;
        u32 clock=0;
        u32 fparam=0;
-       void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+       void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
 
        /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
@@ -1225,18 +1222,18 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
           Read SPD of DIMM by I2C interface,
           and program the DIMM Module Controller.
        */
-       if (!(speed = pdc20621_detect_dimm(pe))) {
+       if (!(speed = pdc20621_detect_dimm(host))) {
                printk(KERN_ERR "Detect Local DIMM Fail\n");
                return 1;       /* DIMM error */
        }
        VPRINTK("Local DIMM Speed = %d\n", speed);
 
        /* Programming DIMM0 Module Control Register (index_CID0:80h) */
-       size = pdc20621_prog_dimm0(pe);
+       size = pdc20621_prog_dimm0(host);
        VPRINTK("Local DIMM Size = %dMB\n",size);
 
        /* Programming DIMM Module Global Control Register (index_CID0:88h) */
-       if (pdc20621_prog_dimm_global(pe)) {
+       if (pdc20621_prog_dimm_global(host)) {
                printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
                return 1;
        }
@@ -1249,20 +1246,20 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
                                '9','8','0','3','1','6','1','2',0,0};
                u8 test_parttern2[40] = {0};
 
-               pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
-               pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
+               pdc20621_put_to_dimm(host, (void *) test_parttern2, 0x10040, 40);
+               pdc20621_put_to_dimm(host, (void *) test_parttern2, 0x40, 40);
 
-               pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
-               pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+               pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x10040, 40);
+               pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40);
                printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
                       test_parttern2[1], &(test_parttern2[2]));
-               pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
+               pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x10040,
                                       40);
                printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
                       test_parttern2[1], &(test_parttern2[2]));
 
-               pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
-               pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+               pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x40, 40);
+               pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40);
                printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
                       test_parttern2[1], &(test_parttern2[2]));
        }
@@ -1270,14 +1267,14 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
 
        /* ECC initiliazation. */
 
-       pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+       pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
                          PDC_DIMM_SPD_TYPE, &spd0);
        if (spd0 == 0x02) {
                VPRINTK("Start ECC initialization\n");
                addr = 0;
                length = size * 1024 * 1024;
                while (addr < length) {
-                       pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
+                       pdc20621_put_to_dimm(host, (void *) &tmp, addr,
                                             sizeof(u32));
                        addr += sizeof(u32);
                }
@@ -1287,10 +1284,10 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
 }
 
 
-static void pdc_20621_init(struct ata_probe_ent *pe)
+static void pdc_20621_init(struct ata_host *host)
 {
        u32 tmp;
-       void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+       void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
 
        /* hard-code chip #0 */
        mmio += PDC_CHIP0_OFS;
@@ -1321,15 +1318,25 @@ static void pdc_20621_init(struct ata_probe_ent *pe)
 static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
-       struct ata_probe_ent *probe_ent;
+       const struct ata_port_info *ppi[] =
+               { &pdc_port_info[ent->driver_data], NULL };
+       struct ata_host *host;
        void __iomem *base;
        struct pdc_host_priv *hpriv;
-       unsigned int board_idx = (unsigned int) ent->driver_data;
        int rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* allocate host */
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
+       hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+       if (!host || !hpriv)
+               return -ENOMEM;
+
+       host->private_data = hpriv;
+
+       /* acquire resources and fill host */
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
@@ -1340,7 +1347,15 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
                pcim_pin_device(pdev);
        if (rc)
                return rc;
+       host->iomap = pcim_iomap_table(pdev);
+
+       base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
+       pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200);
+       pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280);
+       pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300);
+       pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380);
 
+       /* configure and activate */
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
                return rc;
@@ -1348,50 +1363,13 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
        if (rc)
                return rc;
 
-       probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
+       if (pdc20621_dimm_init(host))
                return -ENOMEM;
-
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
-
-       hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
-       if (!hpriv)
-               return -ENOMEM;
-
-       probe_ent->sht          = pdc_port_info[board_idx].sht;
-       probe_ent->port_flags   = pdc_port_info[board_idx].flags;
-       probe_ent->pio_mask     = pdc_port_info[board_idx].pio_mask;
-       probe_ent->mwdma_mask   = pdc_port_info[board_idx].mwdma_mask;
-       probe_ent->udma_mask    = pdc_port_info[board_idx].udma_mask;
-       probe_ent->port_ops     = pdc_port_info[board_idx].port_ops;
-
-               probe_ent->irq = pdev->irq;
-               probe_ent->irq_flags = IRQF_SHARED;
-       probe_ent->iomap = pcim_iomap_table(pdev);
-
-       probe_ent->private_data = hpriv;
-       base = probe_ent->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
-
-       probe_ent->n_ports = 4;
-       pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
-       pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
-       pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
-       pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
+       pdc_20621_init(host);
 
        pci_set_master(pdev);
-
-       /* initialize adapter */
-       /* initialize local dimm */
-       if (pdc20621_dimm_init(probe_ent))
-               return -ENOMEM;
-       pdc_20621_init(probe_ent);
-
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
+       return ata_host_activate(host, pdev->irq, pdc20621_interrupt,
+                                IRQF_SHARED, &pdc_sata_sht);
 }
 
 
index d659ace80f4f6c985f6da071a61b9d42ff93b8a5..f74e383de08303546259f0d1f817c77043788000 100644 (file)
@@ -115,7 +115,6 @@ static const struct ata_port_operations uli_ops = {
        .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -127,7 +126,6 @@ static const struct ata_port_operations uli_ops = {
 };
 
 static struct ata_port_info uli_port_info = {
-       .sht            = &uli_sht,
        .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                          ATA_FLAG_IGN_SIMPLEX,
        .pio_mask       = 0x1f,         /* pio0-4 */
@@ -185,12 +183,13 @@ static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
-       struct ata_probe_ent *probe_ent;
-       struct ata_port_info *ppi[2];
-       int rc;
+       const struct ata_port_info *ppi[] = { &uli_port_info, NULL };
        unsigned int board_idx = (unsigned int) ent->driver_data;
+       struct ata_host *host;
        struct uli_priv *hpriv;
        void __iomem * const *iomap;
+       struct ata_ioports *ioaddr;
+       int n_ports, rc;
 
        if (!printed_version++)
                dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
@@ -199,54 +198,42 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc) {
-               pcim_pin_device(pdev);
-               return rc;
-       }
-
-       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-       if (rc)
-               return rc;
-       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+       n_ports = 2;
+       if (board_idx == uli_5287)
+               n_ports = 4;
+       rc = ata_pci_prepare_native_host(pdev, ppi, n_ports, &host);
        if (rc)
                return rc;
 
-       ppi[0] = ppi[1] = &uli_port_info;
-       probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-       if (!probe_ent)
-               return -ENOMEM;
-
        hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
        if (!hpriv)
                return -ENOMEM;
+       host->private_data = hpriv;
 
-       probe_ent->private_data = hpriv;
-
-       iomap = pcim_iomap_table(pdev);
+       iomap = host->iomap;
 
        switch (board_idx) {
        case uli_5287:
                hpriv->scr_cfg_addr[0] = ULI5287_BASE;
                hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
-                       probe_ent->n_ports = 4;
 
-               probe_ent->port[2].cmd_addr = iomap[0] + 8;
-               probe_ent->port[2].altstatus_addr =
-               probe_ent->port[2].ctl_addr = (void __iomem *)
+               ioaddr = &host->ports[2]->ioaddr;
+               ioaddr->cmd_addr = iomap[0] + 8;
+               ioaddr->altstatus_addr =
+               ioaddr->ctl_addr = (void __iomem *)
                        ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4;
-               probe_ent->port[2].bmdma_addr = iomap[4] + 16;
+               ioaddr->bmdma_addr = iomap[4] + 16;
                hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
+               ata_std_ports(ioaddr);
 
-               probe_ent->port[3].cmd_addr = iomap[2] + 8;
-               probe_ent->port[3].altstatus_addr =
-               probe_ent->port[3].ctl_addr = (void __iomem *)
+               ioaddr = &host->ports[3]->ioaddr;
+               ioaddr->cmd_addr = iomap[2] + 8;
+               ioaddr->altstatus_addr =
+               ioaddr->ctl_addr = (void __iomem *)
                        ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4;
-               probe_ent->port[3].bmdma_addr = iomap[4] + 24;
+               ioaddr->bmdma_addr = iomap[4] + 24;
                hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
-
-               ata_std_ports(&probe_ent->port[2]);
-               ata_std_ports(&probe_ent->port[3]);
+               ata_std_ports(ioaddr);
                break;
 
        case uli_5289:
@@ -266,12 +253,8 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_master(pdev);
        pci_intx(pdev, 1);
-
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
+       return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+                                &uli_sht);
 }
 
 static int __init uli_init(void)
index 598e6a26a481a7934d8ae14121e395844c1f22dd..1d855f55f5f710edd378110740b76042afe37005 100644 (file)
@@ -64,8 +64,6 @@ enum {
        PORT0                   = (1 << 1),
        PORT1                   = (1 << 0),
        ALL_PORTS               = PORT0 | PORT1,
-       PATA_PORT               = 2,    /* PATA is port 2 */
-       N_PORTS                 = 3,
 
        NATIVE_MODE_ALL         = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
 
@@ -78,11 +76,9 @@ static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void svia_noop_freeze(struct ata_port *ap);
 static void vt6420_error_handler(struct ata_port *ap);
-static void vt6421_sata_error_handler(struct ata_port *ap);
-static void vt6421_pata_error_handler(struct ata_port *ap);
+static int vt6421_pata_cable_detect(struct ata_port *ap);
 static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
 static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
-static int vt6421_port_start(struct ata_port *ap);
 
 static const struct pci_device_id svia_pci_tbl[] = {
        { PCI_VDEVICE(VIA, 0x5337), vt6420 },
@@ -141,7 +137,6 @@ static const struct ata_port_operations vt6420_sata_ops = {
        .error_handler          = vt6420_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -172,15 +167,15 @@ static const struct ata_port_operations vt6421_pata_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = vt6421_pata_error_handler,
+       .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = vt6421_pata_cable_detect,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
 
-       .port_start             = vt6421_port_start,
+       .port_start             = ata_port_start,
 };
 
 static const struct ata_port_operations vt6421_sata_ops = {
@@ -203,10 +198,10 @@ static const struct ata_port_operations vt6421_sata_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = vt6421_sata_error_handler,
+       .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_sata,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -214,11 +209,10 @@ static const struct ata_port_operations vt6421_sata_ops = {
        .scr_read               = svia_scr_read,
        .scr_write              = svia_scr_write,
 
-       .port_start             = vt6421_port_start,
+       .port_start             = ata_port_start,
 };
 
-static struct ata_port_info vt6420_port_info = {
-       .sht            = &svia_sht,
+static const struct ata_port_info vt6420_port_info = {
        .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
        .pio_mask       = 0x1f,
        .mwdma_mask     = 0x07,
@@ -226,6 +220,22 @@ static struct ata_port_info vt6420_port_info = {
        .port_ops       = &vt6420_sata_ops,
 };
 
+static struct ata_port_info vt6421_sport_info = {
+       .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+       .pio_mask       = 0x1f,
+       .mwdma_mask     = 0x07,
+       .udma_mask      = 0x7f,
+       .port_ops       = &vt6421_sata_ops,
+};
+
+static struct ata_port_info vt6421_pport_info = {
+       .flags          = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY,
+       .pio_mask       = 0x1f,
+       .mwdma_mask     = 0,
+       .udma_mask      = 0x7f,
+       .port_ops       = &vt6421_pata_ops,
+};
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
 MODULE_LICENSE("GPL");
@@ -330,35 +340,15 @@ static void vt6420_error_handler(struct ata_port *ap)
                                  NULL, ata_std_postreset);
 }
 
-static int vt6421_pata_prereset(struct ata_port *ap)
+static int vt6421_pata_cable_detect(struct ata_port *ap)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u8 tmp;
 
        pci_read_config_byte(pdev, PATA_UDMA_TIMING, &tmp);
        if (tmp & 0x10)
-               ap->cbl = ATA_CBL_PATA40;
-       else
-               ap->cbl = ATA_CBL_PATA80;
-       return 0;
-}
-
-static void vt6421_pata_error_handler(struct ata_port *ap)
-{
-       return ata_bmdma_drive_eh(ap, vt6421_pata_prereset, ata_std_softreset,
-                                 NULL, ata_std_postreset);
-}
-
-static int vt6421_sata_prereset(struct ata_port *ap)
-{
-       ap->cbl = ATA_CBL_SATA;
-       return 0;
-}
-
-static void vt6421_sata_error_handler(struct ata_port *ap)
-{
-       return ata_bmdma_drive_eh(ap, vt6421_sata_prereset, ata_std_softreset,
-                                 NULL, ata_std_postreset);
+               return ATA_CBL_PATA40;
+       return ATA_CBL_PATA80;
 }
 
 static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
@@ -375,16 +365,6 @@ static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
        pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]);
 }
 
-static int vt6421_port_start(struct ata_port *ap)
-{
-       if (ap->port_no == PATA_PORT) {
-               ap->ops = &vt6421_pata_ops;
-               ap->mwdma_mask = 0;
-               ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST;
-       }
-       return ata_port_start(ap);
-}
-
 static const unsigned int svia_bar_sizes[] = {
        8, 4, 8, 4, 16, 256
 };
@@ -403,79 +383,78 @@ static void __iomem * vt6421_scr_addr(void __iomem *addr, unsigned int port)
        return addr + (port * 64);
 }
 
-static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
-                             void __iomem * const *iomap, unsigned int port)
+static void vt6421_init_addrs(struct ata_port *ap)
 {
-       void __iomem *reg_addr = iomap[port];
-       void __iomem *bmdma_addr = iomap[4] + (port * 8);
-
-       probe_ent->port[port].cmd_addr = reg_addr;
-       probe_ent->port[port].altstatus_addr =
-       probe_ent->port[port].ctl_addr = (void __iomem *)
+       void __iomem * const * iomap = ap->host->iomap;
+       void __iomem *reg_addr = iomap[ap->port_no];
+       void __iomem *bmdma_addr = iomap[4] + (ap->port_no * 8);
+       struct ata_ioports *ioaddr = &ap->ioaddr;
+
+       ioaddr->cmd_addr = reg_addr;
+       ioaddr->altstatus_addr =
+       ioaddr->ctl_addr = (void __iomem *)
                ((unsigned long)(reg_addr + 8) | ATA_PCI_CTL_OFS);
-       probe_ent->port[port].bmdma_addr = bmdma_addr;
-       probe_ent->port[port].scr_addr = vt6421_scr_addr(iomap[5], port);
+       ioaddr->bmdma_addr = bmdma_addr;
+       ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no);
 
-       ata_std_ports(&probe_ent->port[port]);
+       ata_std_ports(ioaddr);
 }
 
-static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
+static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
 {
-       struct ata_probe_ent *probe_ent;
-       struct ata_port_info *ppi[2];
-       void __iomem *bar5;
+       const struct ata_port_info *ppi[] = { &vt6420_port_info, NULL };
+       struct ata_host *host;
+       int rc;
 
-       ppi[0] = ppi[1] = &vt6420_port_info;
-       probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-       if (!probe_ent)
-               return NULL;
+       rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
+       if (rc)
+               return rc;
+       *r_host = host;
 
-       bar5 = pcim_iomap(pdev, 5, 0);
-       if (!bar5) {
+       rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+       if (rc) {
                dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n");
-               return NULL;
+               return rc;
        }
 
-       probe_ent->port[0].scr_addr = svia_scr_addr(bar5, 0);
-       probe_ent->port[1].scr_addr = svia_scr_addr(bar5, 1);
+       host->ports[0]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 0);
+       host->ports[1]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 1);
 
-       return probe_ent;
+       return 0;
 }
 
-static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
+static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
 {
-       struct ata_probe_ent *probe_ent;
-       unsigned int i;
+       const struct ata_port_info *ppi[] =
+               { &vt6421_sport_info, &vt6421_sport_info, &vt6421_pport_info };
+       struct ata_host *host;
+       int i, rc;
+
+       *r_host = host = ata_host_alloc_pinfo(&pdev->dev, ppi, ARRAY_SIZE(ppi));
+       if (!host) {
+               dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");
+               return -ENOMEM;
+       }
 
-       probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (!probe_ent)
-               return NULL;
-
-       memset(probe_ent, 0, sizeof(*probe_ent));
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
-
-       probe_ent->sht          = &svia_sht;
-       probe_ent->port_flags   = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY;
-       probe_ent->port_ops     = &vt6421_sata_ops;
-       probe_ent->n_ports      = N_PORTS;
-       probe_ent->irq          = pdev->irq;
-       probe_ent->irq_flags    = IRQF_SHARED;
-       probe_ent->pio_mask     = 0x1f;
-       probe_ent->mwdma_mask   = 0x07;
-       probe_ent->udma_mask    = 0x7f;
-
-       for (i = 0; i < 6; i++)
-               if (!pcim_iomap(pdev, i, 0)) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "failed to iomap PCI BAR %d\n", i);
-                       return NULL;
-               }
+       rc = pcim_iomap_regions(pdev, 0x1f, DRV_NAME);
+       if (rc) {
+               dev_printk(KERN_ERR, &pdev->dev, "failed to request/iomap "
+                          "PCI BARs (errno=%d)\n", rc);
+               return rc;
+       }
+       host->iomap = pcim_iomap_table(pdev);
 
-       for (i = 0; i < N_PORTS; i++)
-               vt6421_init_addrs(probe_ent, pcim_iomap_table(pdev), i);
+       for (i = 0; i < host->n_ports; i++)
+               vt6421_init_addrs(host->ports[i]);
 
-       return probe_ent;
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               return rc;
+       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               return rc;
+
+       return 0;
 }
 
 static void svia_configure(struct pci_dev *pdev)
@@ -522,7 +501,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        static int printed_version;
        unsigned int i;
        int rc;
-       struct ata_probe_ent *probe_ent;
+       struct ata_host *host;
        int board_id = (int) ent->driver_data;
        const int *bar_sizes;
        u8 tmp8;
@@ -534,12 +513,6 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc) {
-               pcim_pin_device(pdev);
-               return rc;
-       }
-
        if (board_id == vt6420) {
                pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
                if (tmp8 & SATA_2DEV) {
@@ -565,32 +538,18 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                        return -ENODEV;
                }
 
-       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-       if (rc)
-               return rc;
-       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-       if (rc)
-               return rc;
-
        if (board_id == vt6420)
-               probe_ent = vt6420_init_probe_ent(pdev);
+               rc = vt6420_prepare_host(pdev, &host);
        else
-               probe_ent = vt6421_init_probe_ent(pdev);
-
-       if (!probe_ent) {
-               dev_printk(KERN_ERR, &pdev->dev, "out of memory\n");
-               return -ENOMEM;
-       }
+               rc = vt6421_prepare_host(pdev, &host);
+       if (rc)
+               return rc;
 
        svia_configure(pdev);
 
        pci_set_master(pdev);
-
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
+       return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+                                &svia_sht);
 }
 
 static int __init svia_init(void)
index 170bad1b415b01765276b7578f6675804e7afb6d..80126f835d323897ec8ace75110cc3dbbc78d133 100644 (file)
@@ -333,7 +333,6 @@ static const struct ata_port_operations vsc_sata_ops = {
        .thaw                   = vsc_thaw,
        .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-       .irq_handler            = vsc_sata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
        .irq_ack                = ata_irq_ack,
@@ -367,30 +366,50 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
 
 static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+       static const struct ata_port_info pi = {
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_MMIO,
+               .pio_mask       = 0x1f,
+               .mwdma_mask     = 0x07,
+               .udma_mask      = 0x7f,
+               .port_ops       = &vsc_sata_ops,
+       };
+       const struct ata_port_info *ppi[] = { &pi, NULL };
        static int printed_version;
-       struct ata_probe_ent *probe_ent;
+       struct ata_host *host;
        void __iomem *mmio_base;
-       int rc;
+       int i, rc;
        u8 cls;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* allocate host */
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
+       if (!host)
+               return -ENOMEM;
+
        rc = pcim_enable_device(pdev);
        if (rc)
                return rc;
 
-       /*
-        * Check if we have needed resource mapped.
-        */
+       /* check if we have needed resource mapped */
        if (pci_resource_len(pdev, 0) == 0)
                return -ENODEV;
 
+       /* map IO regions and intialize host accordingly */
        rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME);
        if (rc == -EBUSY)
                pcim_pin_device(pdev);
        if (rc)
                return rc;
+       host->iomap = pcim_iomap_table(pdev);
+
+       mmio_base = host->iomap[VSC_MMIO_BAR];
+
+       for (i = 0; i < host->n_ports; i++)
+               vsc_sata_setup_port(&host->ports[i]->ioaddr,
+                                   mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET);
 
        /*
         * Use 32 bit DMA mask, because 64 bit address support is poor.
@@ -402,12 +421,6 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
        if (rc)
                return rc;
 
-       probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-       if (probe_ent == NULL)
-               return -ENOMEM;
-       probe_ent->dev = pci_dev_to_dev(pdev);
-       INIT_LIST_HEAD(&probe_ent->node);
-
        /*
         * Due to a bug in the chip, the default cache line size can't be
         * used (unless the default is non-zero).
@@ -418,33 +431,6 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
 
        if (pci_enable_msi(pdev) == 0)
                pci_intx(pdev, 0);
-       else
-               probe_ent->irq_flags = IRQF_SHARED;
-
-       probe_ent->sht = &vsc_sata_sht;
-       probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                               ATA_FLAG_MMIO;
-       probe_ent->port_ops = &vsc_sata_ops;
-       probe_ent->n_ports = 4;
-       probe_ent->irq = pdev->irq;
-       probe_ent->iomap = pcim_iomap_table(pdev);
-
-       /* We don't care much about the PIO/UDMA masks, but the core won't like us
-        * if we don't fill these
-        */
-       probe_ent->pio_mask = 0x1f;
-       probe_ent->mwdma_mask = 0x07;
-       probe_ent->udma_mask = 0x7f;
-
-       mmio_base = probe_ent->iomap[VSC_MMIO_BAR];
-
-       /* We have 4 ports per PCI function */
-       vsc_sata_setup_port(&probe_ent->port[0], mmio_base + 1 * VSC_SATA_PORT_OFFSET);
-       vsc_sata_setup_port(&probe_ent->port[1], mmio_base + 2 * VSC_SATA_PORT_OFFSET);
-       vsc_sata_setup_port(&probe_ent->port[2], mmio_base + 3 * VSC_SATA_PORT_OFFSET);
-       vsc_sata_setup_port(&probe_ent->port[3], mmio_base + 4 * VSC_SATA_PORT_OFFSET);
-
-       pci_set_master(pdev);
 
        /*
         * Config offset 0x98 is "Extended Control and Status Register 0"
@@ -454,11 +440,9 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
         */
        pci_write_config_dword(pdev, 0x98, 0);
 
-       if (!ata_device_add(probe_ent))
-               return -ENODEV;
-
-       devm_kfree(&pdev->dev, probe_ent);
-       return 0;
+       pci_set_master(pdev);
+       return ata_host_activate(host, pdev->irq, vsc_sata_interrupt,
+                                IRQF_SHARED, &vsc_sata_sht);
 }
 
 static const struct pci_device_id vsc_sata_pci_tbl[] = {
index 8dcf9d20f44985be7cbf707bee14e5e20af6a077..c70d52ace8b2da72237bbe7bd38a1f36a6d3d726 100644 (file)
@@ -202,13 +202,16 @@ static struct miscdevice briq_panel_miscdev = {
 
 static int __init briq_panel_init(void)
 {
-       struct device_node *root = find_path_device("/");
+       struct device_node *root = of_find_node_by_path("/");
        const char *machine;
        int i;
 
        machine = get_property(root, "model", NULL);
-       if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0)
+       if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
+               of_node_put(root);
                return -ENODEV;
+       }
+       of_node_put(root);
 
        printk(KERN_INFO
                "briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
index a0a88aa23f5b751457e01470afbe6f06068678c9..0f9ed7b46a6df81bb1332b1a048a2c475028cb00 100644 (file)
@@ -47,8 +47,6 @@
 #define HVC_MAJOR      229
 #define HVC_MINOR      0
 
-#define TIMEOUT                (10)
-
 /*
  * Wait this long per iteration while trying to push buffered data to the
  * hypervisor before allowing the tty to complete a close operation.
@@ -104,12 +102,12 @@ static DEFINE_SPINLOCK(hvc_structs_lock);
 /*
  * This value is used to assign a tty->index value to a hvc_struct based
  * upon order of exposure via hvc_probe(), when we can not match it to
- * a console canidate registered with hvc_instantiate().
+ * a console candidate registered with hvc_instantiate().
  */
 static int last_hvc = -1;
 
 /*
- * Do not call this function with either the hvc_strucst_lock or the hvc_struct
+ * Do not call this function with either the hvc_structs_lock or the hvc_struct
  * lock held.  If successful, this function increments the kobject reference
  * count against the target hvc_struct so it should be released when finished.
  */
@@ -162,7 +160,7 @@ void hvc_console_print(struct console *co, const char *b, unsigned count)
        if (index >= MAX_NR_HVC_CONSOLES)
                return;
 
-       /* This console adapter was removed so it is not useable. */
+       /* This console adapter was removed so it is not usable. */
        if (vtermnos[index] < 0)
                return;
 
@@ -220,7 +218,7 @@ struct console hvc_con_driver = {
 };
 
 /*
- * Early console initialization.  Preceeds driver initialization.
+ * Early console initialization.  Precedes driver initialization.
  *
  * (1) we are first, and the user specified another driver
  * -- index will remain -1
@@ -257,7 +255,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
        if (vtermnos[index] != -1)
                return -1;
 
-       /* make sure no no tty has been registerd in this index */
+       /* make sure no no tty has been registered in this index */
        hp = hvc_get_by_index(index);
        if (hp) {
                kobject_put(&hp->kobj);
@@ -267,7 +265,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
        vtermnos[index] = vtermno;
        cons_ops[index] = ops;
 
-       /* reserve all indices upto and including this index */
+       /* reserve all indices up to and including this index */
        if (last_hvc < index)
                last_hvc = index;
 
@@ -528,7 +526,7 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
 
 /*
  * This is actually a contract between the driver and the tty layer outlining
- * how much write room the driver can guarentee will be sent OR BUFFERED.  This
+ * how much write room the driver can guarantee will be sent OR BUFFERED.  This
  * driver MUST honor the return value.
  */
 static int hvc_write_room(struct tty_struct *tty)
@@ -550,6 +548,18 @@ static int hvc_chars_in_buffer(struct tty_struct *tty)
        return hp->n_outbuf;
 }
 
+/*
+ * timeout will vary between the MIN and MAX values defined here.  By default
+ * and during console activity we will use a default MIN_TIMEOUT of 10.  When
+ * the console is idle, we increase the timeout value on each pass through
+ * msleep until we reach the max.  This may be noticeable as a brief (average
+ * one second) delay on the console before the console responds to input when
+ * there has been no input for some time.
+ */
+#define MIN_TIMEOUT            (10)
+#define MAX_TIMEOUT            (2000)
+static u32 timeout = MIN_TIMEOUT;
+
 #define HVC_POLL_READ  0x00000001
 #define HVC_POLL_WRITE 0x00000002
 
@@ -642,9 +652,14 @@ static int hvc_poll(struct hvc_struct *hp)
  bail:
        spin_unlock_irqrestore(&hp->lock, flags);
 
-       if (read_total)
+       if (read_total) {
+               /* Activity is occurring, so reset the polling backoff value to
+                  a minimum for performance. */
+               timeout = MIN_TIMEOUT;
+
                tty_flip_buffer_push(tty);
-       
+       }
+
        return poll_mask;
 }
 
@@ -688,8 +703,12 @@ int khvcd(void *unused)
                if (!hvc_kicked) {
                        if (poll_mask == 0)
                                schedule();
-                       else
-                               msleep_interruptible(TIMEOUT);
+                       else {
+                               if (timeout < MAX_TIMEOUT)
+                                       timeout += (timeout >> 6) + 1;
+
+                               msleep_interruptible(timeout);
+                       }
                }
                __set_current_state(TASK_RUNNING);
        } while (!kthread_should_stop());
@@ -794,7 +813,7 @@ int __devexit hvc_remove(struct hvc_struct *hp)
 
        /*
         * We 'put' the instance that was grabbed when the kobject instance
-        * was intialized using kobject_init().  Let the last holder of this
+        * was initialized using kobject_init().  Let the last holder of this
         * kobject cause it to be removed, which will probably be the tty_hangup
         * below.
         */
@@ -850,7 +869,7 @@ int __init hvc_init(void)
 }
 module_init(hvc_init);
 
-/* This isn't particularily necessary due to this being a console driver
+/* This isn't particularly necessary due to this being a console driver
  * but it is nice to be thorough.
  */
 static void __exit hvc_exit(void)
index f144a947bd17aaa8549230e307c13def30296822..ec420fe8a9089f5a2f4be1201b6dbd5d7307fb8c 100644 (file)
@@ -575,7 +575,7 @@ static int hvc_find_vtys(void)
                                (num_found >= VTTY_PORTS))
                        break;
 
-               vtermno = get_property(vty, "reg", NULL);
+               vtermno = of_get_property(vty, "reg", NULL);
                if (!vtermno)
                        continue;
 
index f9c00844d2bfe9250448e0436421085f4b220d8a..94a542e20efb02eb07beb1266567e444b396219f 100644 (file)
@@ -153,7 +153,7 @@ static int hvc_find_vtys(void)
                if (num_found >= MAX_NR_HVC_CONSOLES)
                        break;
 
-               vtermno = get_property(vty, "reg", NULL);
+               vtermno = of_get_property(vty, "reg", NULL);
                if (!vtermno)
                        continue;
 
index 50315d6364fdd98727133c9fa7930ea0aa755d0f..d5a752da322f855261a06c9aacb93636fb57d1f9 100644 (file)
@@ -1279,8 +1279,8 @@ static int __init hvsi_console_init(void)
                struct hvsi_struct *hp;
                const uint32_t *vtermno, *irq;
 
-               vtermno = get_property(vty, "reg", NULL);
-               irq = get_property(vty, "interrupts", NULL);
+               vtermno = of_get_property(vty, "reg", NULL);
+               irq = of_get_property(vty, "interrupts", NULL);
                if (!vtermno || !irq)
                        continue;
 
index 78237577b05ac57790ac34aee0f601b8aae23aa7..3ef593a9015f1d298348cc44040000182ef7b63e 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * Sony Programmable I/O Control Device driver for VAIO
  *
+ * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
+ *
  * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
  *
  * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
@@ -95,6 +97,11 @@ module_param(useinput, int, 0444);
 MODULE_PARM_DESC(useinput,
                 "set this if you would like sonypi to feed events to the input subsystem");
 
+static int check_ioport = 1;
+module_param(check_ioport, int, 0444);
+MODULE_PARM_DESC(check_ioport,
+                "set this to 0 if you think the automatic ioport check for sony-laptop is wrong");
+
 #define SONYPI_DEVICE_MODEL_TYPE1      1
 #define SONYPI_DEVICE_MODEL_TYPE2      2
 #define SONYPI_DEVICE_MODEL_TYPE3      3
@@ -477,7 +484,7 @@ static struct sonypi_device {
        u16 evtype_offset;
        int camera_power;
        int bluetooth_power;
-       struct semaphore lock;
+       struct mutex lock;
        struct kfifo *fifo;
        spinlock_t fifo_lock;
        wait_queue_head_t fifo_proc_list;
@@ -884,7 +891,7 @@ int sonypi_camera_command(int command, u8 value)
        if (!camera)
                return -EIO;
 
-       down(&sonypi_device.lock);
+       mutex_lock(&sonypi_device.lock);
 
        switch (command) {
        case SONYPI_COMMAND_SETCAMERA:
@@ -919,7 +926,7 @@ int sonypi_camera_command(int command, u8 value)
                       command);
                break;
        }
-       up(&sonypi_device.lock);
+       mutex_unlock(&sonypi_device.lock);
        return 0;
 }
 
@@ -938,20 +945,20 @@ static int sonypi_misc_fasync(int fd, struct file *filp, int on)
 static int sonypi_misc_release(struct inode *inode, struct file *file)
 {
        sonypi_misc_fasync(-1, file, 0);
-       down(&sonypi_device.lock);
+       mutex_lock(&sonypi_device.lock);
        sonypi_device.open_count--;
-       up(&sonypi_device.lock);
+       mutex_unlock(&sonypi_device.lock);
        return 0;
 }
 
 static int sonypi_misc_open(struct inode *inode, struct file *file)
 {
-       down(&sonypi_device.lock);
+       mutex_lock(&sonypi_device.lock);
        /* Flush input queue on first open */
        if (!sonypi_device.open_count)
                kfifo_reset(sonypi_device.fifo);
        sonypi_device.open_count++;
-       up(&sonypi_device.lock);
+       mutex_unlock(&sonypi_device.lock);
        return 0;
 }
 
@@ -1001,7 +1008,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
        u8 val8;
        u16 val16;
 
-       down(&sonypi_device.lock);
+       mutex_lock(&sonypi_device.lock);
        switch (cmd) {
        case SONYPI_IOCGBRT:
                if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) {
@@ -1101,7 +1108,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
        default:
                ret = -EINVAL;
        }
-       up(&sonypi_device.lock);
+       mutex_unlock(&sonypi_device.lock);
        return ret;
 }
 
@@ -1260,6 +1267,28 @@ static int __devinit sonypi_create_input_devices(void)
 static int __devinit sonypi_setup_ioports(struct sonypi_device *dev,
                                const struct sonypi_ioport_list *ioport_list)
 {
+       /* try to detect if sony-laptop is being used and thus
+        * has already requested one of the known ioports.
+        * As in the deprecated check_region this is racy has we have
+        * multiple ioports available and one of them can be requested
+        * between this check and the subsequent request. Anyway, as an
+        * attempt to be some more user-friendly as we currently are,
+        * this is enough.
+        */
+       const struct sonypi_ioport_list *check = ioport_list;
+       while (check_ioport && check->port1) {
+               if (!request_region(check->port1,
+                                  sonypi_device.region_size,
+                                  "Sony Programable I/O Device Check")) {
+                       printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? "
+                                       "if not use check_ioport=0\n",
+                                       check->port1);
+                       return -EBUSY;
+               }
+               release_region(check->port1, sonypi_device.region_size);
+               check++;
+       }
+
        while (ioport_list->port1) {
 
                if (request_region(ioport_list->port1,
@@ -1321,6 +1350,10 @@ static int __devinit sonypi_probe(struct platform_device *dev)
        struct pci_dev *pcidev;
        int error;
 
+       printk(KERN_WARNING "sonypi: please try the sony-laptop module instead "
+                       "and report failures, see also "
+                       "http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n");
+
        spin_lock_init(&sonypi_device.fifo_lock);
        sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
                                         &sonypi_device.fifo_lock);
@@ -1330,7 +1363,7 @@ static int __devinit sonypi_probe(struct platform_device *dev)
        }
 
        init_waitqueue_head(&sonypi_device.fifo_proc_list);
-       init_MUTEX(&sonypi_device.lock);
+       mutex_init(&sonypi_device.lock);
        sonypi_device.bluetooth_power = -1;
 
        if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
index aefd683c60b7e6a0304c6a9b410b5e22647f8a86..3c852009196eab09c2cd97adec699771ca408536 100644 (file)
@@ -53,8 +53,8 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size)
        }
 
        reg = get_property(dn, "reg", &reglen);
-       naddrc = prom_n_addr_cells(dn);
-       nsizec = prom_n_size_cells(dn);
+       naddrc = of_n_addr_cells(dn);
+       nsizec = of_n_size_cells(dn);
 
        of_node_put(dn);
 
index e812aa129e289540c5edae8c9ffb83da5f1e8ad0..60198a78974c614277b74fc44a48599a10fbc561 100644 (file)
@@ -548,7 +548,7 @@ config MV64X60_WDT
        depends on WATCHDOG && MV64X60
 
 config BOOKE_WDT
-       tristate "PowerPC Book-E Watchdog Timer"
+       bool "PowerPC Book-E Watchdog Timer"
        depends on WATCHDOG && (BOOKE || 4xx)
        ---help---
          Please see Documentation/watchdog/watchdog-api.txt for
index 5ac309ee7f05c39d97f22c562bc3318aee85215c..5cfcff532545b019e3f984dbf3de5273b91d464b 100644 (file)
@@ -26,7 +26,7 @@
 /*
  * The I/O port the PMTMR resides at.
  * The location is detected during setup_arch(),
- * in arch/i386/acpi/boot.c
+ * in arch/i386/kernel/acpi/boot.c
  */
 u32 pmtmr_ioport __read_mostly;
 
index f1f0f5d0442cc53c5abfe2623f0015132ff29fb6..f5ebad5614126d966cfc7e637a6522fda5bf705d 100644 (file)
@@ -141,10 +141,10 @@ static void ams_worker(struct work_struct *work)
 int ams_sensor_attach(void)
 {
        int result;
-       u32 *prop;
+       const u32 *prop;
 
        /* Get orientation */
-       prop = (u32*)get_property(ams_info.of_node, "orientation", NULL);
+       prop = get_property(ams_info.of_node, "orientation", NULL);
        if (!prop)
                return -ENODEV;
        ams_info.orient1 = *prop;
index 0d24bdfea53e0a965f109fd5917019e701fb0d6f..485d333bcb3eadabd5b7ee8e5eb6b022cc5676f1 100644 (file)
@@ -263,7 +263,7 @@ int __init ams_i2c_init(struct device_node *np)
 {
        char *tmp_bus;
        int result;
-       u32 *prop;
+       const u32 *prop;
 
        mutex_lock(&ams_info.lock);
 
@@ -276,7 +276,7 @@ int __init ams_i2c_init(struct device_node *np)
        ams_info.bustype = BUS_I2C;
 
        /* look for bus either using "reg" or by path */
-       prop = (u32*)get_property(ams_info.of_node, "reg", NULL);
+       prop = get_property(ams_info.of_node, "reg", NULL);
        if (!prop) {
                result = -ENODEV;
 
index 4636ae031a53cb83b0e1fc1267629cab6746ddfb..1b01c215bfe7471c672557dd41303bee1979d46c 100644 (file)
@@ -146,7 +146,7 @@ static void ams_pmu_exit(void)
 
 int __init ams_pmu_init(struct device_node *np)
 {
-       u32 *prop;
+       const u32 *prop;
        int result;
 
        mutex_lock(&ams_info.lock);
@@ -160,7 +160,7 @@ int __init ams_pmu_init(struct device_node *np)
        ams_info.bustype = BUS_HOST;
 
        /* Get PMU command, should be 0x4e, but we can never know */
-       prop = (u32*)get_property(ams_info.of_node, "reg", NULL);
+       prop = get_property(ams_info.of_node, "reg", NULL);
        if (!prop) {
                result = -ENODEV;
                goto exit;
index 3b23d677cb8630508acd34d98b748149643685a0..4700085ba834a70f2000f316305831b267db18b0 100644 (file)
@@ -565,11 +565,11 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
                                const struct of_device_id *id)
 {
        struct ehca_shca *shca;
-       u64 *handle;
+       const u64 *handle;
        struct ib_pd *ibpd;
        int ret;
 
-       handle = (u64 *)get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
+       handle = get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
        if (!handle) {
                ehca_gen_err("Cannot get eHCA handle for adapter: %s.",
                             dev->ofdev.node->full_name);
index f729eebf771f80447fd64a42a3919d0fd52d888a..adfea3c7c62af3a2a8dca67a4b14a5eefa8e32e3 100644 (file)
@@ -90,7 +90,7 @@ static int autopoll_devs;
 int __adb_probe_sync;
 
 #ifdef CONFIG_PM
-static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static void adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
 static struct pmu_sleep_notifier adb_sleep_notifier = {
        adb_notify_sleep,
        SLEEP_LEVEL_ADB,
@@ -340,11 +340,9 @@ __initcall(adb_init);
 /*
  * notify clients before sleep and reset bus afterwards
  */
-int
+void
 adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
-       int ret;
-       
        switch (when) {
        case PBOOK_SLEEP_REQUEST:
                adb_got_sleep = 1;
@@ -353,22 +351,8 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
                /* Stop autopoll */
                if (adb_controller->autopoll)
                        adb_controller->autopoll(0);
-               ret = blocking_notifier_call_chain(&adb_client_list,
-                               ADB_MSG_POWERDOWN, NULL);
-               if (ret & NOTIFY_STOP_MASK) {
-                       up(&adb_probe_mutex);
-                       return PBOOK_SLEEP_REFUSE;
-               }
-               break;
-       case PBOOK_SLEEP_REJECT:
-               if (adb_got_sleep) {
-                       adb_got_sleep = 0;
-                       up(&adb_probe_mutex);
-                       adb_reset_bus();
-               }
-               break;
-               
-       case PBOOK_SLEEP_NOW:
+               blocking_notifier_call_chain(&adb_client_list,
+                       ADB_MSG_POWERDOWN, NULL);
                break;
        case PBOOK_WAKE:
                adb_got_sleep = 0;
@@ -376,14 +360,13 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
                adb_reset_bus();
                break;
        }
-       return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PM */
 
 static int
 do_adb_reset_bus(void)
 {
-       int ret, nret;
+       int ret;
        
        if (adb_controller == NULL)
                return -ENXIO;
@@ -391,13 +374,8 @@ do_adb_reset_bus(void)
        if (adb_controller->autopoll)
                adb_controller->autopoll(0);
 
-       nret = blocking_notifier_call_chain(&adb_client_list,
-                       ADB_MSG_PRE_RESET, NULL);
-       if (nret & NOTIFY_STOP_MASK) {
-               if (adb_controller->autopoll)
-                       adb_controller->autopoll(autopoll_devs);
-               return -EBUSY;
-       }
+       blocking_notifier_call_chain(&adb_client_list,
+               ADB_MSG_PRE_RESET, NULL);
 
        if (sleepy_trackpad) {
                /* Let the trackpad settle down */
@@ -427,10 +405,8 @@ do_adb_reset_bus(void)
        }
        up(&adb_handler_sem);
 
-       nret = blocking_notifier_call_chain(&adb_client_list,
-                       ADB_MSG_POST_RESET, NULL);
-       if (nret & NOTIFY_STOP_MASK)
-               return -EBUSY;
+       blocking_notifier_call_chain(&adb_client_list,
+               ADB_MSG_POST_RESET, NULL);
        
        return ret;
 }
index cdd5a0f72e3c108600b4e49057fd5899bbdd4a7c..e54c4d9f63650387649f55934b920741a1f07ccc 100644 (file)
@@ -145,11 +145,12 @@ anslcd_init(void)
        int retval;
        struct device_node* node;
 
-       node = find_devices("lcd");
-       if (!node || !node->parent)
-               return -ENODEV;
-       if (strcmp(node->parent->name, "gc"))
+       node = of_find_node_by_name(NULL, "lcd");
+       if (!node || !node->parent || strcmp(node->parent->name, "gc")) {
+               of_node_put(node);
                return -ENODEV;
+       }
+       of_node_put(node);
 
        anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20);
        
index c5e4d43f97fcbe89c4bf69853cb618d3c5bab578..cdb0bead99171f7a58198b3e62717612b87dc410 100644 (file)
@@ -96,7 +96,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
 static struct apm_user *       user_list;
 
-static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static void apm_notify_sleep(struct pmu_sleep_notifier *self, int when);
 static struct pmu_sleep_notifier apm_sleep_notifier = {
        apm_notify_sleep,
        SLEEP_LEVEL_USERLAND,
@@ -352,7 +352,7 @@ static int do_open(struct inode * inode, struct file * filp)
  * doesn't provide a way to NAK, but this could be added
  * here.
  */
-static int wait_all_suspend(void)
+static void wait_all_suspend(void)
 {
        DECLARE_WAITQUEUE(wait, current);
 
@@ -366,24 +366,19 @@ static int wait_all_suspend(void)
        remove_wait_queue(&apm_suspend_waitqueue, &wait);
 
        DBG("apm_emu: wait_all_suspend() - complete !\n");
-       
-       return 1;
 }
 
-static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when)
+static void apm_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
        switch(when) {
                case PBOOK_SLEEP_REQUEST:
                        queue_event(APM_SYS_SUSPEND, NULL);
-                       if (!wait_all_suspend())
-                               return PBOOK_SLEEP_REFUSE;
+                       wait_all_suspend();
                        break;
-               case PBOOK_SLEEP_REJECT:
                case PBOOK_WAKE:
                        queue_event(APM_NORMAL_RESUME, NULL);
                        break;
        }
-       return PBOOK_SLEEP_OK;
 }
 
 #define APM_CRITICAL           10
index c1fd816e9f09d282b9ec8cd5678dcb2c84ef3f1f..1599dc34f15fbbfd151ecc264680bfe20191ed95 100644 (file)
@@ -102,8 +102,6 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
        return 0;
 }
 
-EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons);
-
 static int emumousebtn_input_register(void)
 {
        int ret;
index 026b67f4f659f59fb55e9953dd87ba05952207e5..79119f56e82def706ce517bfdb8e9dcebc1eb3d3 100644 (file)
@@ -82,7 +82,14 @@ struct adb_driver macio_adb_driver = {
 
 int macio_probe(void)
 {
-       return find_compatible_devices("adb", "chrp,adb0")? 0: -ENODEV;
+       struct device_node *np;
+
+       np = of_find_compatible_node(NULL, "adb", "chrp,adb0");
+       if (np) {
+               of_node_put(np);
+               return 0;
+       }
+       return -ENODEV;
 }
 
 int macio_init(void)
@@ -91,12 +98,14 @@ int macio_init(void)
        struct resource r;
        unsigned int irq;
 
-       adbs = find_compatible_devices("adb", "chrp,adb0");
+       adbs = of_find_compatible_node(NULL, "adb", "chrp,adb0");
        if (adbs == 0)
                return -ENXIO;
 
-       if (of_address_to_resource(adbs, 0, &r))
+       if (of_address_to_resource(adbs, 0, &r)) {
+               of_node_put(adbs);
                return -ENXIO;
+       }
        adb = ioremap(r.start, sizeof(struct adb_regs));
 
        out_8(&adb->ctrl.r, 0);
@@ -107,6 +116,7 @@ int macio_init(void)
        out_8(&adb->autopoll.r, APE);
 
        irq = irq_of_parse_and_map(adbs, 0);
+       of_node_put(adbs);
        if (request_irq(irq, macio_adb_interrupt, 0, "ADB", (void *)0)) {
                printk(KERN_ERR "ADB: can't get irq %d\n", irq);
                return -EAGAIN;
index d56216067549397e1c88041e3697e5f8349d425c..c96b7fe882a450ccfaae4d9fe8c6d0c084077876 100644 (file)
@@ -134,108 +134,12 @@ static int macio_device_resume(struct device * dev)
        return 0;
 }
 
-static int macio_uevent(struct device *dev, char **envp, int num_envp,
-                          char *buffer, int buffer_size)
-{
-       struct macio_dev * macio_dev;
-       struct of_device * of;
-       char *scratch;
-       const char *compat, *compat2;
-
-       int i = 0;
-       int length, cplen, cplen2, seen = 0;
-
-       if (!dev)
-               return -ENODEV;
-
-       macio_dev = to_macio_device(dev);
-       if (!macio_dev)
-               return -ENODEV;
-
-       of = &macio_dev->ofdev;
-
-       /* stuff we want to pass to /sbin/hotplug */
-       envp[i++] = scratch = buffer;
-       length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name);
-       ++length;
-       buffer_size -= length;
-       if ((buffer_size <= 0) || (i >= num_envp))
-               return -ENOMEM;
-       scratch += length;
-
-       envp[i++] = scratch;
-       length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type);
-       ++length;
-       buffer_size -= length;
-       if ((buffer_size <= 0) || (i >= num_envp))
-               return -ENOMEM;
-       scratch += length;
-
-        /* Since the compatible field can contain pretty much anything
-         * it's not really legal to split it out with commas. We split it
-         * up using a number of environment variables instead. */
-
-       compat = get_property(of->node, "compatible", &cplen);
-       compat2 = compat;
-       cplen2= cplen;
-       while (compat && cplen > 0) {
-                envp[i++] = scratch;
-               length = scnprintf (scratch, buffer_size,
-                                    "OF_COMPATIBLE_%d=%s", seen, compat);
-               ++length;
-               buffer_size -= length;
-               if ((buffer_size <= 0) || (i >= num_envp))
-                       return -ENOMEM;
-               scratch += length;
-               length = strlen (compat) + 1;
-               compat += length;
-               cplen -= length;
-               seen++;
-       }
-
-       envp[i++] = scratch;
-       length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen);
-       ++length;
-       buffer_size -= length;
-       if ((buffer_size <= 0) || (i >= num_envp))
-               return -ENOMEM;
-       scratch += length;
-
-       envp[i++] = scratch;
-       length = scnprintf (scratch, buffer_size, "MODALIAS=of:N%sT%s",
-                       of->node->name, of->node->type);
-       /* overwrite '\0' */
-       buffer_size -= length;
-       if ((buffer_size <= 0) || (i >= num_envp))
-               return -ENOMEM;
-       scratch += length;
-
-       if (!compat2) {
-               compat2 = "";
-               cplen2 = 1;
-       }
-       while (cplen2 > 0) {
-               length = snprintf (scratch, buffer_size, "C%s", compat2);
-               buffer_size -= length;
-               if (buffer_size <= 0)
-                       return -ENOMEM;
-               scratch += length;
-               length = strlen (compat2) + 1;
-               compat2 += length;
-               cplen2 -= length;
-       }
-
-       envp[i] = NULL;
-
-       return 0;
-}
-
 extern struct device_attribute macio_dev_attrs[];
 
 struct bus_type macio_bus_type = {
        .name   = "macio",
        .match  = macio_bus_match,
-       .uevent = macio_uevent,
+       .uevent = of_device_uevent,
        .probe  = macio_device_probe,
        .remove = macio_device_remove,
        .shutdown = macio_device_shutdown,
@@ -491,7 +395,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
 #endif
                        MAX_NODE_NAME_SIZE, np->name);
        } else {
-               reg = get_property(np, "reg", NULL);
+               reg = of_get_property(np, "reg", NULL);
                sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s",
                        chip->lbus.index,
                        reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
index 8566bdfdd4b88a072c49dfc96e4b62aa730ab7c6..cc8267912656363a5e50545a3430b8523d09fcaa 100644 (file)
@@ -21,7 +21,7 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
        int length = 0;
 
        of = &to_macio_device (dev)->ofdev;
-       compat = get_property(of->node, "compatible", &cplen);
+       compat = of_get_property(of->node, "compatible", &cplen);
        if (!compat) {
                *buf = '\0';
                return 0;
@@ -47,18 +47,20 @@ static ssize_t modalias_show (struct device *dev, struct device_attribute *attr,
        int length;
 
        of = &to_macio_device (dev)->ofdev;
-       compat = get_property(of->node, "compatible", &cplen);
+       compat = of_get_property(of->node, "compatible", &cplen);
        if (!compat) compat = "", cplen = 1;
        length = sprintf (buf, "of:N%sT%s", of->node->name, of->node->type);
        buf += length;
        while (cplen > 0) {
                int l;
-               length += sprintf (buf, "C%s", compat);
-               buf += length;
+               l = sprintf (buf, "C%s", compat);
+               length += l;
+               buf += l;
                l = strlen (compat) + 1;
                compat += l;
                cplen -= l;
        }
+       length += sprintf(buf, "\n");
 
        return length;
 }
index f83fad2a3ff451ec8702e9048f94521cf56a1c98..4177ff004753299152a4d79471b784184eb7efdb 100644 (file)
@@ -387,7 +387,7 @@ static int __devinit rackmeter_probe(struct macio_dev* mdev,
               if (strcmp(np->name, "lightshow") == 0)
                       break;
               if ((strcmp(np->name, "sound") == 0) &&
-                  get_property(np, "virtual", NULL) != NULL)
+                  of_get_property(np, "virtual", NULL) != NULL)
                       break;
        }
        if (np == NULL) {
index c9f3dc4fd3ee47a567d8087e9064efd55cf078bd..a98a328b1cfcf335a637079cbc6c3b189c8c27a1 100644 (file)
@@ -491,7 +491,7 @@ int __init smu_init (void)
                printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n");
                goto fail;
        }
-       data = get_property(smu->db_node, "reg", NULL);
+       data = of_get_property(smu->db_node, "reg", NULL);
        if (data == NULL) {
                of_node_put(smu->db_node);
                smu->db_node = NULL;
@@ -512,7 +512,7 @@ int __init smu_init (void)
                smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt");
                if (smu->msg_node == NULL)
                        break;
-               data = get_property(smu->msg_node, "reg", NULL);
+               data = of_get_property(smu->msg_node, "reg", NULL);
                if (data == NULL) {
                        of_node_put(smu->msg_node);
                        smu->msg_node = NULL;
@@ -952,7 +952,7 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
        prop->name = ((char *)prop) + tlen - 18;
        sprintf(prop->name, "sdb-partition-%02x", id);
        prop->length = len;
-       prop->value = (unsigned char *)hdr;
+       prop->value = hdr;
        prop->next = NULL;
 
        /* Read the datablock */
@@ -1004,7 +1004,7 @@ const struct smu_sdbp_header *__smu_get_sdb_partition(int id,
        } else
                mutex_lock(&smu_part_access);
 
-       part = get_property(smu->of_node, pname, size);
+       part = of_get_property(smu->of_node, pname, size);
        if (part == NULL) {
                DPRINTK("trying to extract from SMU ...\n");
                part = smu_create_sdb_partition(id);
index a7ce559266380596a045657ed14ae12efd4f5bb6..228903403cfcf78334184cf5aa3df2f99285a706 100644 (file)
@@ -567,13 +567,13 @@ thermostat_init(void)
        else
                return -ENODEV;
 
-       prop = get_property(np, "hwsensor-params-version", NULL);
+       prop = of_get_property(np, "hwsensor-params-version", NULL);
        printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
                         (*prop == 1)?"":"un");
        if (*prop != 1)
                return -ENODEV;
 
-       prop = get_property(np, "reg", NULL);
+       prop = of_get_property(np, "reg", NULL);
        if (!prop)
                return -ENODEV;
 
@@ -591,9 +591,9 @@ thermostat_init(void)
                         "limit_adjust: %d, fan_speed: %d\n",
                         therm_bus, therm_address, limit_adjust, fan_speed);
 
-       if (get_property(np, "hwsensor-location", NULL)) {
+       if (of_get_property(np, "hwsensor-location", NULL)) {
                for (i = 0; i < 3; i++) {
-                       sensor_location[i] = get_property(np,
+                       sensor_location[i] = of_get_property(np,
                                        "hwsensor-location", NULL) + offset;
 
                        if (sensor_location[i] == NULL)
index 2e4ad44a863640424745e711f5bd73b0a5703af6..78ff186171393eaac54f54fe00a1aef4b7c276df 100644 (file)
@@ -674,7 +674,7 @@ static int read_eeprom(int cpu, struct mpu_data *out)
                printk(KERN_ERR "therm_pm72: Failed to retrieve cpuid node from device-tree\n");
                return -ENODEV;
        }
-       data = get_property(np, "cpuid", &len);
+       data = of_get_property(np, "cpuid", &len);
        if (data == NULL) {
                printk(KERN_ERR "therm_pm72: Failed to retrieve cpuid property from device-tree\n");
                of_node_put(np);
@@ -1337,7 +1337,7 @@ static int init_backside_state(struct backside_pid_state *state)
         */
        u3 = of_find_node_by_path("/u3@0,f8000000");
        if (u3 != NULL) {
-               const u32 *vers = get_property(u3, "device-rev", NULL);
+               const u32 *vers = of_get_property(u3, "device-rev", NULL);
                if (vers)
                        if (((*vers) & 0x3f) < 0x34)
                                u3h = 0;
@@ -2129,8 +2129,8 @@ static void fcu_lookup_fans(struct device_node *fcu_node)
                        continue;
 
                /* Lookup for a matching location */
-               loc = get_property(np, "location", NULL);
-               reg = get_property(np, "reg", NULL);
+               loc = of_get_property(np, "location", NULL);
+               reg = of_get_property(np, "reg", NULL);
                if (loc == NULL || reg == NULL)
                        continue;
                DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
index a1d3a987cb3acad619ed55adcc3b2d1752b9091b..35233de460ad7f6e574b552c710ea10b0867abae 100644 (file)
@@ -492,7 +492,7 @@ g4fan_init( void )
 
        if( !(np=of_find_node_by_name(NULL, "power-mgt")) )
                return -ENODEV;
-       info = get_property(np, "thermal-info", NULL);
+       info = of_get_property(np, "thermal-info", NULL);
        of_node_put(np);
 
        if( !info || !machine_is_compatible("PowerMac3,6") )
index d58fcf6cca0aec41f68344f9cf99e880193ba9da..76d21775fc35b8362dec4ce9dbd694d1d468b5b6 100644 (file)
@@ -131,7 +131,7 @@ int __init find_via_cuda(void)
     if (vias == 0)
        return 0;
 
-    reg = get_property(vias, "reg", NULL);
+    reg = of_get_property(vias, "reg", NULL);
     if (reg == NULL) {
            printk(KERN_ERR "via-cuda: No \"reg\" property !\n");
            goto fail;
index 179af10105d968fe9216cb03f41f33de0599ddca..fc89a7047cd0b0a24925e9ec97d86efcb81e1a32 100644 (file)
@@ -81,7 +81,7 @@ static struct led_classdev pmu_led = {
 };
 
 #ifdef CONFIG_PM
-static int pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when)
+static void pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when)
 {
        unsigned long flags;
 
@@ -99,8 +99,6 @@ static int pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when)
                break;
        }
        spin_unlock_irqrestore(&pmu_blink_lock, flags);
-
-       return PBOOK_SLEEP_OK;
 }
 
 static struct pmu_sleep_notifier via_pmu_led_sleep_notif = {
@@ -120,11 +118,13 @@ static int __init via_pmu_led_init(void)
        dt = of_find_node_by_path("/");
        if (dt == NULL)
                return -ENODEV;
-       model = get_property(dt, "model", NULL);
+       model = of_get_property(dt, "model", NULL);
        if (model == NULL)
                return -ENODEV;
        if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
-           strncmp(model, "iBook", strlen("iBook")) != 0) {
+           strncmp(model, "iBook", strlen("iBook")) != 0 &&
+           strcmp(model, "PowerMac7,2") != 0 &&
+           strcmp(model, "PowerMac7,3") != 0) {
                of_node_put(dt);
                /* ignore */
                return -ENODEV;
index b6073bdb50c36a73b73e6851ebe6ba2f414801fb..1729d3fd7a11417ed63c784986290b9bba5b1a4c 100644 (file)
@@ -289,7 +289,7 @@ int __init find_via_pmu(void)
        if (vias == NULL)
                return 0;
 
-       reg = get_property(vias, "reg", NULL);
+       reg = of_get_property(vias, "reg", NULL);
        if (reg == NULL) {
                printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
                goto fail;
@@ -319,10 +319,13 @@ int __init find_via_pmu(void)
        else if (device_is_compatible(vias->parent, "Keylargo")
                 || device_is_compatible(vias->parent, "K2-Keylargo")) {
                struct device_node *gpiop;
+               struct device_node *adbp;
                u64 gaddr = OF_BAD_ADDR;
 
                pmu_kind = PMU_KEYLARGO_BASED;
-               pmu_has_adb = (find_type_devices("adb") != NULL);
+               adbp = of_find_node_by_type(NULL, "adb");
+               pmu_has_adb = (adbp != NULL);
+               of_node_put(adbp);
                pmu_intr_mask = PMU_INT_PCEJECT |
                                PMU_INT_SNDBRT |
                                PMU_INT_ADB |
@@ -331,7 +334,7 @@ int __init find_via_pmu(void)
                
                gpiop = of_find_node_by_name(NULL, "gpio");
                if (gpiop) {
-                       reg = get_property(gpiop, "reg", NULL);
+                       reg = of_get_property(gpiop, "reg", NULL);
                        if (reg)
                                gaddr = of_translate_address(gpiop, reg);
                        if (gaddr != OF_BAD_ADDR)
@@ -484,10 +487,11 @@ static int __init via_pmu_dev_init(void)
                pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
                pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
        } else {
-               struct device_node* prim = find_devices("power-mgt");
+               struct device_node* prim =
+                       of_find_node_by_name(NULL, "power-mgt");
                const u32 *prim_info = NULL;
                if (prim)
-                       prim_info = get_property(prim, "prim-info", NULL);
+                       prim_info = of_get_property(prim, "prim-info", NULL);
                if (prim_info) {
                        /* Other stuffs here yet unknown */
                        pmu_battery_count = (prim_info[6] >> 16) & 0xff;
@@ -495,6 +499,7 @@ static int __init via_pmu_dev_init(void)
                        if (pmu_battery_count > 1)
                                pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
                }
+               of_node_put(prim);
        }
 #endif /* CONFIG_PPC32 */
 
@@ -1769,35 +1774,21 @@ EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
 
 /* Sleep is broadcast last-to-first */
-static int
-broadcast_sleep(int when, int fallback)
+static void broadcast_sleep(int when)
 {
-       int ret = PBOOK_SLEEP_OK;
        struct list_head *list;
        struct pmu_sleep_notifier *notifier;
 
        for (list = sleep_notifiers.prev; list != &sleep_notifiers;
             list = list->prev) {
                notifier = list_entry(list, struct pmu_sleep_notifier, list);
-               ret = notifier->notifier_call(notifier, when);
-               if (ret != PBOOK_SLEEP_OK) {
-                       printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n",
-                              when, notifier, notifier->notifier_call);
-                       for (; list != &sleep_notifiers; list = list->next) {
-                               notifier = list_entry(list, struct pmu_sleep_notifier, list);
-                               notifier->notifier_call(notifier, fallback);
-                       }
-                       return ret;
-               }
+               notifier->notifier_call(notifier, when);
        }
-       return ret;
 }
 
 /* Wake is broadcast first-to-last */
-static int
-broadcast_wake(void)
+static void broadcast_wake(void)
 {
-       int ret = PBOOK_SLEEP_OK;
        struct list_head *list;
        struct pmu_sleep_notifier *notifier;
 
@@ -1806,7 +1797,6 @@ broadcast_wake(void)
                notifier = list_entry(list, struct pmu_sleep_notifier, list);
                notifier->notifier_call(notifier, PBOOK_WAKE);
        }
-       return ret;
 }
 
 /*
@@ -2013,12 +2003,8 @@ pmac_suspend_devices(void)
 
        pm_prepare_console();
        
-       /* Notify old-style device drivers & userland */
-       ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
-       if (ret != PBOOK_SLEEP_OK) {
-               printk(KERN_ERR "Sleep rejected by drivers\n");
-               return -EBUSY;
-       }
+       /* Notify old-style device drivers */
+       broadcast_sleep(PBOOK_SLEEP_REQUEST);
 
        /* Sync the disks. */
        /* XXX It would be nice to have some way to ensure that
@@ -2028,12 +2014,7 @@ pmac_suspend_devices(void)
         */
        sys_sync();
 
-       /* Sleep can fail now. May not be very robust but useful for debugging */
-       ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
-       if (ret != PBOOK_SLEEP_OK) {
-               printk(KERN_ERR "Driver sleep failed\n");
-               return -EBUSY;
-       }
+       broadcast_sleep(PBOOK_SLEEP_NOW);
 
        /* Send suspend call to devices, hold the device core's dpm_sem */
        ret = device_suspend(PMSG_SUSPEND);
@@ -2154,7 +2135,7 @@ static int powerbook_sleep_grackle(void)
        int ret;
        struct pci_dev *grackle;
 
-       grackle = pci_find_slot(0, 0);
+       grackle = pci_get_bus_and_slot(0, 0);
        if (!grackle)
                return -ENODEV;
 
@@ -2202,6 +2183,8 @@ static int powerbook_sleep_grackle(void)
        pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); 
        pci_write_config_word(grackle, 0x70, pmcr1);
 
+       pci_dev_put(grackle);
+
        /* Make sure the PMU is idle */
        pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
        restore_via_state();
index 3f7967feaf5b7e7900c3134e40cb5b3f33fef493..ab4d1b63f63e673c70f3321a837cc4f029a380c4 100644 (file)
@@ -176,7 +176,7 @@ static int wf_lm75_attach(struct i2c_adapter *adapter)
        for (dev = NULL;
             (dev = of_get_next_child(busnode, dev)) != NULL;) {
                const char *loc =
-                       get_property(dev, "hwsensor-location", NULL);
+                       of_get_property(dev, "hwsensor-location", NULL);
                u8 addr;
 
                /* We must re-match the adapter in order to properly check
index eae1189d6c41f6755636629df11621e6ef2d76a6..eaa74afa175ba44efc29aaec393b6aadc9a59c0b 100644 (file)
@@ -134,7 +134,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter)
                if (!device_is_compatible(dev, "max6690"))
                        continue;
                addr = pmac_i2c_get_dev_addr(dev);
-               loc = get_property(dev, "hwsensor-location", NULL);
+               loc = of_get_property(dev, "hwsensor-location", NULL);
                if (loc == NULL || addr == 0)
                        continue;
                printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
index 31b750d61206acd13091d39a68218d0e251284e8..ff398adc0283b720ff0ba7265e03725a3edbd5ec 100644 (file)
@@ -167,7 +167,7 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
        if (fct == NULL)
                return NULL;
        fct->ctrl.ops = &smu_fan_ops;
-       l = get_property(node, "location", NULL);
+       l = of_get_property(node, "location", NULL);
        if (l == NULL)
                goto fail;
 
@@ -224,17 +224,17 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
                goto fail;
 
        /* Get min & max values*/
-       v = get_property(node, "min-value", NULL);
+       v = of_get_property(node, "min-value", NULL);
        if (v == NULL)
                goto fail;
        fct->min = *v;
-       v = get_property(node, "max-value", NULL);
+       v = of_get_property(node, "max-value", NULL);
        if (v == NULL)
                goto fail;
        fct->max = *v;
 
        /* Get "reg" value */
-       reg = get_property(node, "reg", NULL);
+       reg = of_get_property(node, "reg", NULL);
        if (reg == NULL)
                goto fail;
        fct->reg = *reg;
index 83f79de7174beea3859afa905fe31b73a2bb50e4..9a6c2cf8fd0e6e54ffaf31bfb2847210df0a5796 100644 (file)
@@ -241,7 +241,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
        char *name;
        int vsens[2], isens[2];
 
-       reg = get_property(dev, "reg", NULL);
+       reg = of_get_property(dev, "reg", NULL);
        if (reg == NULL)
                return;
        addr = *reg;
@@ -268,9 +268,9 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
        isens[0] = isens[1] = -1;
        child = NULL;
        while ((child = of_get_next_child(dev, child)) != NULL) {
-               reg = get_property(child, "reg", NULL);
-               type = get_property(child, "device_type", NULL);
-               loc = get_property(child, "location", NULL);
+               reg = of_get_property(child, "reg", NULL);
+               type = of_get_property(child, "device_type", NULL);
+               loc = of_get_property(child, "location", NULL);
                if (reg == NULL || loc == NULL)
                        continue;
 
index 01b4c50143ddc77010b0ef72bc57f85f11861a5d..9c567b93f417b05d7ad15cd054c30627d851fb16 100644 (file)
@@ -204,8 +204,8 @@ static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
        ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL);
        if (ads == NULL)
                return NULL;
-       c = get_property(node, "device_type", NULL);
-       l = get_property(node, "location", NULL);
+       c = of_get_property(node, "device_type", NULL);
+       l = of_get_property(node, "location", NULL);
        if (c == NULL || l == NULL)
                goto fail;
 
@@ -255,7 +255,7 @@ static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
        } else
                goto fail;
 
-       v = get_property(node, "reg", NULL);
+       v = of_get_property(node, "reg", NULL);
        if (v == NULL)
                goto fail;
        ads->reg = *v;
index 4c2471ee054aa099a8777de111e7b219fe6c6eb9..d8121234c3471e9a4f1b609e1890f02e92970d59 100644 (file)
@@ -867,7 +867,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad4;
        }
 
-       cc->bs = bioset_create(MIN_IOS, MIN_IOS, 4);
+       cc->bs = bioset_create(MIN_IOS, MIN_IOS);
        if (!cc->bs) {
                ti->error = "Cannot allocate crypt bioset";
                goto bad_bs;
index 4eb73d3952130898e60db2cf3d98371706562110..8bdc8a87b249c4b9a0b46ab0e22308e30ed7c1d6 100644 (file)
@@ -60,7 +60,7 @@ static int resize_pool(unsigned int new_ios)
                if (!_io_pool)
                        return -ENOMEM;
 
-               _bios = bioset_create(16, 16, 4);
+               _bios = bioset_create(16, 16);
                if (!_bios) {
                        mempool_destroy(_io_pool);
                        _io_pool = NULL;
index 3668b170ea68f7c11cb8fc850ddf1babeb7eaa5a..11a98df298ece4db805682edc80d9860635f5cc4 100644 (file)
@@ -1012,7 +1012,7 @@ static struct mapped_device *alloc_dev(int minor)
        if (!md->tio_pool)
                goto bad3;
 
-       md->bs = bioset_create(16, 16, 4);
+       md->bs = bioset_create(16, 16);
        if (!md->bs)
                goto bad_no_bioset;
 
index 639e8b6c35b11dd03b72bef6a26be7b0521553b6..bc773781993a5b75113388a623f12f64fa697556 100644 (file)
@@ -577,14 +577,14 @@ config VIDEO_ZORAN_AVS6EYES
 
 config VIDEO_MEYE
        tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
-       depends on PCI && SONYPI && VIDEO_V4L1
+       depends on PCI && SONY_LAPTOP && VIDEO_V4L1
        ---help---
          This is the video4linux driver for the Motion Eye camera found
          in the Vaio Picturebook laptops. Please read the material in
          <file:Documentation/video4linux/meye.txt> for more information.
 
-         If you say Y or M here, you need to say Y or M to "Sony Programmable
-         I/O Control Device" in the character device section.
+         If you say Y or M here, you need to say Y or M to "Sony Laptop
+         Extras" in the misc device section.
 
          To compile this driver as a module, choose M here: the
          module will be called meye.
index 98681da5e3b91fbbd72d9c665c277eaf22e48cea..664aba8b4d85231895954ac48df4447212796d48 100644 (file)
@@ -925,13 +925,13 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV)
                        return -EINVAL;
                mutex_lock(&meye.lock);
-               sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS,
+               sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS,
                                      p->brightness >> 10);
-               sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE,
+               sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE,
                                      p->hue >> 10);
-               sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR,
+               sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR,
                                      p->colour >> 10);
-               sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST,
+               sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST,
                                      p->contrast >> 10);
                meye.picture = *p;
                mutex_unlock(&meye.lock);
@@ -1043,11 +1043,11 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                    meye.params.quality != jp->quality)
                        mchip_hic_stop();       /* need restart */
                meye.params = *jp;
-               sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS,
+               sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
                                      meye.params.sharpness);
-               sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC,
+               sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
                                      meye.params.agc);
-               sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE,
+               sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
                                      meye.params.picture);
                mutex_unlock(&meye.lock);
                break;
@@ -1287,38 +1287,38 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                mutex_lock(&meye.lock);
                switch (c->id) {
                case V4L2_CID_BRIGHTNESS:
-                       sonypi_camera_command(
-                               SONYPI_COMMAND_SETCAMERABRIGHTNESS, c->value);
+                       sony_pic_camera_command(
+                               SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
                        meye.picture.brightness = c->value << 10;
                        break;
                case V4L2_CID_HUE:
-                       sonypi_camera_command(
-                               SONYPI_COMMAND_SETCAMERAHUE, c->value);
+                       sony_pic_camera_command(
+                               SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
                        meye.picture.hue = c->value << 10;
                        break;
                case V4L2_CID_CONTRAST:
-                       sonypi_camera_command(
-                               SONYPI_COMMAND_SETCAMERACONTRAST, c->value);
+                       sony_pic_camera_command(
+                               SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
                        meye.picture.contrast = c->value << 10;
                        break;
                case V4L2_CID_SATURATION:
-                       sonypi_camera_command(
-                               SONYPI_COMMAND_SETCAMERACOLOR, c->value);
+                       sony_pic_camera_command(
+                               SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
                        meye.picture.colour = c->value << 10;
                        break;
                case V4L2_CID_AGC:
-                       sonypi_camera_command(
-                               SONYPI_COMMAND_SETCAMERAAGC, c->value);
+                       sony_pic_camera_command(
+                               SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
                        meye.params.agc = c->value;
                        break;
                case V4L2_CID_SHARPNESS:
-                       sonypi_camera_command(
-                               SONYPI_COMMAND_SETCAMERASHARPNESS, c->value);
+                       sony_pic_camera_command(
+                               SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
                        meye.params.sharpness = c->value;
                        break;
                case V4L2_CID_PICTURE:
-                       sonypi_camera_command(
-                               SONYPI_COMMAND_SETCAMERAPICTURE, c->value);
+                       sony_pic_camera_command(
+                               SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
                        meye.params.picture = c->value;
                        break;
                case V4L2_CID_JPEGQUAL:
@@ -1848,7 +1848,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
        memcpy(meye.video_dev, &meye_template, sizeof(meye_template));
        meye.video_dev->dev = &meye.mchip_dev->dev;
 
-       if ((ret = sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 1))) {
+       if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
                printk(KERN_ERR "meye: unable to power on the camera\n");
                printk(KERN_ERR "meye: did you enable the camera in "
                                "sonypi using the module options ?\n");
@@ -1928,13 +1928,13 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
        meye.params.picture = 0;
        meye.params.framerate = 0;
 
-       sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, 32);
-       sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, 32);
-       sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, 32);
-       sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, 32);
-       sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, 32);
-       sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, 0);
-       sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, 48);
+       sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, 32);
+       sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, 32);
+       sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, 32);
+       sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, 32);
+       sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, 32);
+       sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
+       sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
 
        printk(KERN_INFO "meye: Motion Eye Camera Driver v%s.\n",
               MEYE_DRIVER_VERSION);
@@ -1953,7 +1953,7 @@ outremap:
 outregions:
        pci_disable_device(meye.mchip_dev);
 outenabledev:
-       sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
+       sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
 outsonypienable:
        kfifo_free(meye.doneq);
 outkfifoalloc2:
@@ -1986,7 +1986,7 @@ static void __devexit meye_remove(struct pci_dev *pcidev)
 
        pci_disable_device(meye.mchip_dev);
 
-       sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
+       sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
 
        kfifo_free(meye.doneq);
        kfifo_free(meye.grabq);
index ea107cb5c845baf46b928bf880e1b54944257077..323d0074120da4aa5ad7f0c87413abd72212e219 100644 (file)
 /****************************************************************************/
 
 /* Sony Programmable I/O Controller for accessing the camera commands */
-#include <linux/sonypi.h>
+#include <linux/sony-laptop.h>
 
 /* private API definitions */
 #include <linux/meye.h>
index fe184f93c016a12d6b2661f926041ba8fc7db86d..1455a8f4e930389133dd1801fa7e6327517d9365 100644 (file)
@@ -2160,7 +2160,7 @@ static int find_planb(void)
        if (!machine_is(powermac))
                return 0;
 
-       planb_devices = find_devices("planb");
+       planb_devices = of_find_node_by_name(NULL, "planb");
        if (planb_devices == 0) {
                planb_num=0;
                printk(KERN_WARNING "PlanB: no device found!\n");
@@ -2175,12 +2175,14 @@ static int find_planb(void)
        if (planb_devices->n_addrs != 1) {
                printk (KERN_WARNING "PlanB: expecting 1 address for planb "
                        "(got %d)", planb_devices->n_addrs);
+               of_node_put(planb_devices);
                return 0;
        }
 
        if (planb_devices->n_intrs == 0) {
                printk(KERN_WARNING "PlanB: no intrs for device %s\n",
                       planb_devices->full_name);
+               of_node_put(planb_devices);
                return 0;
        } else {
                irq = planb_devices->intrs[0].line;
@@ -2202,6 +2204,7 @@ static int find_planb(void)
        confreg = planb_devices->addrs[0].space & 0xff;
        old_base = planb_devices->addrs[0].address;
        new_base = 0xf1000000;
+       of_node_put(planb_devices);
 
        DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
                "membase 0x%x (base reg. 0x%x)\n",
index 80b199fa0aa9b7173fc684b1866de7c1c2e46b2f..a3c525b2616aafeaa855b03377e0f4ee4937cdc5 100644 (file)
@@ -112,14 +112,70 @@ config SONY_LAPTOP
        depends on X86 && ACPI
        select BACKLIGHT_CLASS_DEVICE
          ---help---
-         This mini-driver drives the SNC device present in the ACPI BIOS of
-         the Sony Vaio laptops.
+         This mini-driver drives the SNC and SPIC devices present in the ACPI
+         BIOS of the Sony Vaio laptops.
 
-         It gives access to some extra laptop functionalities. In its current
-         form, this driver let the user set or query the screen brightness
-         through the backlight subsystem and remove/apply power to some
+         It gives access to some extra laptop functionalities like Bluetooth,
+         screen brightness control, Fn keys and allows powering on/off some
          devices.
 
          Read <file:Documentation/sony-laptop.txt> for more information.
 
+config SONY_LAPTOP_OLD
+       bool "Sonypi compatibility"
+       depends on SONY_LAPTOP
+         ---help---
+         Build the sonypi driver compatibility code into the sony-laptop driver.
+
+config THINKPAD_ACPI
+       tristate "ThinkPad ACPI Laptop Extras"
+       depends on X86 && ACPI
+       select BACKLIGHT_CLASS_DEVICE
+       select HWMON
+       ---help---
+         This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
+         support for Fn-Fx key combinations, Bluetooth control, video
+         output switching, ThinkLight control, UltraBay eject and more.
+         For more information about this driver see 
+         <file:Documentation/thinkpad-acpi.txt> and <http://ibm-acpi.sf.net/> .
+
+         This driver was formely known as ibm-acpi.
+
+         If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
+
+config THINKPAD_ACPI_DEBUG
+       bool "Verbose debug mode"
+       depends on THINKPAD_ACPI
+       default n
+       ---help---
+         Enables extra debugging information, at the expense of a slightly
+         increase in driver size.
+
+         If you are not sure, say N here.
+
+config THINKPAD_ACPI_DOCK
+       bool "Legacy Docking Station Support"
+       depends on THINKPAD_ACPI
+       depends on ACPI_DOCK=n
+       default n
+       ---help---
+         Allows the thinkpad_acpi driver to handle docking station events.
+         This support was made obsolete by the generic ACPI docking station
+         support (CONFIG_ACPI_DOCK).  It will allow locking and removing the
+         laptop from the docking station, but will not properly connect PCI
+         devices.
+
+         If you are not sure, say N here.
+
+config THINKPAD_ACPI_BAY
+       bool "Legacy Removable Bay Support"
+       depends on THINKPAD_ACPI
+       default y
+       ---help---
+         Allows the thinkpad_acpi driver to handle removable bays.  It will
+         eletrically disable the device in the bay, and also generate
+         notifications when the bay lever is ejected or inserted.
+
+         If you are not sure, say Y here.
+
 endmenu
index 7793ccd7904962c699340c53e8ef1cfa6389e9b1..e325164591380bd93011840757808b3927e26eb1 100644 (file)
@@ -12,3 +12,4 @@ obj-$(CONFIG_TIFM_CORE)               += tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)        += tifm_7xx1.o
 obj-$(CONFIG_SGI_IOC4)         += ioc4.o
 obj-$(CONFIG_SONY_LAPTOP)      += sony-laptop.o
+obj-$(CONFIG_THINKPAD_ACPI)    += thinkpad_acpi.o
index 4b232124a1abb0dea3b9e737062250e3988b968c..65c32a95e121360d3288e95fc5b96792538084ad 100644 (file)
@@ -3,7 +3,7 @@
  *
  *
  *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
- *  Copyright (C) 2006 Corentin Chary
+ *  Copyright (C) 2006-2007 Corentin Chary
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -48,7 +48,7 @@
 #include <acpi/acpi_bus.h>
 #include <asm/uaccess.h>
 
-#define ASUS_LAPTOP_VERSION "0.40"
+#define ASUS_LAPTOP_VERSION "0.41"
 
 #define ASUS_HOTK_NAME          "Asus Laptop Support"
 #define ASUS_HOTK_CLASS         "hotkey"
@@ -81,7 +81,8 @@
 #define TLED_ON     0x08       //touchpad LED
 #define RLED_ON     0x10       //Record LED
 #define PLED_ON     0x20       //Phone LED
-#define LCD_ON      0x40       //LCD backlight
+#define GLED_ON     0x40       //Gaming LED
+#define LCD_ON      0x80       //LCD backlight
 
 #define ASUS_LOG    ASUS_HOTK_FILE ": "
 #define ASUS_ERR    KERN_ERR    ASUS_LOG
@@ -94,6 +95,19 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
 MODULE_DESCRIPTION(ASUS_HOTK_NAME);
 MODULE_LICENSE("GPL");
 
+/* WAPF defines the behavior of the Fn+Fx wlan key
+ * The significance of values is yet to be found, but
+ * most of the time:
+ * 0x0 will do nothing
+ * 0x1 will allow to control the device with Fn+Fx key.
+ * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key
+ * 0x5 like 0x1 or 0x4
+ * So, if something doesn't work as you want, just try other values =)
+ */
+static uint wapf = 1;
+module_param(wapf, uint, 0644);
+MODULE_PARM_DESC(wapf, "WAPF value");
+
 #define ASUS_HANDLE(object, paths...)                                  \
        static acpi_handle  object##_handle = NULL;                     \
        static char *object##_paths[] = { paths }
@@ -103,6 +117,7 @@ ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");
 ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
 ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED");        /* W1JC */
 ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED");        /* A7J */
+ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED");        /* G1, G2 (probably) */
 
 /* LEDD */
 ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
@@ -221,6 +236,7 @@ ASUS_LED(mled, "mail");
 ASUS_LED(tled, "touchpad");
 ASUS_LED(rled, "record");
 ASUS_LED(pled, "phone");
+ASUS_LED(gled, "gaming");
 
 /*
  * This function evaluates an ACPI method, given an int as parameter, the
@@ -245,32 +261,19 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
        return (status == AE_OK);
 }
 
-static int read_acpi_int(acpi_handle handle, const char *method, int *val,
-                        struct acpi_object_list *params)
-{
-       struct acpi_buffer output;
-       union acpi_object out_obj;
-       acpi_status status;
-
-       output.length = sizeof(out_obj);
-       output.pointer = &out_obj;
-
-       status = acpi_evaluate_object(handle, (char *)method, params, &output);
-       *val = out_obj.integer.value;
-       return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
-}
-
 static int read_wireless_status(int mask)
 {
-       int status;
+       ulong status;
+       acpi_status rv = AE_OK;
 
        if (!wireless_status_handle)
                return (hotk->status & mask) ? 1 : 0;
 
-       if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) {
-               return (status & mask) ? 1 : 0;
-       } else
+       rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status);
+       if (ACPI_FAILURE(rv))
                printk(ASUS_WARNING "Error reading Wireless status\n");
+       else
+               return (status & mask) ? 1 : 0;
 
        return (hotk->status & mask) ? 1 : 0;
 }
@@ -285,19 +288,28 @@ static int read_status(int mask)
        return (hotk->status & mask) ? 1 : 0;
 }
 
-static void write_status(acpi_handle handle, int out, int mask, int invert)
+static void write_status(acpi_handle handle, int out, int mask)
 {
        hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
 
-       if (invert)             /* invert target value */
+       switch (mask) {
+       case MLED_ON:
                out = !out & 0x1;
+               break;
+       case GLED_ON:
+               out = (out & 0x1) + 1;
+               break;
+       default:
+               out &= 0x1;
+               break;
+       }
 
        if (handle && !write_acpi_int(handle, NULL, out, NULL))
-               printk(ASUS_WARNING " write failed\n");
+               printk(ASUS_WARNING " write failed %x\n", mask);
 }
 
 /* /sys/class/led handlers */
-#define ASUS_LED_HANDLER(object, mask, invert)                         \
+#define ASUS_LED_HANDLER(object, mask)                                 \
        static void object##_led_set(struct led_classdev *led_cdev,     \
                                     enum led_brightness value)         \
        {                                                               \
@@ -307,13 +319,14 @@ static void write_status(acpi_handle handle, int out, int mask, int invert)
        static void object##_led_update(struct work_struct *ignored)    \
        {                                                               \
                int value = object##_led_wk;                            \
-               write_status(object##_set_handle, value, (mask), (invert)); \
+               write_status(object##_set_handle, value, (mask));       \
        }
 
-ASUS_LED_HANDLER(mled, MLED_ON, 1);
-ASUS_LED_HANDLER(pled, PLED_ON, 0);
-ASUS_LED_HANDLER(rled, RLED_ON, 0);
-ASUS_LED_HANDLER(tled, TLED_ON, 0);
+ASUS_LED_HANDLER(mled, MLED_ON);
+ASUS_LED_HANDLER(pled, PLED_ON);
+ASUS_LED_HANDLER(rled, RLED_ON);
+ASUS_LED_HANDLER(tled, TLED_ON);
+ASUS_LED_HANDLER(gled, GLED_ON);
 
 static int get_lcd_state(void)
 {
@@ -338,7 +351,7 @@ static int set_lcd_state(int value)
                        printk(ASUS_WARNING "Error switching LCD\n");
        }
 
-       write_status(NULL, lcd, LCD_ON, 0);
+       write_status(NULL, lcd, LCD_ON);
        return 0;
 }
 
@@ -354,9 +367,11 @@ static void lcd_blank(int blank)
 
 static int read_brightness(struct backlight_device *bd)
 {
-       int value;
+       ulong value;
+       acpi_status rv = AE_OK;
 
-       if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL))
+       rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
+       if (ACPI_FAILURE(rv))
                printk(ASUS_WARNING "Error reading brightness\n");
 
        return value;
@@ -403,8 +418,10 @@ static ssize_t show_infos(struct device *dev,
                          struct device_attribute *attr, char *page)
 {
        int len = 0;
-       int temp;
+       ulong temp;
        char buf[16];           //enough for all info
+       acpi_status rv = AE_OK;
+
        /*
         * We use the easy way, we don't care of off and count, so we don't set eof
         * to 1
@@ -418,9 +435,10 @@ static ssize_t show_infos(struct device *dev,
         * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
         * The significance of others is yet to be found.
         */
-       if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL))
-               len +=
-                   sprintf(page + len, "SFUN value         : 0x%04x\n", temp);
+       rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
+       if (!ACPI_FAILURE(rv))
+               len += sprintf(page + len, "SFUN value         : 0x%04x\n",
+                              (uint) temp);
        /*
         * Another value for userspace: the ASYM method returns 0x02 for
         * battery low and 0x04 for battery critical, its readings tend to be
@@ -428,9 +446,10 @@ static ssize_t show_infos(struct device *dev,
         * Note: since not all the laptops provide this method, errors are
         * silently ignored.
         */
-       if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL))
-               len +=
-                   sprintf(page + len, "ASYM value         : 0x%04x\n", temp);
+       rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
+       if (!ACPI_FAILURE(rv))
+               len += sprintf(page + len, "ASYM value         : 0x%04x\n",
+                              (uint) temp);
        if (asus_info) {
                snprintf(buf, 16, "%d", asus_info->length);
                len += sprintf(page + len, "DSDT length        : %s\n", buf);
@@ -465,7 +484,7 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
 }
 
 static ssize_t store_status(const char *buf, size_t count,
-                           acpi_handle handle, int mask, int invert)
+                           acpi_handle handle, int mask)
 {
        int rv, value;
        int out = 0;
@@ -474,7 +493,7 @@ static ssize_t store_status(const char *buf, size_t count,
        if (rv > 0)
                out = value ? 1 : 0;
 
-       write_status(handle, out, mask, invert);
+       write_status(handle, out, mask);
 
        return rv;
 }
@@ -515,7 +534,7 @@ static ssize_t show_wlan(struct device *dev,
 static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
                          const char *buf, size_t count)
 {
-       return store_status(buf, count, wl_switch_handle, WL_ON, 0);
+       return store_status(buf, count, wl_switch_handle, WL_ON);
 }
 
 /*
@@ -531,7 +550,7 @@ static ssize_t store_bluetooth(struct device *dev,
                               struct device_attribute *attr, const char *buf,
                               size_t count)
 {
-       return store_status(buf, count, bt_switch_handle, BT_ON, 0);
+       return store_status(buf, count, bt_switch_handle, BT_ON);
 }
 
 /*
@@ -547,12 +566,15 @@ static void set_display(int value)
 
 static int read_display(void)
 {
-       int value = 0;
+       ulong value = 0;
+       acpi_status rv = AE_OK;
 
        /* In most of the case, we know how to set the display, but sometime
           we can't read it */
        if (display_get_handle) {
-               if (!read_acpi_int(display_get_handle, NULL, &value, NULL))
+               rv = acpi_evaluate_integer(display_get_handle, NULL,
+                                          NULL, &value);
+               if (ACPI_FAILURE(rv))
                        printk(ASUS_WARNING "Error reading display status\n");
        }
 
@@ -656,10 +678,10 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
         * switched
         */
        if (event == ATKD_LCD_ON) {
-               write_status(NULL, 1, LCD_ON, 0);
+               write_status(NULL, 1, LCD_ON);
                lcd_blank(FB_BLANK_UNBLANK);
        } else if (event == ATKD_LCD_OFF) {
-               write_status(NULL, 0, LCD_ON, 0);
+               write_status(NULL, 0, LCD_ON);
                lcd_blank(FB_BLANK_POWERDOWN);
        }
 
@@ -771,7 +793,7 @@ static int asus_hotk_get_info(void)
 {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *model = NULL;
-       int bsts_result, hwrs_result;
+       ulong bsts_result, hwrs_result;
        char *string = NULL;
        acpi_status status;
 
@@ -794,11 +816,16 @@ static int asus_hotk_get_info(void)
        }
 
        /* This needs to be called for some laptops to init properly */
-       if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL))
+       status =
+           acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result);
+       if (ACPI_FAILURE(status))
                printk(ASUS_WARNING "Error calling BSTS\n");
        else if (bsts_result)
                printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
-                      bsts_result);
+                      (uint) bsts_result);
+
+       /* This too ... */
+       write_acpi_int(hotk->handle, "CWAP", wapf, NULL);
 
        /*
         * Try to match the object returned by INIT to the specific model.
@@ -831,6 +858,7 @@ static int asus_hotk_get_info(void)
        ASUS_HANDLE_INIT(tled_set);
        ASUS_HANDLE_INIT(rled_set);
        ASUS_HANDLE_INIT(pled_set);
+       ASUS_HANDLE_INIT(gled_set);
 
        ASUS_HANDLE_INIT(ledd_set);
 
@@ -840,7 +868,9 @@ static int asus_hotk_get_info(void)
         * The significance of others is yet to be found.
         * If we don't find the method, we assume the device are present.
         */
-       if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL))
+       status =
+           acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result);
+       if (ACPI_FAILURE(status))
                hwrs_result = WL_HWRS | BT_HWRS;
 
        if (hwrs_result & WL_HWRS)
@@ -928,11 +958,15 @@ static int asus_hotk_add(struct acpi_device *device)
        asus_hotk_found = 1;
 
        /* WLED and BLED are on by default */
-       write_status(bt_switch_handle, 1, BT_ON, 0);
-       write_status(wl_switch_handle, 1, WL_ON, 0);
+       write_status(bt_switch_handle, 1, BT_ON);
+       write_status(wl_switch_handle, 1, WL_ON);
+
+       /* If the h/w switch is off, we need to check the real status */
+       write_status(NULL, read_status(BT_ON), BT_ON);
+       write_status(NULL, read_status(WL_ON), WL_ON);
 
        /* LCD Backlight is on by default */
-       write_status(NULL, 1, LCD_ON, 0);
+       write_status(NULL, 1, LCD_ON);
 
        /* LED display is off by default */
        hotk->ledd_status = 0xFFF;
@@ -991,6 +1025,7 @@ static void asus_led_exit(void)
        ASUS_LED_UNREGISTER(tled);
        ASUS_LED_UNREGISTER(pled);
        ASUS_LED_UNREGISTER(rled);
+       ASUS_LED_UNREGISTER(gled);
 
        destroy_workqueue(led_workqueue);
 }
@@ -1062,6 +1097,10 @@ static int asus_led_init(struct device *dev)
        if (rv)
                return rv;
 
+       rv = ASUS_LED_REGISTER(gled, dev);
+       if (rv)
+               return rv;
+
        led_workqueue = create_singlethread_workqueue("led_workqueue");
        if (!led_workqueue)
                return -ENOMEM;
index ac708bc2f9f3ce3bf158c74cf376072d7ac8726b..c15c1f61bd1bfad853b8c6ea343d6cdd47e98135 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * ACPI Sony Notebook Control Driver (SNC)
+ * ACPI Sony Notebook Control Driver (SNC and SPIC)
  *
  * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
  * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
@@ -7,6 +7,25 @@
  * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
  * which are copyrighted by their respective authors.
  *
+ * The SNY6001 driver part is based on the sonypi driver which includes
+ * material from:
+ *
+ * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ *
+ * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
+ *
+ * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
+ *
+ * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/kfifo.h>
+#include <linux/workqueue.h>
+#include <linux/acpi.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 #include <asm/uaccess.h>
+#include <linux/sonypi.h>
+#include <linux/sony-laptop.h>
+#ifdef CONFIG_SONY_LAPTOP_OLD
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#endif
 
-#define ACPI_SNC_CLASS         "sony"
-#define ACPI_SNC_HID           "SNY5001"
-#define ACPI_SNC_DRIVER_NAME   "ACPI Sony Notebook Control Driver v0.4"
+#define DRV_PFX                        "sony-laptop: "
+#define dprintk(msg...)                do {                    \
+       if (debug) printk(KERN_WARNING DRV_PFX  msg);   \
+} while (0)
 
-/* the device uses 1-based values, while the backlight subsystem uses
-   0-based values */
-#define SONY_MAX_BRIGHTNESS    8
+#define SONY_LAPTOP_DRIVER_VERSION     "0.5"
 
-#define LOG_PFX                        KERN_WARNING "sony-laptop: "
+#define SONY_NC_CLASS          "sony-nc"
+#define SONY_NC_HID            "SNY5001"
+#define SONY_NC_DRIVER_NAME    "Sony Notebook Control Driver"
+
+#define SONY_PIC_CLASS         "sony-pic"
+#define SONY_PIC_HID           "SNY6001"
+#define SONY_PIC_DRIVER_NAME   "Sony Programmable IO Control Driver"
 
 MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
-MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME);
+MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION);
 
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
                 "the development of this driver");
 
-static ssize_t sony_acpi_show(struct device *, struct device_attribute *,
+static int no_spic;            /* = 0 */
+module_param(no_spic, int, 0444);
+MODULE_PARM_DESC(no_spic,
+                "set this if you don't want to enable the SPIC device");
+
+static int compat;             /* = 0 */
+module_param(compat, int, 0444);
+MODULE_PARM_DESC(compat,
+                "set this if you want to enable backward compatibility mode");
+
+static unsigned long mask = 0xffffffff;
+module_param(mask, ulong, 0644);
+MODULE_PARM_DESC(mask,
+                "set this to the mask of event you want to enable (see doc)");
+
+static int camera;             /* = 0 */
+module_param(camera, int, 0444);
+MODULE_PARM_DESC(camera,
+                "set this to 1 to enable Motion Eye camera controls "
+                "(only use it if you have a C1VE or C1VN model)");
+
+#ifdef CONFIG_SONY_LAPTOP_OLD
+static int minor = -1;
+module_param(minor, int, 0);
+MODULE_PARM_DESC(minor,
+                "minor number of the misc device for the SPIC compatibility code, "
+                "default is -1 (automatic)");
+#endif
+
+/*********** Input Devices ***********/
+
+#define SONY_LAPTOP_BUF_SIZE   128
+struct sony_laptop_input_s {
+       atomic_t                users;
+       struct input_dev        *jog_dev;
+       struct input_dev        *key_dev;
+       struct kfifo            *fifo;
+       spinlock_t              fifo_lock;
+       struct workqueue_struct *wq;
+};
+static struct sony_laptop_input_s sony_laptop_input = {
+       .users = ATOMIC_INIT(0),
+};
+
+struct sony_laptop_keypress {
+       struct input_dev *dev;
+       int key;
+};
+
+/* Correspondance table between sonypi events and input layer events */
+static struct {
+       int sonypiev;
+       int inputev;
+} sony_laptop_inputkeys[] = {
+       { SONYPI_EVENT_CAPTURE_PRESSED,         KEY_CAMERA },
+       { SONYPI_EVENT_FNKEY_ONLY,              KEY_FN },
+       { SONYPI_EVENT_FNKEY_ESC,               KEY_FN_ESC },
+       { SONYPI_EVENT_FNKEY_F1,                KEY_FN_F1 },
+       { SONYPI_EVENT_FNKEY_F2,                KEY_FN_F2 },
+       { SONYPI_EVENT_FNKEY_F3,                KEY_FN_F3 },
+       { SONYPI_EVENT_FNKEY_F4,                KEY_FN_F4 },
+       { SONYPI_EVENT_FNKEY_F5,                KEY_FN_F5 },
+       { SONYPI_EVENT_FNKEY_F6,                KEY_FN_F6 },
+       { SONYPI_EVENT_FNKEY_F7,                KEY_FN_F7 },
+       { SONYPI_EVENT_FNKEY_F8,                KEY_FN_F8 },
+       { SONYPI_EVENT_FNKEY_F9,                KEY_FN_F9 },
+       { SONYPI_EVENT_FNKEY_F10,               KEY_FN_F10 },
+       { SONYPI_EVENT_FNKEY_F11,               KEY_FN_F11 },
+       { SONYPI_EVENT_FNKEY_F12,               KEY_FN_F12 },
+       { SONYPI_EVENT_FNKEY_1,                 KEY_FN_1 },
+       { SONYPI_EVENT_FNKEY_2,                 KEY_FN_2 },
+       { SONYPI_EVENT_FNKEY_D,                 KEY_FN_D },
+       { SONYPI_EVENT_FNKEY_E,                 KEY_FN_E },
+       { SONYPI_EVENT_FNKEY_F,                 KEY_FN_F },
+       { SONYPI_EVENT_FNKEY_S,                 KEY_FN_S },
+       { SONYPI_EVENT_FNKEY_B,                 KEY_FN_B },
+       { SONYPI_EVENT_BLUETOOTH_PRESSED,       KEY_BLUE },
+       { SONYPI_EVENT_BLUETOOTH_ON,            KEY_BLUE },
+       { SONYPI_EVENT_PKEY_P1,                 KEY_PROG1 },
+       { SONYPI_EVENT_PKEY_P2,                 KEY_PROG2 },
+       { SONYPI_EVENT_PKEY_P3,                 KEY_PROG3 },
+       { SONYPI_EVENT_BACK_PRESSED,            KEY_BACK },
+       { SONYPI_EVENT_HELP_PRESSED,            KEY_HELP },
+       { SONYPI_EVENT_ZOOM_PRESSED,            KEY_ZOOM },
+       { SONYPI_EVENT_THUMBPHRASE_PRESSED,     BTN_THUMB },
+       { 0, 0 },
+};
+
+/* release buttons after a short delay if pressed */
+static void do_sony_laptop_release_key(struct work_struct *work)
+{
+       struct sony_laptop_keypress kp;
+
+       while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
+                        sizeof(kp)) == sizeof(kp)) {
+               msleep(10);
+               input_report_key(kp.dev, kp.key, 0);
+               input_sync(kp.dev);
+       }
+}
+static DECLARE_WORK(sony_laptop_release_key_work,
+               do_sony_laptop_release_key);
+
+/* forward event to the input subsytem */
+static void sony_laptop_report_input_event(u8 event)
+{
+       struct input_dev *jog_dev = sony_laptop_input.jog_dev;
+       struct input_dev *key_dev = sony_laptop_input.key_dev;
+       struct sony_laptop_keypress kp = { NULL };
+       int i;
+
+       if (event == SONYPI_EVENT_FNKEY_RELEASED) {
+               /* Nothing, not all VAIOs generate this event */
+               return;
+       }
+
+       /* report events */
+       switch (event) {
+       /* jog_dev events */
+       case SONYPI_EVENT_JOGDIAL_UP:
+       case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
+               input_report_rel(jog_dev, REL_WHEEL, 1);
+               input_sync(jog_dev);
+               return;
+
+       case SONYPI_EVENT_JOGDIAL_DOWN:
+       case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
+               input_report_rel(jog_dev, REL_WHEEL, -1);
+               input_sync(jog_dev);
+               return;
+
+       /* key_dev events */
+       case SONYPI_EVENT_JOGDIAL_PRESSED:
+               kp.key = BTN_MIDDLE;
+               kp.dev = jog_dev;
+               break;
+
+       default:
+               for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
+                       if (event == sony_laptop_inputkeys[i].sonypiev) {
+                               kp.dev = key_dev;
+                               kp.key = sony_laptop_inputkeys[i].inputev;
+                               break;
+                       }
+               break;
+       }
+
+       if (kp.dev) {
+               input_report_key(kp.dev, kp.key, 1);
+               input_sync(kp.dev);
+               kfifo_put(sony_laptop_input.fifo,
+                         (unsigned char *)&kp, sizeof(kp));
+
+               if (!work_pending(&sony_laptop_release_key_work))
+                       queue_work(sony_laptop_input.wq,
+                                       &sony_laptop_release_key_work);
+       } else
+               dprintk("unknown input event %.2x\n", event);
+}
+
+static int sony_laptop_setup_input(void)
+{
+       struct input_dev *jog_dev;
+       struct input_dev *key_dev;
+       int i;
+       int error;
+
+       /* don't run again if already initialized */
+       if (atomic_add_return(1, &sony_laptop_input.users) > 1)
+               return 0;
+
+       /* kfifo */
+       spin_lock_init(&sony_laptop_input.fifo_lock);
+       sony_laptop_input.fifo =
+               kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
+                           &sony_laptop_input.fifo_lock);
+       if (IS_ERR(sony_laptop_input.fifo)) {
+               printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+               error = PTR_ERR(sony_laptop_input.fifo);
+               goto err_dec_users;
+       }
+
+       /* init workqueue */
+       sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");
+       if (!sony_laptop_input.wq) {
+               printk(KERN_ERR DRV_PFX
+                               "Unabe to create workqueue.\n");
+               error = -ENXIO;
+               goto err_free_kfifo;
+       }
+
+       /* input keys */
+       key_dev = input_allocate_device();
+       if (!key_dev) {
+               error = -ENOMEM;
+               goto err_destroy_wq;
+       }
+
+       key_dev->name = "Sony Vaio Keys";
+       key_dev->id.bustype = BUS_ISA;
+       key_dev->id.vendor = PCI_VENDOR_ID_SONY;
+
+       /* Initialize the Input Drivers: special keys */
+       key_dev->evbit[0] = BIT(EV_KEY);
+       for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
+               if (sony_laptop_inputkeys[i].inputev)
+                       set_bit(sony_laptop_inputkeys[i].inputev,
+                                       key_dev->keybit);
+
+       error = input_register_device(key_dev);
+       if (error)
+               goto err_free_keydev;
+
+       sony_laptop_input.key_dev = key_dev;
+
+       /* jogdial */
+       jog_dev = input_allocate_device();
+       if (!jog_dev) {
+               error = -ENOMEM;
+               goto err_unregister_keydev;
+       }
+
+       jog_dev->name = "Sony Vaio Jogdial";
+       jog_dev->id.bustype = BUS_ISA;
+       jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
+
+       jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
+       jog_dev->relbit[0] = BIT(REL_WHEEL);
+
+       error = input_register_device(jog_dev);
+       if (error)
+               goto err_free_jogdev;
+
+       sony_laptop_input.jog_dev = jog_dev;
+
+       return 0;
+
+err_free_jogdev:
+       input_free_device(jog_dev);
+
+err_unregister_keydev:
+       input_unregister_device(key_dev);
+       /* to avoid kref underflow below at input_free_device */
+       key_dev = NULL;
+
+err_free_keydev:
+       input_free_device(key_dev);
+
+err_destroy_wq:
+       destroy_workqueue(sony_laptop_input.wq);
+
+err_free_kfifo:
+       kfifo_free(sony_laptop_input.fifo);
+
+err_dec_users:
+       atomic_dec(&sony_laptop_input.users);
+       return error;
+}
+
+static void sony_laptop_remove_input(void)
+{
+       /* cleanup only after the last user has gone */
+       if (!atomic_dec_and_test(&sony_laptop_input.users))
+               return;
+
+       /* flush workqueue first */
+       flush_workqueue(sony_laptop_input.wq);
+
+       /* destroy input devs */
+       input_unregister_device(sony_laptop_input.key_dev);
+       sony_laptop_input.key_dev = NULL;
+
+       if (sony_laptop_input.jog_dev) {
+               input_unregister_device(sony_laptop_input.jog_dev);
+               sony_laptop_input.jog_dev = NULL;
+       }
+
+       destroy_workqueue(sony_laptop_input.wq);
+       kfifo_free(sony_laptop_input.fifo);
+}
+
+/*********** Platform Device ***********/
+
+static atomic_t sony_pf_users = ATOMIC_INIT(0);
+static struct platform_driver sony_pf_driver = {
+       .driver = {
+                  .name = "sony-laptop",
+                  .owner = THIS_MODULE,
+                  }
+};
+static struct platform_device *sony_pf_device;
+
+static int sony_pf_add(void)
+{
+       int ret = 0;
+
+       /* don't run again if already initialized */
+       if (atomic_add_return(1, &sony_pf_users) > 1)
+               return 0;
+
+       ret = platform_driver_register(&sony_pf_driver);
+       if (ret)
+               goto out;
+
+       sony_pf_device = platform_device_alloc("sony-laptop", -1);
+       if (!sony_pf_device) {
+               ret = -ENOMEM;
+               goto out_platform_registered;
+       }
+
+       ret = platform_device_add(sony_pf_device);
+       if (ret)
+               goto out_platform_alloced;
+
+       return 0;
+
+      out_platform_alloced:
+       platform_device_put(sony_pf_device);
+       sony_pf_device = NULL;
+      out_platform_registered:
+       platform_driver_unregister(&sony_pf_driver);
+      out:
+       atomic_dec(&sony_pf_users);
+       return ret;
+}
+
+static void sony_pf_remove(void)
+{
+       /* deregister only after the last user has gone */
+       if (!atomic_dec_and_test(&sony_pf_users))
+               return;
+
+       platform_device_del(sony_pf_device);
+       platform_device_put(sony_pf_device);
+       platform_driver_unregister(&sony_pf_driver);
+}
+
+/*********** SNC (SNY5001) Device ***********/
+
+/* the device uses 1-based values, while the backlight subsystem uses
+   0-based values */
+#define SONY_MAX_BRIGHTNESS    8
+
+#define SNC_VALIDATE_IN                0
+#define SNC_VALIDATE_OUT       1
+
+static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
                              char *);
-static ssize_t sony_acpi_store(struct device *, struct device_attribute *,
+static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
                               const char *, size_t);
 static int boolean_validate(const int, const int);
 static int brightness_default_validate(const int, const int);
 
-#define SNC_VALIDATE_IN                0
-#define SNC_VALIDATE_OUT       1
-
-struct sony_acpi_value {
+struct sony_nc_value {
        char *name;             /* name of the entry */
        char **acpiget;         /* names of the ACPI get function */
        char **acpiset;         /* names of the ACPI set function */
@@ -75,65 +458,65 @@ struct sony_acpi_value {
        struct device_attribute devattr;        /* sysfs atribute */
 };
 
-#define HANDLE_NAMES(_name, _values...) \
+#define SNC_HANDLE_NAMES(_name, _values...) \
        static char *snc_##_name[] = { _values, NULL }
 
-#define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \
+#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
        { \
                .name           = __stringify(_name), \
                .acpiget        = _getters, \
                .acpiset        = _setters, \
                .validate       = _validate, \
                .debug          = _debug, \
-               .devattr        = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \
+               .devattr        = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
        }
 
-#define SONY_ACPI_VALUE_NULL   { .name = NULL }
+#define SNC_HANDLE_NULL        { .name = NULL }
 
-HANDLE_NAMES(fnkey_get, "GHKE");
+SNC_HANDLE_NAMES(fnkey_get, "GHKE");
 
-HANDLE_NAMES(brightness_def_get, "GPBR");
-HANDLE_NAMES(brightness_def_set, "SPBR");
+SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
+SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
 
-HANDLE_NAMES(cdpower_get, "GCDP");
-HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
+SNC_HANDLE_NAMES(cdpower_get, "GCDP");
+SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
 
-HANDLE_NAMES(audiopower_get, "GAZP");
-HANDLE_NAMES(audiopower_set, "AZPW");
+SNC_HANDLE_NAMES(audiopower_get, "GAZP");
+SNC_HANDLE_NAMES(audiopower_set, "AZPW");
 
-HANDLE_NAMES(lanpower_get, "GLNP");
-HANDLE_NAMES(lanpower_set, "LNPW");
+SNC_HANDLE_NAMES(lanpower_get, "GLNP");
+SNC_HANDLE_NAMES(lanpower_set, "LNPW");
 
-HANDLE_NAMES(PID_get, "GPID");
+SNC_HANDLE_NAMES(PID_get, "GPID");
 
-HANDLE_NAMES(CTR_get, "GCTR");
-HANDLE_NAMES(CTR_set, "SCTR");
+SNC_HANDLE_NAMES(CTR_get, "GCTR");
+SNC_HANDLE_NAMES(CTR_set, "SCTR");
 
-HANDLE_NAMES(PCR_get, "GPCR");
-HANDLE_NAMES(PCR_set, "SPCR");
+SNC_HANDLE_NAMES(PCR_get, "GPCR");
+SNC_HANDLE_NAMES(PCR_set, "SPCR");
 
-HANDLE_NAMES(CMI_get, "GCMI");
-HANDLE_NAMES(CMI_set, "SCMI");
+SNC_HANDLE_NAMES(CMI_get, "GCMI");
+SNC_HANDLE_NAMES(CMI_set, "SCMI");
 
-static struct sony_acpi_value sony_acpi_values[] = {
-       SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get,
+static struct sony_nc_value sony_nc_values[] = {
+       SNC_HANDLE(brightness_default, snc_brightness_def_get,
                        snc_brightness_def_set, brightness_default_validate, 0),
-       SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0),
-       SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
-       SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set,
+       SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
+       SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
+       SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
                        boolean_validate, 0),
-       SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set,
+       SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
                        boolean_validate, 1),
        /* unknown methods */
-       SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1),
-       SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
-       SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
-       SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
-       SONY_ACPI_VALUE_NULL
+       SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
+       SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
+       SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
+       SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
+       SNC_HANDLE_NULL
 };
 
-static acpi_handle sony_acpi_handle;
-static struct acpi_device *sony_acpi_acpi_device = NULL;
+static acpi_handle sony_nc_acpi_handle;
+static struct acpi_device *sony_nc_acpi_device = NULL;
 
 /*
  * acpi_evaluate_object wrappers
@@ -153,7 +536,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
                return 0;
        }
 
-       printk(LOG_PFX "acpi_callreadfunc failed\n");
+       printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n");
 
        return -1;
 }
@@ -179,7 +562,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
        if (status == AE_OK) {
                if (result != NULL) {
                        if (out_obj.type != ACPI_TYPE_INTEGER) {
-                               printk(LOG_PFX "acpi_evaluate_object bad "
+                               printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad "
                                       "return type\n");
                                return -1;
                        }
@@ -188,13 +571,13 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
                return 0;
        }
 
-       printk(LOG_PFX "acpi_evaluate_object failed\n");
+       printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n");
 
        return -1;
 }
 
 /*
- * sony_acpi_values input/output validate functions
+ * sony_nc_values input/output validate functions
  */
 
 /* brightness_default_validate:
@@ -229,19 +612,19 @@ static int boolean_validate(const int direction, const int value)
 }
 
 /*
- * Sysfs show/store common to all sony_acpi_values
+ * Sysfs show/store common to all sony_nc_values
  */
-static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
+static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
                              char *buffer)
 {
        int value;
-       struct sony_acpi_value *item =
-           container_of(attr, struct sony_acpi_value, devattr);
+       struct sony_nc_value *item =
+           container_of(attr, struct sony_nc_value, devattr);
 
        if (!*item->acpiget)
                return -EIO;
 
-       if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0)
+       if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0)
                return -EIO;
 
        if (item->validate)
@@ -250,13 +633,13 @@ static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
        return snprintf(buffer, PAGE_SIZE, "%d\n", value);
 }
 
-static ssize_t sony_acpi_store(struct device *dev,
+static ssize_t sony_nc_sysfs_store(struct device *dev,
                               struct device_attribute *attr,
                               const char *buffer, size_t count)
 {
        int value;
-       struct sony_acpi_value *item =
-           container_of(attr, struct sony_acpi_value, devattr);
+       struct sony_nc_value *item =
+           container_of(attr, struct sony_nc_value, devattr);
 
        if (!item->acpiset)
                return -EIO;
@@ -272,118 +655,20 @@ static ssize_t sony_acpi_store(struct device *dev,
        if (value < 0)
                return value;
 
-       if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0)
+       if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0)
                return -EIO;
        item->value = value;
        item->valid = 1;
        return count;
 }
 
-/*
- * Platform device
- */
-static struct platform_driver sncpf_driver = {
-       .driver = {
-                  .name = "sony-laptop",
-                  .owner = THIS_MODULE,
-                  }
-};
-static struct platform_device *sncpf_device;
-
-static int sony_snc_pf_add(void)
-{
-       acpi_handle handle;
-       struct sony_acpi_value *item;
-       int ret = 0;
-
-       ret = platform_driver_register(&sncpf_driver);
-       if (ret)
-               goto out;
-
-       sncpf_device = platform_device_alloc("sony-laptop", -1);
-       if (!sncpf_device) {
-               ret = -ENOMEM;
-               goto out_platform_registered;
-       }
-
-       ret = platform_device_add(sncpf_device);
-       if (ret)
-               goto out_platform_alloced;
-
-       for (item = sony_acpi_values; item->name; ++item) {
-
-               if (!debug && item->debug)
-                       continue;
-
-               /* find the available acpiget as described in the DSDT */
-               for (; item->acpiget && *item->acpiget; ++item->acpiget) {
-                       if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
-                                                        *item->acpiget,
-                                                        &handle))) {
-                               if (debug)
-                                       printk(LOG_PFX "Found %s getter: %s\n",
-                                              item->name, *item->acpiget);
-                               item->devattr.attr.mode |= S_IRUGO;
-                               break;
-                       }
-               }
-
-               /* find the available acpiset as described in the DSDT */
-               for (; item->acpiset && *item->acpiset; ++item->acpiset) {
-                       if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
-                                                        *item->acpiset,
-                                                        &handle))) {
-                               if (debug)
-                                       printk(LOG_PFX "Found %s setter: %s\n",
-                                              item->name, *item->acpiset);
-                               item->devattr.attr.mode |= S_IWUSR;
-                               break;
-                       }
-               }
-
-               if (item->devattr.attr.mode != 0) {
-                       ret =
-                           device_create_file(&sncpf_device->dev,
-                                              &item->devattr);
-                       if (ret)
-                               goto out_sysfs;
-               }
-       }
-
-       return 0;
-
-      out_sysfs:
-       for (item = sony_acpi_values; item->name; ++item) {
-               device_remove_file(&sncpf_device->dev, &item->devattr);
-       }
-       platform_device_del(sncpf_device);
-      out_platform_alloced:
-       platform_device_put(sncpf_device);
-      out_platform_registered:
-       platform_driver_unregister(&sncpf_driver);
-      out:
-       return ret;
-}
-
-static void sony_snc_pf_remove(void)
-{
-       struct sony_acpi_value *item;
-
-       for (item = sony_acpi_values; item->name; ++item) {
-               device_remove_file(&sncpf_device->dev, &item->devattr);
-       }
-
-       platform_device_del(sncpf_device);
-       platform_device_put(sncpf_device);
-       platform_driver_unregister(&sncpf_driver);
-}
 
 /*
  * Backlight device
  */
 static int sony_backlight_update_status(struct backlight_device *bd)
 {
-       return acpi_callsetfunc(sony_acpi_handle, "SBRT",
+       return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
                                bd->props.brightness + 1, NULL);
 }
 
@@ -391,7 +676,7 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
 {
        int value;
 
-       if (acpi_callgetfunc(sony_acpi_handle, "GBRT", &value))
+       if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
                return 0;
        /* brightness levels are 1-based, while backlight ones are 0-based */
        return value - 1;
@@ -408,9 +693,9 @@ static struct backlight_ops sony_backlight_ops = {
  */
 static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
 {
-       if (debug)
-               printk(LOG_PFX "sony_acpi_notify, event: %d\n", event);
-       acpi_bus_generate_event(sony_acpi_acpi_device, 1, event);
+       dprintk("sony_acpi_notify, event: %d\n", event);
+       sony_laptop_report_input_event(event);
+       acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
 }
 
 static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -422,7 +707,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
        node = (struct acpi_namespace_node *)handle;
        operand = (union acpi_operand_object *)node->object;
 
-       printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
+       printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
               (u32) operand->method.param_count);
 
        return AE_OK;
@@ -431,16 +716,16 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
 /*
  * ACPI device
  */
-static int sony_acpi_resume(struct acpi_device *device)
+static int sony_nc_resume(struct acpi_device *device)
 {
-       struct sony_acpi_value *item;
+       struct sony_nc_value *item;
 
-       for (item = sony_acpi_values; item->name; item++) {
+       for (item = sony_nc_values; item->name; item++) {
                int ret;
 
                if (!item->valid)
                        continue;
-               ret = acpi_callsetfunc(sony_acpi_handle, *item->acpiset,
+               ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
                                       item->value, NULL);
                if (ret < 0) {
                        printk("%s: %d\n", __FUNCTION__, ret);
@@ -450,42 +735,55 @@ static int sony_acpi_resume(struct acpi_device *device)
        return 0;
 }
 
-static int sony_acpi_add(struct acpi_device *device)
+static int sony_nc_add(struct acpi_device *device)
 {
        acpi_status status;
        int result = 0;
        acpi_handle handle;
+       struct sony_nc_value *item;
+
+       printk(KERN_INFO DRV_PFX "%s v%s.\n",
+               SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
 
-       sony_acpi_acpi_device = device;
+       sony_nc_acpi_device = device;
+       strcpy(acpi_device_class(device), "sony/hotkey");
 
-       sony_acpi_handle = device->handle;
+       sony_nc_acpi_handle = device->handle;
 
        if (debug) {
-               status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle,
+               status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
                                             1, sony_walk_callback, NULL, NULL);
                if (ACPI_FAILURE(status)) {
-                       printk(LOG_PFX "unable to walk acpi resources\n");
+                       printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n");
                        result = -ENODEV;
                        goto outwalk;
                }
        }
 
-       status = acpi_install_notify_handler(sony_acpi_handle,
+       /* setup input devices and helper fifo */
+       result = sony_laptop_setup_input();
+       if (result) {
+               printk(KERN_ERR DRV_PFX
+                               "Unabe to create input devices.\n");
+               goto outwalk;
+       }
+
+       status = acpi_install_notify_handler(sony_nc_acpi_handle,
                                             ACPI_DEVICE_NOTIFY,
                                             sony_acpi_notify, NULL);
        if (ACPI_FAILURE(status)) {
-               printk(LOG_PFX "unable to install notify handler\n");
+               printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
                result = -ENODEV;
-               goto outwalk;
+               goto outinput;
        }
 
-       if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, "GBRT", &handle))) {
+       if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) {
                sony_backlight_device = backlight_device_register("sony", NULL,
                                                                  NULL,
                                                                  &sony_backlight_ops);
 
                if (IS_ERR(sony_backlight_device)) {
-                       printk(LOG_PFX "unable to register backlight device\n");
+                       printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
                        sony_backlight_device = NULL;
                } else {
                        sony_backlight_device->props.brightness =
@@ -497,68 +795,1497 @@ static int sony_acpi_add(struct acpi_device *device)
 
        }
 
-       if (sony_snc_pf_add())
+       result = sony_pf_add();
+       if (result)
                goto outbacklight;
 
-       printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n");
+       /* create sony_pf sysfs attributes related to the SNC device */
+       for (item = sony_nc_values; item->name; ++item) {
+
+               if (!debug && item->debug)
+                       continue;
+
+               /* find the available acpiget as described in the DSDT */
+               for (; item->acpiget && *item->acpiget; ++item->acpiget) {
+                       if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
+                                                        *item->acpiget,
+                                                        &handle))) {
+                               dprintk("Found %s getter: %s\n",
+                                               item->name, *item->acpiget);
+                               item->devattr.attr.mode |= S_IRUGO;
+                               break;
+                       }
+               }
+
+               /* find the available acpiset as described in the DSDT */
+               for (; item->acpiset && *item->acpiset; ++item->acpiset) {
+                       if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
+                                                        *item->acpiset,
+                                                        &handle))) {
+                               dprintk("Found %s setter: %s\n",
+                                               item->name, *item->acpiset);
+                               item->devattr.attr.mode |= S_IWUSR;
+                               break;
+                       }
+               }
+
+               if (item->devattr.attr.mode != 0) {
+                       result =
+                           device_create_file(&sony_pf_device->dev,
+                                              &item->devattr);
+                       if (result)
+                               goto out_sysfs;
+               }
+       }
 
        return 0;
 
+      out_sysfs:
+       for (item = sony_nc_values; item->name; ++item) {
+               device_remove_file(&sony_pf_device->dev, &item->devattr);
+       }
+       sony_pf_remove();
+
       outbacklight:
        if (sony_backlight_device)
                backlight_device_unregister(sony_backlight_device);
 
-       status = acpi_remove_notify_handler(sony_acpi_handle,
+       status = acpi_remove_notify_handler(sony_nc_acpi_handle,
                                            ACPI_DEVICE_NOTIFY,
                                            sony_acpi_notify);
        if (ACPI_FAILURE(status))
-               printk(LOG_PFX "unable to remove notify handler\n");
+               printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
+
+      outinput:
+       sony_laptop_remove_input();
+
       outwalk:
        return result;
 }
 
-static int sony_acpi_remove(struct acpi_device *device, int type)
+static int sony_nc_remove(struct acpi_device *device, int type)
 {
        acpi_status status;
+       struct sony_nc_value *item;
 
        if (sony_backlight_device)
                backlight_device_unregister(sony_backlight_device);
 
-       sony_acpi_acpi_device = NULL;
+       sony_nc_acpi_device = NULL;
 
-       status = acpi_remove_notify_handler(sony_acpi_handle,
+       status = acpi_remove_notify_handler(sony_nc_acpi_handle,
                                            ACPI_DEVICE_NOTIFY,
                                            sony_acpi_notify);
        if (ACPI_FAILURE(status))
-               printk(LOG_PFX "unable to remove notify handler\n");
+               printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
 
-       sony_snc_pf_remove();
+       for (item = sony_nc_values; item->name; ++item) {
+               device_remove_file(&sony_pf_device->dev, &item->devattr);
+       }
 
-       printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n");
+       sony_pf_remove();
+       sony_laptop_remove_input();
+       dprintk(SONY_NC_DRIVER_NAME " removed.\n");
 
        return 0;
 }
 
-static struct acpi_driver sony_acpi_driver = {
-       .name = ACPI_SNC_DRIVER_NAME,
-       .class = ACPI_SNC_CLASS,
-       .ids = ACPI_SNC_HID,
+static struct acpi_driver sony_nc_driver = {
+       .name = SONY_NC_DRIVER_NAME,
+       .class = SONY_NC_CLASS,
+       .ids = SONY_NC_HID,
+       .owner = THIS_MODULE,
        .ops = {
-               .add = sony_acpi_add,
-               .remove = sony_acpi_remove,
-               .resume = sony_acpi_resume,
+               .add = sony_nc_add,
+               .remove = sony_nc_remove,
+               .resume = sony_nc_resume,
                },
 };
 
-static int __init sony_acpi_init(void)
-{
-       return acpi_bus_register_driver(&sony_acpi_driver);
+/*********** SPIC (SNY6001) Device ***********/
+
+#define SONYPI_DEVICE_TYPE1    0x00000001
+#define SONYPI_DEVICE_TYPE2    0x00000002
+#define SONYPI_DEVICE_TYPE3    0x00000004
+
+#define SONY_PIC_EV_MASK       0xff
+
+struct sony_pic_ioport {
+       struct acpi_resource_io io;
+       struct list_head        list;
+};
+
+struct sony_pic_irq {
+       struct acpi_resource_irq        irq;
+       struct list_head                list;
+};
+
+struct sony_pic_dev {
+       int                     model;
+       u8                      camera_power;
+       u8                      bluetooth_power;
+       u8                      wwan_power;
+       struct acpi_device      *acpi_dev;
+       struct sony_pic_irq     *cur_irq;
+       struct sony_pic_ioport  *cur_ioport;
+       struct list_head        interrupts;
+       struct list_head        ioports;
+       struct mutex            lock;
+};
+
+static struct sony_pic_dev spic_dev = {
+       .interrupts     = LIST_HEAD_INIT(spic_dev.interrupts),
+       .ioports        = LIST_HEAD_INIT(spic_dev.ioports),
+};
+
+/* Event masks */
+#define SONYPI_JOGGER_MASK                     0x00000001
+#define SONYPI_CAPTURE_MASK                    0x00000002
+#define SONYPI_FNKEY_MASK                      0x00000004
+#define SONYPI_BLUETOOTH_MASK                  0x00000008
+#define SONYPI_PKEY_MASK                       0x00000010
+#define SONYPI_BACK_MASK                       0x00000020
+#define SONYPI_HELP_MASK                       0x00000040
+#define SONYPI_LID_MASK                                0x00000080
+#define SONYPI_ZOOM_MASK                       0x00000100
+#define SONYPI_THUMBPHRASE_MASK                        0x00000200
+#define SONYPI_MEYE_MASK                       0x00000400
+#define SONYPI_MEMORYSTICK_MASK                        0x00000800
+#define SONYPI_BATTERY_MASK                    0x00001000
+#define SONYPI_WIRELESS_MASK                   0x00002000
+
+struct sonypi_event {
+       u8      data;
+       u8      event;
+};
+
+/* The set of possible button release events */
+static struct sonypi_event sonypi_releaseev[] = {
+       { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
+       { 0, 0 }
+};
+
+/* The set of possible jogger events  */
+static struct sonypi_event sonypi_joggerev[] = {
+       { 0x1f, SONYPI_EVENT_JOGDIAL_UP },
+       { 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
+       { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
+       { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
+       { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
+       { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
+       { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
+       { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
+       { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
+       { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
+       { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
+       { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
+       { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
+       { 0, 0 }
+};
+
+/* The set of possible capture button events */
+static struct sonypi_event sonypi_captureev[] = {
+       { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
+       { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
+       { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
+       { 0, 0 }
+};
+
+/* The set of possible fnkeys events */
+static struct sonypi_event sonypi_fnkeyev[] = {
+       { 0x10, SONYPI_EVENT_FNKEY_ESC },
+       { 0x11, SONYPI_EVENT_FNKEY_F1 },
+       { 0x12, SONYPI_EVENT_FNKEY_F2 },
+       { 0x13, SONYPI_EVENT_FNKEY_F3 },
+       { 0x14, SONYPI_EVENT_FNKEY_F4 },
+       { 0x15, SONYPI_EVENT_FNKEY_F5 },
+       { 0x16, SONYPI_EVENT_FNKEY_F6 },
+       { 0x17, SONYPI_EVENT_FNKEY_F7 },
+       { 0x18, SONYPI_EVENT_FNKEY_F8 },
+       { 0x19, SONYPI_EVENT_FNKEY_F9 },
+       { 0x1a, SONYPI_EVENT_FNKEY_F10 },
+       { 0x1b, SONYPI_EVENT_FNKEY_F11 },
+       { 0x1c, SONYPI_EVENT_FNKEY_F12 },
+       { 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
+       { 0x21, SONYPI_EVENT_FNKEY_1 },
+       { 0x22, SONYPI_EVENT_FNKEY_2 },
+       { 0x31, SONYPI_EVENT_FNKEY_D },
+       { 0x32, SONYPI_EVENT_FNKEY_E },
+       { 0x33, SONYPI_EVENT_FNKEY_F },
+       { 0x34, SONYPI_EVENT_FNKEY_S },
+       { 0x35, SONYPI_EVENT_FNKEY_B },
+       { 0x36, SONYPI_EVENT_FNKEY_ONLY },
+       { 0, 0 }
+};
+
+/* The set of possible program key events */
+static struct sonypi_event sonypi_pkeyev[] = {
+       { 0x01, SONYPI_EVENT_PKEY_P1 },
+       { 0x02, SONYPI_EVENT_PKEY_P2 },
+       { 0x04, SONYPI_EVENT_PKEY_P3 },
+       { 0x5c, SONYPI_EVENT_PKEY_P1 },
+       { 0, 0 }
+};
+
+/* The set of possible bluetooth events */
+static struct sonypi_event sonypi_blueev[] = {
+       { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
+       { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
+       { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
+       { 0, 0 }
+};
+
+/* The set of possible wireless events */
+static struct sonypi_event sonypi_wlessev[] = {
+       { 0x59, SONYPI_EVENT_WIRELESS_ON },
+       { 0x5a, SONYPI_EVENT_WIRELESS_OFF },
+       { 0, 0 }
+};
+
+/* The set of possible back button events */
+static struct sonypi_event sonypi_backev[] = {
+       { 0x20, SONYPI_EVENT_BACK_PRESSED },
+       { 0, 0 }
+};
+
+/* The set of possible help button events */
+static struct sonypi_event sonypi_helpev[] = {
+       { 0x3b, SONYPI_EVENT_HELP_PRESSED },
+       { 0, 0 }
+};
+
+
+/* The set of possible lid events */
+static struct sonypi_event sonypi_lidev[] = {
+       { 0x51, SONYPI_EVENT_LID_CLOSED },
+       { 0x50, SONYPI_EVENT_LID_OPENED },
+       { 0, 0 }
+};
+
+/* The set of possible zoom events */
+static struct sonypi_event sonypi_zoomev[] = {
+       { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
+       { 0, 0 }
+};
+
+/* The set of possible thumbphrase events */
+static struct sonypi_event sonypi_thumbphraseev[] = {
+       { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
+       { 0, 0 }
+};
+
+/* The set of possible motioneye camera events */
+static struct sonypi_event sonypi_meyeev[] = {
+       { 0x00, SONYPI_EVENT_MEYE_FACE },
+       { 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
+       { 0, 0 }
+};
+
+/* The set of possible memorystick events */
+static struct sonypi_event sonypi_memorystickev[] = {
+       { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
+       { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
+       { 0, 0 }
+};
+
+/* The set of possible battery events */
+static struct sonypi_event sonypi_batteryev[] = {
+       { 0x20, SONYPI_EVENT_BATTERY_INSERT },
+       { 0x30, SONYPI_EVENT_BATTERY_REMOVE },
+       { 0, 0 }
+};
+
+static struct sonypi_eventtypes {
+       int                     model;
+       u8                      data;
+       unsigned long           mask;
+       struct sonypi_event *   events;
+} sony_pic_eventtypes[] = {
+       { SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev },
+       { SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
+       { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
+       { SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
+       { SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
+       { SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+       { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+       { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
+       { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+       { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
+
+       { SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev },
+       { SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
+       { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
+       { SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
+       { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+       { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+       { SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
+       { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
+       { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
+       { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
+       { SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
+       { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+       { SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+       { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+
+       { SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev },
+       { SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+       { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+       { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+       { SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+       { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+       { 0 }
+};
+
+static int sony_pic_detect_device_type(void)
+{
+       struct pci_dev *pcidev;
+       int model = 0;
+
+       if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                    PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+               model = SONYPI_DEVICE_TYPE1;
+
+       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                         PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+               model = SONYPI_DEVICE_TYPE3;
+
+       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                         PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
+               model = SONYPI_DEVICE_TYPE3;
+
+       else
+               model = SONYPI_DEVICE_TYPE2;
+
+       if (pcidev)
+               pci_dev_put(pcidev);
+
+       printk(KERN_INFO DRV_PFX "detected Type%d model\n",
+                       model == SONYPI_DEVICE_TYPE1 ? 1 :
+                       model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
+       return model;
+}
+
+#define ITERATIONS_LONG                10000
+#define ITERATIONS_SHORT       10
+#define wait_on_command(command, iterations) {                         \
+       unsigned int n = iterations;                                    \
+       while (--n && (command))                                        \
+               udelay(1);                                              \
+       if (!n)                                                         \
+               dprintk("command failed at %s : %s (line %d)\n",        \
+                               __FILE__, __FUNCTION__, __LINE__);      \
+}
+
+static u8 sony_pic_call1(u8 dev)
+{
+       u8 v1, v2;
+
+       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+                       ITERATIONS_LONG);
+       outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+       v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4);
+       v2 = inb_p(spic_dev.cur_ioport->io.minimum);
+       dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
+       return v2;
+}
+
+static u8 sony_pic_call2(u8 dev, u8 fn)
+{
+       u8 v1;
+
+       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+                       ITERATIONS_LONG);
+       outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+                       ITERATIONS_LONG);
+       outb(fn, spic_dev.cur_ioport->io.minimum);
+       v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+       dprintk("sony_pic_call2: 0x%.4x\n", v1);
+       return v1;
+}
+
+static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
+{
+       u8 v1;
+
+       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+       outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+       outb(fn, spic_dev.cur_ioport->io.minimum);
+       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+       outb(v, spic_dev.cur_ioport->io.minimum);
+       v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+       dprintk("sony_pic_call3: 0x%.4x\n", v1);
+       return v1;
+}
+
+/* camera tests and poweron/poweroff */
+#define SONYPI_CAMERA_PICTURE          5
+#define SONYPI_CAMERA_CONTROL          0x10
+
+#define SONYPI_CAMERA_BRIGHTNESS               0
+#define SONYPI_CAMERA_CONTRAST                 1
+#define SONYPI_CAMERA_HUE                      2
+#define SONYPI_CAMERA_COLOR                    3
+#define SONYPI_CAMERA_SHARPNESS                        4
+
+#define SONYPI_CAMERA_EXPOSURE_MASK            0xC
+#define SONYPI_CAMERA_WHITE_BALANCE_MASK       0x3
+#define SONYPI_CAMERA_PICTURE_MODE_MASK                0x30
+#define SONYPI_CAMERA_MUTE_MASK                        0x40
+
+/* the rest don't need a loop until not 0xff */
+#define SONYPI_CAMERA_AGC                      6
+#define SONYPI_CAMERA_AGC_MASK                 0x30
+#define SONYPI_CAMERA_SHUTTER_MASK             0x7
+
+#define SONYPI_CAMERA_SHUTDOWN_REQUEST         7
+#define SONYPI_CAMERA_CONTROL                  0x10
+
+#define SONYPI_CAMERA_STATUS                   7
+#define SONYPI_CAMERA_STATUS_READY             0x2
+#define SONYPI_CAMERA_STATUS_POSITION          0x4
+
+#define SONYPI_DIRECTION_BACKWARDS             0x4
+
+#define SONYPI_CAMERA_REVISION                         8
+#define SONYPI_CAMERA_ROMVERSION               9
+
+static int __sony_pic_camera_ready(void)
+{
+       u8 v;
+
+       v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
+       return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
+}
+
+static int __sony_pic_camera_off(void)
+{
+       if (!camera) {
+               printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+               return -ENODEV;
+       }
+
+       wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
+                               SONYPI_CAMERA_MUTE_MASK),
+                       ITERATIONS_SHORT);
+
+       if (spic_dev.camera_power) {
+               sony_pic_call2(0x91, 0);
+               spic_dev.camera_power = 0;
+       }
+       return 0;
+}
+
+static int __sony_pic_camera_on(void)
+{
+       int i, j, x;
+
+       if (!camera) {
+               printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+               return -ENODEV;
+       }
+
+       if (spic_dev.camera_power)
+               return 0;
+
+       for (j = 5; j > 0; j--) {
+
+               for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
+                       msleep(10);
+               sony_pic_call1(0x93);
+
+               for (i = 400; i > 0; i--) {
+                       if (__sony_pic_camera_ready())
+                               break;
+                       msleep(10);
+               }
+               if (i)
+                       break;
+       }
+
+       if (j == 0) {
+               printk(KERN_WARNING DRV_PFX "failed to power on camera\n");
+               return -ENODEV;
+       }
+
+       wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
+                               0x5a),
+                       ITERATIONS_SHORT);
+
+       spic_dev.camera_power = 1;
+       return 0;
+}
+
+/* External camera command (exported to the motion eye v4l driver) */
+int sony_pic_camera_command(int command, u8 value)
+{
+       if (!camera)
+               return -EIO;
+
+       mutex_lock(&spic_dev.lock);
+
+       switch (command) {
+       case SONY_PIC_COMMAND_SETCAMERA:
+               if (value)
+                       __sony_pic_camera_on();
+               else
+                       __sony_pic_camera_off();
+               break;
+       case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
+               wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
+                               ITERATIONS_SHORT);
+               break;
+       case SONY_PIC_COMMAND_SETCAMERACONTRAST:
+               wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
+                               ITERATIONS_SHORT);
+               break;
+       case SONY_PIC_COMMAND_SETCAMERAHUE:
+               wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
+                               ITERATIONS_SHORT);
+               break;
+       case SONY_PIC_COMMAND_SETCAMERACOLOR:
+               wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
+                               ITERATIONS_SHORT);
+               break;
+       case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
+               wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
+                               ITERATIONS_SHORT);
+               break;
+       case SONY_PIC_COMMAND_SETCAMERAPICTURE:
+               wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
+                               ITERATIONS_SHORT);
+               break;
+       case SONY_PIC_COMMAND_SETCAMERAAGC:
+               wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
+                               ITERATIONS_SHORT);
+               break;
+       default:
+               printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n",
+                      command);
+               break;
+       }
+       mutex_unlock(&spic_dev.lock);
+       return 0;
+}
+EXPORT_SYMBOL(sony_pic_camera_command);
+
+/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */
+static void sony_pic_set_wwanpower(u8 state)
+{
+       state = !!state;
+       mutex_lock(&spic_dev.lock);
+       if (spic_dev.wwan_power == state) {
+               mutex_unlock(&spic_dev.lock);
+               return;
+       }
+       sony_pic_call2(0xB0, state);
+       spic_dev.wwan_power = state;
+       mutex_unlock(&spic_dev.lock);
+}
+
+static ssize_t sony_pic_wwanpower_store(struct device *dev,
+               struct device_attribute *attr,
+               const char *buffer, size_t count)
+{
+       unsigned long value;
+       if (count > 31)
+               return -EINVAL;
+
+       value = simple_strtoul(buffer, NULL, 10);
+       sony_pic_set_wwanpower(value);
+
+       return count;
+}
+
+static ssize_t sony_pic_wwanpower_show(struct device *dev,
+               struct device_attribute *attr, char *buffer)
+{
+       ssize_t count;
+       mutex_lock(&spic_dev.lock);
+       count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
+       mutex_unlock(&spic_dev.lock);
+       return count;
+}
+
+/* bluetooth subsystem power state */
+static void __sony_pic_set_bluetoothpower(u8 state)
+{
+       state = !!state;
+       if (spic_dev.bluetooth_power == state)
+               return;
+       sony_pic_call2(0x96, state);
+       sony_pic_call1(0x82);
+       spic_dev.bluetooth_power = state;
+}
+
+static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
+               struct device_attribute *attr,
+               const char *buffer, size_t count)
+{
+       unsigned long value;
+       if (count > 31)
+               return -EINVAL;
+
+       value = simple_strtoul(buffer, NULL, 10);
+       mutex_lock(&spic_dev.lock);
+       __sony_pic_set_bluetoothpower(value);
+       mutex_unlock(&spic_dev.lock);
+
+       return count;
+}
+
+static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
+               struct device_attribute *attr, char *buffer)
+{
+       ssize_t count = 0;
+       mutex_lock(&spic_dev.lock);
+       count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
+       mutex_unlock(&spic_dev.lock);
+       return count;
+}
+
+/* fan speed */
+/* FAN0 information (reverse engineered from ACPI tables) */
+#define SONY_PIC_FAN0_STATUS   0x93
+static int sony_pic_set_fanspeed(unsigned long value)
+{
+       return ec_write(SONY_PIC_FAN0_STATUS, value);
+}
+
+static int sony_pic_get_fanspeed(u8 *value)
+{
+       return ec_read(SONY_PIC_FAN0_STATUS, value);
+}
+
+static ssize_t sony_pic_fanspeed_store(struct device *dev,
+               struct device_attribute *attr,
+               const char *buffer, size_t count)
+{
+       unsigned long value;
+       if (count > 31)
+               return -EINVAL;
+
+       value = simple_strtoul(buffer, NULL, 10);
+       if (sony_pic_set_fanspeed(value))
+               return -EIO;
+
+       return count;
+}
+
+static ssize_t sony_pic_fanspeed_show(struct device *dev,
+               struct device_attribute *attr, char *buffer)
+{
+       u8 value = 0;
+       if (sony_pic_get_fanspeed(&value))
+               return -EIO;
+
+       return snprintf(buffer, PAGE_SIZE, "%d\n", value);
+}
+
+#define SPIC_ATTR(_name, _mode)                                        \
+struct device_attribute spic_attr_##_name = __ATTR(_name,      \
+               _mode, sony_pic_## _name ##_show,               \
+               sony_pic_## _name ##_store)
+
+static SPIC_ATTR(bluetoothpower, 0644);
+static SPIC_ATTR(wwanpower, 0644);
+static SPIC_ATTR(fanspeed, 0644);
+
+static struct attribute *spic_attributes[] = {
+       &spic_attr_bluetoothpower.attr,
+       &spic_attr_wwanpower.attr,
+       &spic_attr_fanspeed.attr,
+       NULL
+};
+
+static struct attribute_group spic_attribute_group = {
+       .attrs = spic_attributes
+};
+
+/******** SONYPI compatibility **********/
+#ifdef CONFIG_SONY_LAPTOP_OLD
+
+/* battery / brightness / temperature  addresses */
+#define SONYPI_BAT_FLAGS       0x81
+#define SONYPI_LCD_LIGHT       0x96
+#define SONYPI_BAT1_PCTRM      0xa0
+#define SONYPI_BAT1_LEFT       0xa2
+#define SONYPI_BAT1_MAXRT      0xa4
+#define SONYPI_BAT2_PCTRM      0xa8
+#define SONYPI_BAT2_LEFT       0xaa
+#define SONYPI_BAT2_MAXRT      0xac
+#define SONYPI_BAT1_MAXTK      0xb0
+#define SONYPI_BAT1_FULL       0xb2
+#define SONYPI_BAT2_MAXTK      0xb8
+#define SONYPI_BAT2_FULL       0xba
+#define SONYPI_TEMP_STATUS     0xC1
+
+struct sonypi_compat_s {
+       struct fasync_struct    *fifo_async;
+       struct kfifo            *fifo;
+       spinlock_t              fifo_lock;
+       wait_queue_head_t       fifo_proc_list;
+       atomic_t                open_count;
+};
+static struct sonypi_compat_s sonypi_compat = {
+       .open_count = ATOMIC_INIT(0),
+};
+
+static int sonypi_misc_fasync(int fd, struct file *filp, int on)
+{
+       int retval;
+
+       retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
+       if (retval < 0)
+               return retval;
+       return 0;
+}
+
+static int sonypi_misc_release(struct inode *inode, struct file *file)
+{
+       sonypi_misc_fasync(-1, file, 0);
+       atomic_dec(&sonypi_compat.open_count);
+       return 0;
+}
+
+static int sonypi_misc_open(struct inode *inode, struct file *file)
+{
+       /* Flush input queue on first open */
+       if (atomic_inc_return(&sonypi_compat.open_count) == 1)
+               kfifo_reset(sonypi_compat.fifo);
+       return 0;
+}
+
+static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
+                               size_t count, loff_t *pos)
+{
+       ssize_t ret;
+       unsigned char c;
+
+       if ((kfifo_len(sonypi_compat.fifo) == 0) &&
+           (file->f_flags & O_NONBLOCK))
+               return -EAGAIN;
+
+       ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
+                                      kfifo_len(sonypi_compat.fifo) != 0);
+       if (ret)
+               return ret;
+
+       while (ret < count &&
+              (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) {
+               if (put_user(c, buf++))
+                       return -EFAULT;
+               ret++;
+       }
+
+       if (ret > 0) {
+               struct inode *inode = file->f_path.dentry->d_inode;
+               inode->i_atime = current_fs_time(inode->i_sb);
+       }
+
+       return ret;
+}
+
+static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
+       if (kfifo_len(sonypi_compat.fifo))
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static int ec_read16(u8 addr, u16 *value)
+{
+       u8 val_lb, val_hb;
+       if (ec_read(addr, &val_lb))
+               return -1;
+       if (ec_read(addr + 1, &val_hb))
+               return -1;
+       *value = val_lb | (val_hb << 8);
+       return 0;
+}
+
+static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
+                            unsigned int cmd, unsigned long arg)
+{
+       int ret = 0;
+       void __user *argp = (void __user *)arg;
+       u8 val8;
+       u16 val16;
+       int value;
+
+       mutex_lock(&spic_dev.lock);
+       switch (cmd) {
+       case SONYPI_IOCGBRT:
+               if (sony_backlight_device == NULL) {
+                       ret = -EIO;
+                       break;
+               }
+               if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) {
+                       ret = -EIO;
+                       break;
+               }
+               val8 = ((value & 0xff) - 1) << 5;
+               if (copy_to_user(argp, &val8, sizeof(val8)))
+                               ret = -EFAULT;
+               break;
+       case SONYPI_IOCSBRT:
+               if (sony_backlight_device == NULL) {
+                       ret = -EIO;
+                       break;
+               }
+               if (copy_from_user(&val8, argp, sizeof(val8))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
+                               (val8 >> 5) + 1, NULL)) {
+                       ret = -EIO;
+                       break;
+               }
+               /* sync the backlight device status */
+               sony_backlight_device->props.brightness =
+                   sony_backlight_get_brightness(sony_backlight_device);
+               break;
+       case SONYPI_IOCGBAT1CAP:
+               if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+                       ret = -EIO;
+                       break;
+               }
+               if (copy_to_user(argp, &val16, sizeof(val16)))
+                       ret = -EFAULT;
+               break;
+       case SONYPI_IOCGBAT1REM:
+               if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
+                       ret = -EIO;
+                       break;
+               }
+               if (copy_to_user(argp, &val16, sizeof(val16)))
+                       ret = -EFAULT;
+               break;
+       case SONYPI_IOCGBAT2CAP:
+               if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
+                       ret = -EIO;
+                       break;
+               }
+               if (copy_to_user(argp, &val16, sizeof(val16)))
+                       ret = -EFAULT;
+               break;
+       case SONYPI_IOCGBAT2REM:
+               if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
+                       ret = -EIO;
+                       break;
+               }
+               if (copy_to_user(argp, &val16, sizeof(val16)))
+                       ret = -EFAULT;
+               break;
+       case SONYPI_IOCGBATFLAGS:
+               if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
+                       ret = -EIO;
+                       break;
+               }
+               val8 &= 0x07;
+               if (copy_to_user(argp, &val8, sizeof(val8)))
+                       ret = -EFAULT;
+               break;
+       case SONYPI_IOCGBLUE:
+               val8 = spic_dev.bluetooth_power;
+               if (copy_to_user(argp, &val8, sizeof(val8)))
+                       ret = -EFAULT;
+               break;
+       case SONYPI_IOCSBLUE:
+               if (copy_from_user(&val8, argp, sizeof(val8))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               __sony_pic_set_bluetoothpower(val8);
+               break;
+       /* FAN Controls */
+       case SONYPI_IOCGFAN:
+               if (sony_pic_get_fanspeed(&val8)) {
+                       ret = -EIO;
+                       break;
+               }
+               if (copy_to_user(argp, &val8, sizeof(val8)))
+                       ret = -EFAULT;
+               break;
+       case SONYPI_IOCSFAN:
+               if (copy_from_user(&val8, argp, sizeof(val8))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (sony_pic_set_fanspeed(val8))
+                       ret = -EIO;
+               break;
+       /* GET Temperature (useful under APM) */
+       case SONYPI_IOCGTEMP:
+               if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
+                       ret = -EIO;
+                       break;
+               }
+               if (copy_to_user(argp, &val8, sizeof(val8)))
+                       ret = -EFAULT;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       mutex_unlock(&spic_dev.lock);
+       return ret;
+}
+
+static const struct file_operations sonypi_misc_fops = {
+       .owner          = THIS_MODULE,
+       .read           = sonypi_misc_read,
+       .poll           = sonypi_misc_poll,
+       .open           = sonypi_misc_open,
+       .release        = sonypi_misc_release,
+       .fasync         = sonypi_misc_fasync,
+       .ioctl          = sonypi_misc_ioctl,
+};
+
+static struct miscdevice sonypi_misc_device = {
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = "sonypi",
+       .fops           = &sonypi_misc_fops,
+};
+
+static void sonypi_compat_report_event(u8 event)
+{
+       kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));
+       kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
+       wake_up_interruptible(&sonypi_compat.fifo_proc_list);
+}
+
+static int sonypi_compat_init(void)
+{
+       int error;
+
+       spin_lock_init(&sonypi_compat.fifo_lock);
+       sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
+                                        &sonypi_compat.fifo_lock);
+       if (IS_ERR(sonypi_compat.fifo)) {
+               printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+               return PTR_ERR(sonypi_compat.fifo);
+       }
+
+       init_waitqueue_head(&sonypi_compat.fifo_proc_list);
+
+       if (minor != -1)
+               sonypi_misc_device.minor = minor;
+       error = misc_register(&sonypi_misc_device);
+       if (error) {
+               printk(KERN_ERR DRV_PFX "misc_register failed\n");
+               goto err_free_kfifo;
+       }
+       if (minor == -1)
+               printk(KERN_INFO DRV_PFX "device allocated minor is %d\n",
+                      sonypi_misc_device.minor);
+
+       return 0;
+
+err_free_kfifo:
+       kfifo_free(sonypi_compat.fifo);
+       return error;
+}
+
+static void sonypi_compat_exit(void)
+{
+       misc_deregister(&sonypi_misc_device);
+       kfifo_free(sonypi_compat.fifo);
+}
+#else
+static int sonypi_compat_init(void) { return 0; }
+static void sonypi_compat_exit(void) { }
+static void sonypi_compat_report_event(u8 event) { }
+#endif /* CONFIG_SONY_LAPTOP_OLD */
+
+/*
+ * ACPI callbacks
+ */
+static acpi_status
+sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
+{
+       u32 i;
+       struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
+
+       switch (resource->type) {
+       case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+       case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+               return AE_OK;
+
+       case ACPI_RESOURCE_TYPE_IRQ:
+               {
+                       struct acpi_resource_irq *p = &resource->data.irq;
+                       struct sony_pic_irq *interrupt = NULL;
+                       if (!p || !p->interrupt_count) {
+                               /*
+                                * IRQ descriptors may have no IRQ# bits set,
+                                * particularly those those w/ _STA disabled
+                                */
+                               dprintk("Blank IRQ resource\n");
+                               return AE_OK;
+                       }
+                       for (i = 0; i < p->interrupt_count; i++) {
+                               if (!p->interrupts[i]) {
+                                       printk(KERN_WARNING DRV_PFX
+                                                       "Invalid IRQ %d\n",
+                                                       p->interrupts[i]);
+                                       continue;
+                               }
+                               interrupt = kzalloc(sizeof(*interrupt),
+                                               GFP_KERNEL);
+                               if (!interrupt)
+                                       return AE_ERROR;
+
+                               list_add_tail(&interrupt->list, &dev->interrupts);
+                               interrupt->irq.triggering = p->triggering;
+                               interrupt->irq.polarity = p->polarity;
+                               interrupt->irq.sharable = p->sharable;
+                               interrupt->irq.interrupt_count = 1;
+                               interrupt->irq.interrupts[0] = p->interrupts[i];
+                       }
+                       return AE_OK;
+               }
+       case ACPI_RESOURCE_TYPE_IO:
+               {
+                       struct acpi_resource_io *io = &resource->data.io;
+                       struct sony_pic_ioport *ioport = NULL;
+                       if (!io) {
+                               dprintk("Blank IO resource\n");
+                               return AE_OK;
+                       }
+
+                       ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
+                       if (!ioport)
+                               return AE_ERROR;
+
+                       list_add_tail(&ioport->list, &dev->ioports);
+                       memcpy(&ioport->io, io, sizeof(*io));
+                       return AE_OK;
+               }
+       default:
+               dprintk("Resource %d isn't an IRQ nor an IO port\n",
+                               resource->type);
+
+       case ACPI_RESOURCE_TYPE_END_TAG:
+               return AE_OK;
+       }
+       return AE_CTRL_TERMINATE;
+}
+
+static int sony_pic_possible_resources(struct acpi_device *device)
+{
+       int result = 0;
+       acpi_status status = AE_OK;
+
+       if (!device)
+               return -EINVAL;
+
+       /* get device status */
+       /* see acpi_pci_link_get_current acpi_pci_link_get_possible */
+       dprintk("Evaluating _STA\n");
+       result = acpi_bus_get_status(device);
+       if (result) {
+               printk(KERN_WARNING DRV_PFX "Unable to read status\n");
+               goto end;
+       }
+
+       if (!device->status.enabled)
+               dprintk("Device disabled\n");
+       else
+               dprintk("Device enabled\n");
+
+       /*
+        * Query and parse 'method'
+        */
+       dprintk("Evaluating %s\n", METHOD_NAME__PRS);
+       status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
+                       sony_pic_read_possible_resource, &spic_dev);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_WARNING DRV_PFX
+                               "Failure evaluating %s\n",
+                               METHOD_NAME__PRS);
+               result = -ENODEV;
+       }
+end:
+       return result;
+}
+
+/*
+ *  Disable the spic device by calling its _DIS method
+ */
+static int sony_pic_disable(struct acpi_device *device)
+{
+       if (ACPI_FAILURE(acpi_evaluate_object(device->handle, "_DIS", 0, NULL)))
+               return -ENXIO;
+
+       dprintk("Device disabled\n");
+       return 0;
+}
+
+
+/*
+ *  Based on drivers/acpi/pci_link.c:acpi_pci_link_set
+ *
+ *  Call _SRS to set current resources
+ */
+static int sony_pic_enable(struct acpi_device *device,
+               struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
+{
+       acpi_status status;
+       int result = 0;
+       struct {
+               struct acpi_resource io_res;
+               struct acpi_resource irq_res;
+               struct acpi_resource end;
+       } *resource;
+       struct acpi_buffer buffer = { 0, NULL };
+
+       if (!ioport || !irq)
+               return -EINVAL;
+
+       /* init acpi_buffer */
+       resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
+       if (!resource)
+               return -ENOMEM;
+
+       buffer.length = sizeof(*resource) + 1;
+       buffer.pointer = resource;
+
+       /* setup io resource */
+       resource->io_res.type = ACPI_RESOURCE_TYPE_IO;
+       resource->io_res.length = sizeof(struct acpi_resource);
+       memcpy(&resource->io_res.data.io, &ioport->io,
+                       sizeof(struct acpi_resource_io));
+
+       /* setup irq resource */
+       resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ;
+       resource->irq_res.length = sizeof(struct acpi_resource);
+       memcpy(&resource->irq_res.data.irq, &irq->irq,
+                       sizeof(struct acpi_resource_irq));
+       /* we requested a shared irq */
+       resource->irq_res.data.irq.sharable = ACPI_SHARED;
+
+       resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
+
+       /* Attempt to set the resource */
+       dprintk("Evaluating _SRS\n");
+       status = acpi_set_current_resources(device->handle, &buffer);
+
+       /* check for total failure */
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR DRV_PFX "Error evaluating _SRS");
+               result = -ENODEV;
+               goto end;
+       }
+
+       /* Necessary device initializations calls (from sonypi) */
+       sony_pic_call1(0x82);
+       sony_pic_call2(0x81, 0xff);
+       sony_pic_call1(compat ? 0x92 : 0x82);
+
+end:
+       kfree(resource);
+       return result;
+}
+
+/*****************
+ *
+ * ISR: some event is available
+ *
+ *****************/
+static irqreturn_t sony_pic_irq(int irq, void *dev_id)
+{
+       int i, j;
+       u32 port_val = 0;
+       u8 ev = 0;
+       u8 data_mask = 0;
+       u8 device_event = 0;
+
+       struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
+
+       acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
+                       dev->cur_ioport->io.address_length);
+       ev = port_val & SONY_PIC_EV_MASK;
+       data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
+
+       dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
+                       port_val, ev, data_mask, dev->cur_ioport->io.minimum);
+
+       if (ev == 0x00 || ev == 0xff)
+               return IRQ_HANDLED;
+
+       for (i = 0; sony_pic_eventtypes[i].model; i++) {
+
+               if (spic_dev.model != sony_pic_eventtypes[i].model)
+                       continue;
+
+               if ((data_mask & sony_pic_eventtypes[i].data) !=
+                   sony_pic_eventtypes[i].data)
+                       continue;
+
+               if (!(mask & sony_pic_eventtypes[i].mask))
+                       continue;
+
+               for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) {
+                       if (ev == sony_pic_eventtypes[i].events[j].data) {
+                               device_event =
+                                       sony_pic_eventtypes[i].events[j].event;
+                               goto found;
+                       }
+               }
+       }
+       return IRQ_HANDLED;
+
+found:
+       sony_laptop_report_input_event(device_event);
+       acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event);
+       sonypi_compat_report_event(device_event);
+
+       return IRQ_HANDLED;
+}
+
+/*****************
+ *
+ *  ACPI driver
+ *
+ *****************/
+static int sony_pic_remove(struct acpi_device *device, int type)
+{
+       struct sony_pic_ioport *io, *tmp_io;
+       struct sony_pic_irq *irq, *tmp_irq;
+
+       sonypi_compat_exit();
+
+       if (sony_pic_disable(device)) {
+               printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");
+               return -ENXIO;
+       }
+
+       free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
+       release_region(spic_dev.cur_ioport->io.minimum,
+                       spic_dev.cur_ioport->io.address_length);
+
+       sony_laptop_remove_input();
+
+       /* pf attrs */
+       sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
+       sony_pf_remove();
+
+       list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
+               list_del(&io->list);
+               kfree(io);
+       }
+       list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
+               list_del(&irq->list);
+               kfree(irq);
+       }
+       spic_dev.cur_ioport = NULL;
+       spic_dev.cur_irq = NULL;
+
+       dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
+       return 0;
+}
+
+static int sony_pic_add(struct acpi_device *device)
+{
+       int result;
+       struct sony_pic_ioport *io, *tmp_io;
+       struct sony_pic_irq *irq, *tmp_irq;
+
+       printk(KERN_INFO DRV_PFX "%s v%s.\n",
+               SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
+
+       spic_dev.acpi_dev = device;
+       strcpy(acpi_device_class(device), "sony/hotkey");
+       spic_dev.model = sony_pic_detect_device_type();
+       mutex_init(&spic_dev.lock);
+
+       /* read _PRS resources */
+       result = sony_pic_possible_resources(device);
+       if (result) {
+               printk(KERN_ERR DRV_PFX
+                               "Unabe to read possible resources.\n");
+               goto err_free_resources;
+       }
+
+       /* setup input devices and helper fifo */
+       result = sony_laptop_setup_input();
+       if (result) {
+               printk(KERN_ERR DRV_PFX
+                               "Unabe to create input devices.\n");
+               goto err_free_resources;
+       }
+
+       /* request io port */
+       list_for_each_entry(io, &spic_dev.ioports, list) {
+               if (request_region(io->io.minimum, io->io.address_length,
+                                       "Sony Programable I/O Device")) {
+                       dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n",
+                                       io->io.minimum, io->io.maximum,
+                                       io->io.address_length);
+                       spic_dev.cur_ioport = io;
+                       break;
+               }
+       }
+       if (!spic_dev.cur_ioport) {
+               printk(KERN_ERR DRV_PFX "Failed to request_region.\n");
+               result = -ENODEV;
+               goto err_remove_input;
+       }
+
+       /* request IRQ */
+       list_for_each_entry(irq, &spic_dev.interrupts, list) {
+               if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
+                                       IRQF_SHARED, "sony-laptop", &spic_dev)) {
+                       dprintk("IRQ: %d - triggering: %d - "
+                                       "polarity: %d - shr: %d\n",
+                                       irq->irq.interrupts[0],
+                                       irq->irq.triggering,
+                                       irq->irq.polarity,
+                                       irq->irq.sharable);
+                       spic_dev.cur_irq = irq;
+                       break;
+               }
+       }
+       if (!spic_dev.cur_irq) {
+               printk(KERN_ERR DRV_PFX "Failed to request_irq.\n");
+               result = -ENODEV;
+               goto err_release_region;
+       }
+
+       /* set resource status _SRS */
+       result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
+       if (result) {
+               printk(KERN_ERR DRV_PFX "Couldn't enable device.\n");
+               goto err_free_irq;
+       }
+
+       spic_dev.bluetooth_power = -1;
+       /* create device attributes */
+       result = sony_pf_add();
+       if (result)
+               goto err_disable_device;
+
+       result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
+       if (result)
+               goto err_remove_pf;
+
+       if (sonypi_compat_init())
+               goto err_remove_pf;
+
+       return 0;
+
+err_remove_pf:
+       sony_pf_remove();
+
+err_disable_device:
+       sony_pic_disable(device);
+
+err_free_irq:
+       free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
+
+err_release_region:
+       release_region(spic_dev.cur_ioport->io.minimum,
+                       spic_dev.cur_ioport->io.address_length);
+
+err_remove_input:
+       sony_laptop_remove_input();
+
+err_free_resources:
+       list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
+               list_del(&io->list);
+               kfree(io);
+       }
+       list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
+               list_del(&irq->list);
+               kfree(irq);
+       }
+       spic_dev.cur_ioport = NULL;
+       spic_dev.cur_irq = NULL;
+
+       return result;
+}
+
+static int sony_pic_suspend(struct acpi_device *device, pm_message_t state)
+{
+       if (sony_pic_disable(device))
+               return -ENXIO;
+       return 0;
+}
+
+static int sony_pic_resume(struct acpi_device *device)
+{
+       sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
+       return 0;
+}
+
+static struct acpi_driver sony_pic_driver = {
+       .name = SONY_PIC_DRIVER_NAME,
+       .class = SONY_PIC_CLASS,
+       .ids = SONY_PIC_HID,
+       .owner = THIS_MODULE,
+       .ops = {
+               .add = sony_pic_add,
+               .remove = sony_pic_remove,
+               .suspend = sony_pic_suspend,
+               .resume = sony_pic_resume,
+               },
+};
+
+static struct dmi_system_id __initdata sonypi_dmi_table[] = {
+       {
+               .ident = "Sony Vaio",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
+               },
+       },
+       {
+               .ident = "Sony Vaio",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
+               },
+       },
+       { }
+};
+
+static int __init sony_laptop_init(void)
+{
+       int result;
+
+       if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
+               result = acpi_bus_register_driver(&sony_pic_driver);
+               if (result) {
+                       printk(KERN_ERR DRV_PFX
+                                       "Unable to register SPIC driver.");
+                       goto out;
+               }
+       }
+
+       result = acpi_bus_register_driver(&sony_nc_driver);
+       if (result) {
+               printk(KERN_ERR DRV_PFX "Unable to register SNC driver.");
+               goto out_unregister_pic;
+       }
+
+       return 0;
+
+out_unregister_pic:
+       if (!no_spic)
+               acpi_bus_unregister_driver(&sony_pic_driver);
+out:
+       return result;
 }
 
-static void __exit sony_acpi_exit(void)
+static void __exit sony_laptop_exit(void)
 {
-       acpi_bus_unregister_driver(&sony_acpi_driver);
+       acpi_bus_unregister_driver(&sony_nc_driver);
+       if (!no_spic)
+               acpi_bus_unregister_driver(&sony_pic_driver);
 }
 
-module_init(sony_acpi_init);
-module_exit(sony_acpi_exit);
+module_init(sony_laptop_init);
+module_exit(sony_laptop_exit);
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
new file mode 100644 (file)
index 0000000..6c36a55
--- /dev/null
@@ -0,0 +1,4312 @@
+/*
+ *  thinkpad_acpi.c - ThinkPad ACPI Extras
+ *
+ *
+ *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ *  Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#define IBM_VERSION "0.14"
+#define TPACPI_SYSFS_VERSION 0x000100
+
+/*
+ *  Changelog:
+ *  2007-03-27  0.14   renamed to thinkpad_acpi and moved to
+ *                     drivers/misc.
+ *
+ *  2006-11-22 0.13    new maintainer
+ *                     changelog now lives in git commit history, and will
+ *                     not be updated further in-file.
+ *
+ *  2005-08-17  0.12   fix compilation on 2.6.13-rc kernels
+ *  2005-03-17 0.11    support for 600e, 770x
+ *                         thanks to Jamie Lentin <lentinj@dial.pipex.com>
+ *                     support for 770e, G41
+ *                     G40 and G41 don't have a thinklight
+ *                     temperatures no longer experimental
+ *                     experimental brightness control
+ *                     experimental volume control
+ *                     experimental fan enable/disable
+ *  2005-01-16 0.10    fix module loading on R30, R31
+ *  2005-01-16 0.9     support for 570, R30, R31
+ *                     ultrabay support on A22p, A3x
+ *                     limit arg for cmos, led, beep, drop experimental status
+ *                     more capable led control on A21e, A22p, T20-22, X20
+ *                     experimental temperatures and fan speed
+ *                     experimental embedded controller register dump
+ *                     mark more functions as __init, drop incorrect __exit
+ *                     use MODULE_VERSION
+ *                         thanks to Henrik Brix Andersen <brix@gentoo.org>
+ *                     fix parameter passing on module loading
+ *                         thanks to Rusty Russell <rusty@rustcorp.com.au>
+ *                         thanks to Jim Radford <radford@blackbean.org>
+ *  2004-11-08 0.8     fix init error case, don't return from a macro
+ *                         thanks to Chris Wright <chrisw@osdl.org>
+ *  2004-10-23 0.7     fix module loading on A21e, A22p, T20, T21, X20
+ *                     fix led control on A21e
+ *  2004-10-19 0.6     use acpi_bus_register_driver() to claim HKEY device
+ *  2004-10-18 0.5     thinklight support on A21e, G40, R32, T20, T21, X20
+ *                     proc file format changed
+ *                     video_switch command
+ *                     experimental cmos control
+ *                     experimental led control
+ *                     experimental acpi sounds
+ *  2004-09-16 0.4     support for module parameters
+ *                     hotkey mask can be prefixed by 0x
+ *                     video output switching
+ *                     video expansion control
+ *                     ultrabay eject support
+ *                     removed lcd brightness/on/off control, didn't work
+ *  2004-08-17 0.3     support for R40
+ *                     lcd off, brightness control
+ *                     thinklight on/off
+ *  2004-08-14 0.2     support for T series, X20
+ *                     bluetooth enable/disable
+ *                     hotkey events disabled by default
+ *                     removed fan control, currently useless
+ *  2004-08-09 0.1     initial release, support for X series
+ */
+
+#include "thinkpad_acpi.h"
+
+MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
+MODULE_DESCRIPTION(IBM_DESC);
+MODULE_VERSION(IBM_VERSION);
+MODULE_LICENSE("GPL");
+
+/* Please remove this in year 2009 */
+MODULE_ALIAS("ibm_acpi");
+
+#define __unused __attribute__ ((unused))
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * ACPI Helpers and device model
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/*************************************************************************
+ * ACPI basic handles
+ */
+
+static acpi_handle root_handle = NULL;
+
+#define IBM_HANDLE(object, parent, paths...)                   \
+       static acpi_handle  object##_handle;                    \
+       static acpi_handle *object##_parent = &parent##_handle; \
+       static char        *object##_path;                      \
+       static char        *object##_paths[] = { paths }
+
+IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",     /* 240, 240x */
+          "\\_SB.PCI.ISA.EC",  /* 570 */
+          "\\_SB.PCI0.ISA0.EC0",       /* 600e/x, 770e, 770x */
+          "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
+          "\\_SB.PCI0.AD4S.EC0",       /* i1400, R30 */
+          "\\_SB.PCI0.ICH3.EC0",       /* R31 */
+          "\\_SB.PCI0.LPC.EC", /* all others */
+          );
+
+IBM_HANDLE(ecrd, ec, "ECRD");  /* 570 */
+IBM_HANDLE(ecwr, ec, "ECWR");  /* 570 */
+
+
+/*************************************************************************
+ * Misc ACPI handles
+ */
+
+IBM_HANDLE(cmos, root, "\\UCMS",       /* R50, R50e, R50p, R51, T4x, X31, X40 */
+          "\\CMOS",            /* A3x, G4x, R32, T23, T30, X22-24, X30 */
+          "\\CMS",             /* R40, R40e */
+          );                   /* all others */
+
+IBM_HANDLE(hkey, ec, "\\_SB.HKEY",     /* 600e/x, 770e, 770x */
+          "^HKEY",             /* R30, R31 */
+          "HKEY",              /* all others */
+          );                   /* 570 */
+
+
+/*************************************************************************
+ * ACPI helpers
+ */
+
+static int acpi_evalf(acpi_handle handle,
+                     void *res, char *method, char *fmt, ...)
+{
+       char *fmt0 = fmt;
+       struct acpi_object_list params;
+       union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
+       struct acpi_buffer result, *resultp;
+       union acpi_object out_obj;
+       acpi_status status;
+       va_list ap;
+       char res_type;
+       int success;
+       int quiet;
+
+       if (!*fmt) {
+               printk(IBM_ERR "acpi_evalf() called with empty format\n");
+               return 0;
+       }
+
+       if (*fmt == 'q') {
+               quiet = 1;
+               fmt++;
+       } else
+               quiet = 0;
+
+       res_type = *(fmt++);
+
+       params.count = 0;
+       params.pointer = &in_objs[0];
+
+       va_start(ap, fmt);
+       while (*fmt) {
+               char c = *(fmt++);
+               switch (c) {
+               case 'd':       /* int */
+                       in_objs[params.count].integer.value = va_arg(ap, int);
+                       in_objs[params.count++].type = ACPI_TYPE_INTEGER;
+                       break;
+                       /* add more types as needed */
+               default:
+                       printk(IBM_ERR "acpi_evalf() called "
+                              "with invalid format character '%c'\n", c);
+                       return 0;
+               }
+       }
+       va_end(ap);
+
+       if (res_type != 'v') {
+               result.length = sizeof(out_obj);
+               result.pointer = &out_obj;
+               resultp = &result;
+       } else
+               resultp = NULL;
+
+       status = acpi_evaluate_object(handle, method, &params, resultp);
+
+       switch (res_type) {
+       case 'd':               /* int */
+               if (res)
+                       *(int *)res = out_obj.integer.value;
+               success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
+               break;
+       case 'v':               /* void */
+               success = status == AE_OK;
+               break;
+               /* add more types as needed */
+       default:
+               printk(IBM_ERR "acpi_evalf() called "
+                      "with invalid format character '%c'\n", res_type);
+               return 0;
+       }
+
+       if (!success && !quiet)
+               printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
+                      method, fmt0, status);
+
+       return success;
+}
+
+static void __unused acpi_print_int(acpi_handle handle, char *method)
+{
+       int i;
+
+       if (acpi_evalf(handle, &i, method, "d"))
+               printk(IBM_INFO "%s = 0x%x\n", method, i);
+       else
+               printk(IBM_ERR "error calling %s\n", method);
+}
+
+static int acpi_ec_read(int i, u8 * p)
+{
+       int v;
+
+       if (ecrd_handle) {
+               if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
+                       return 0;
+               *p = v;
+       } else {
+               if (ec_read(i, p) < 0)
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int acpi_ec_write(int i, u8 v)
+{
+       if (ecwr_handle) {
+               if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
+                       return 0;
+       } else {
+               if (ec_write(i, v) < 0)
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int _sta(acpi_handle handle)
+{
+       int status;
+
+       if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
+               status = 0;
+
+       return status;
+}
+
+static int issue_thinkpad_cmos_command(int cmos_cmd)
+{
+       if (!cmos_handle)
+               return -ENXIO;
+
+       if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd))
+               return -EIO;
+
+       return 0;
+}
+
+/*************************************************************************
+ * ACPI device model
+ */
+
+static void drv_acpi_handle_init(char *name,
+                          acpi_handle *handle, acpi_handle parent,
+                          char **paths, int num_paths, char **path)
+{
+       int i;
+       acpi_status status;
+
+       vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n",
+               name);
+
+       for (i = 0; i < num_paths; i++) {
+               status = acpi_get_handle(parent, paths[i], handle);
+               if (ACPI_SUCCESS(status)) {
+                       *path = paths[i];
+                       dbg_printk(TPACPI_DBG_INIT,
+                                  "Found ACPI handle %s for %s\n",
+                                  *path, name);
+                       return;
+               }
+       }
+
+       vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n",
+                   name);
+       *handle = NULL;
+}
+
+static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct ibm_struct *ibm = data;
+
+       if (!ibm || !ibm->acpi || !ibm->acpi->notify)
+               return;
+
+       ibm->acpi->notify(ibm, event);
+}
+
+static int __init setup_acpi_notify(struct ibm_struct *ibm)
+{
+       acpi_status status;
+       int rc;
+
+       BUG_ON(!ibm->acpi);
+
+       if (!*ibm->acpi->handle)
+               return 0;
+
+       vdbg_printk(TPACPI_DBG_INIT,
+               "setting up ACPI notify for %s\n", ibm->name);
+
+       rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
+       if (rc < 0) {
+               printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n",
+                       ibm->name, rc);
+               return -ENODEV;
+       }
+
+       acpi_driver_data(ibm->acpi->device) = ibm;
+       sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
+               IBM_ACPI_EVENT_PREFIX,
+               ibm->name);
+
+       status = acpi_install_notify_handler(*ibm->acpi->handle,
+                       ibm->acpi->type, dispatch_acpi_notify, ibm);
+       if (ACPI_FAILURE(status)) {
+               if (status == AE_ALREADY_EXISTS) {
+                       printk(IBM_NOTICE "another device driver is already handling %s events\n",
+                               ibm->name);
+               } else {
+                       printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
+                               ibm->name, status);
+               }
+               return -ENODEV;
+       }
+       ibm->flags.acpi_notify_installed = 1;
+       return 0;
+}
+
+static int __init tpacpi_device_add(struct acpi_device *device)
+{
+       return 0;
+}
+
+static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
+{
+       int rc;
+
+       dbg_printk(TPACPI_DBG_INIT,
+               "registering %s as an ACPI driver\n", ibm->name);
+
+       BUG_ON(!ibm->acpi);
+
+       ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
+       if (!ibm->acpi->driver) {
+               printk(IBM_ERR "kzalloc(ibm->driver) failed\n");
+               return -ENOMEM;
+       }
+
+       sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
+       ibm->acpi->driver->ids = ibm->acpi->hid;
+       ibm->acpi->driver->ops.add = &tpacpi_device_add;
+
+       rc = acpi_bus_register_driver(ibm->acpi->driver);
+       if (rc < 0) {
+               printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
+                      ibm->acpi->hid, rc);
+               kfree(ibm->acpi->driver);
+               ibm->acpi->driver = NULL;
+       } else if (!rc)
+               ibm->flags.acpi_driver_registered = 1;
+
+       return rc;
+}
+
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Procfs Helpers
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+static int dispatch_procfs_read(char *page, char **start, off_t off,
+                       int count, int *eof, void *data)
+{
+       struct ibm_struct *ibm = data;
+       int len;
+
+       if (!ibm || !ibm->read)
+               return -EINVAL;
+
+       len = ibm->read(page);
+       if (len < 0)
+               return len;
+
+       if (len <= off + count)
+               *eof = 1;
+       *start = page + off;
+       len -= off;
+       if (len > count)
+               len = count;
+       if (len < 0)
+               len = 0;
+
+       return len;
+}
+
+static int dispatch_procfs_write(struct file *file,
+                       const char __user * userbuf,
+                       unsigned long count, void *data)
+{
+       struct ibm_struct *ibm = data;
+       char *kernbuf;
+       int ret;
+
+       if (!ibm || !ibm->write)
+               return -EINVAL;
+
+       kernbuf = kmalloc(count + 2, GFP_KERNEL);
+       if (!kernbuf)
+               return -ENOMEM;
+
+       if (copy_from_user(kernbuf, userbuf, count)) {
+               kfree(kernbuf);
+               return -EFAULT;
+       }
+
+       kernbuf[count] = 0;
+       strcat(kernbuf, ",");
+       ret = ibm->write(kernbuf);
+       if (ret == 0)
+               ret = count;
+
+       kfree(kernbuf);
+
+       return ret;
+}
+
+static char *next_cmd(char **cmds)
+{
+       char *start = *cmds;
+       char *end;
+
+       while ((end = strchr(start, ',')) && end == start)
+               start = end + 1;
+
+       if (!end)
+               return NULL;
+
+       *end = 0;
+       *cmds = end + 1;
+       return start;
+}
+
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Device model: hwmon and platform
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+static struct platform_device *tpacpi_pdev = NULL;
+static struct class_device *tpacpi_hwmon = NULL;
+
+static struct platform_driver tpacpi_pdriver = {
+       .driver = {
+               .name = IBM_DRVR_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+
+/*************************************************************************
+ * thinkpad-acpi driver attributes
+ */
+
+/* interface_version --------------------------------------------------- */
+static ssize_t tpacpi_driver_interface_version_show(
+                               struct device_driver *drv,
+                               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
+}
+
+static DRIVER_ATTR(interface_version, S_IRUGO,
+               tpacpi_driver_interface_version_show, NULL);
+
+/* debug_level --------------------------------------------------------- */
+static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
+                                               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
+}
+
+static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
+                                               const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 0xffff, &t))
+               return -EINVAL;
+
+       dbg_level = t;
+
+       return count;
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+               tpacpi_driver_debug_show, tpacpi_driver_debug_store);
+
+/* version ------------------------------------------------------------- */
+static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
+                                               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);
+}
+
+static DRIVER_ATTR(version, S_IRUGO,
+               tpacpi_driver_version_show, NULL);
+
+/* --------------------------------------------------------------------- */
+
+static struct driver_attribute* tpacpi_driver_attributes[] = {
+       &driver_attr_debug_level, &driver_attr_version,
+       &driver_attr_interface_version,
+};
+
+static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
+{
+       int i, res;
+
+       i = 0;
+       res = 0;
+       while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
+               res = driver_create_file(drv, tpacpi_driver_attributes[i]);
+               i++;
+       }
+
+       return res;
+}
+
+static void tpacpi_remove_driver_attributes(struct device_driver *drv)
+{
+       int i;
+
+       for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
+               driver_remove_file(drv, tpacpi_driver_attributes[i]);
+}
+
+/*************************************************************************
+ * sysfs support helpers
+ */
+
+struct attribute_set_obj {
+       struct attribute_set s;
+       struct attribute *a;
+} __attribute__((packed));
+
+static struct attribute_set *create_attr_set(unsigned int max_members,
+                                               const char* name)
+{
+       struct attribute_set_obj *sobj;
+
+       if (max_members == 0)
+               return NULL;
+
+       /* Allocates space for implicit NULL at the end too */
+       sobj = kzalloc(sizeof(struct attribute_set_obj) +
+                   max_members * sizeof(struct attribute *),
+                   GFP_KERNEL);
+       if (!sobj)
+               return NULL;
+       sobj->s.max_members = max_members;
+       sobj->s.group.attrs = &sobj->a;
+       sobj->s.group.name = name;
+
+       return &sobj->s;
+}
+
+/* not multi-threaded safe, use it in a single thread per set */
+static int add_to_attr_set(struct attribute_set* s, struct attribute *attr)
+{
+       if (!s || !attr)
+               return -EINVAL;
+
+       if (s->members >= s->max_members)
+               return -ENOMEM;
+
+       s->group.attrs[s->members] = attr;
+       s->members++;
+
+       return 0;
+}
+
+static int add_many_to_attr_set(struct attribute_set* s,
+                       struct attribute **attr,
+                       unsigned int count)
+{
+       int i, res;
+
+       for (i = 0; i < count; i++) {
+               res = add_to_attr_set(s, attr[i]);
+               if (res)
+                       return res;
+       }
+
+       return 0;
+}
+
+static void delete_attr_set(struct attribute_set* s, struct kobject *kobj)
+{
+       sysfs_remove_group(kobj, &s->group);
+       destroy_attr_set(s);
+}
+
+static int parse_strtoul(const char *buf,
+               unsigned long max, unsigned long *value)
+{
+       char *endp;
+
+       *value = simple_strtoul(buf, &endp, 0);
+       while (*endp && isspace(*endp))
+               endp++;
+       if (*endp || *value > max)
+               return -EINVAL;
+
+       return 0;
+}
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Subdrivers
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/*************************************************************************
+ * thinkpad-acpi init subdriver
+ */
+
+static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
+{
+       printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
+       printk(IBM_INFO "%s\n", IBM_URL);
+
+       if (ibm_thinkpad_ec_found)
+               printk(IBM_INFO "ThinkPad EC firmware %s\n",
+                      ibm_thinkpad_ec_found);
+
+       return 0;
+}
+
+static int thinkpad_acpi_driver_read(char *p)
+{
+       int len = 0;
+
+       len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
+       len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
+
+       return len;
+}
+
+static struct ibm_struct thinkpad_acpi_driver_data = {
+       .name = "driver",
+       .read = thinkpad_acpi_driver_read,
+};
+
+/*************************************************************************
+ * Hotkey subdriver
+ */
+
+static int hotkey_orig_status;
+static int hotkey_orig_mask;
+
+static struct attribute_set *hotkey_dev_attributes = NULL;
+
+/* sysfs hotkey enable ------------------------------------------------- */
+static ssize_t hotkey_enable_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       int res, status, mask;
+
+       res = hotkey_get(&status, &mask);
+       if (res)
+               return res;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", status);
+}
+
+static ssize_t hotkey_enable_store(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       unsigned long t;
+       int res, status, mask;
+
+       if (parse_strtoul(buf, 1, &t))
+               return -EINVAL;
+
+       res = hotkey_get(&status, &mask);
+       if (!res)
+               res = hotkey_set(t, mask);
+
+       return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_hotkey_enable =
+       __ATTR(enable, S_IWUSR | S_IRUGO,
+               hotkey_enable_show, hotkey_enable_store);
+
+/* sysfs hotkey mask --------------------------------------------------- */
+static ssize_t hotkey_mask_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       int res, status, mask;
+
+       res = hotkey_get(&status, &mask);
+       if (res)
+               return res;
+
+       return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
+}
+
+static ssize_t hotkey_mask_store(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       unsigned long t;
+       int res, status, mask;
+
+       if (parse_strtoul(buf, 0xffff, &t))
+               return -EINVAL;
+
+       res = hotkey_get(&status, &mask);
+       if (!res)
+               hotkey_set(status, t);
+
+       return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_hotkey_mask =
+       __ATTR(mask, S_IWUSR | S_IRUGO,
+               hotkey_mask_show, hotkey_mask_store);
+
+/* sysfs hotkey bios_enabled ------------------------------------------- */
+static ssize_t hotkey_bios_enabled_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status);
+}
+
+static struct device_attribute dev_attr_hotkey_bios_enabled =
+       __ATTR(bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL);
+
+/* sysfs hotkey bios_mask ---------------------------------------------- */
+static ssize_t hotkey_bios_mask_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_bios_mask =
+       __ATTR(bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *hotkey_mask_attributes[] = {
+       &dev_attr_hotkey_mask.attr,
+       &dev_attr_hotkey_bios_enabled.attr,
+       &dev_attr_hotkey_bios_mask.attr,
+};
+
+static int __init hotkey_init(struct ibm_init_struct *iibm)
+{
+       int res;
+
+       vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
+
+       IBM_ACPIHANDLE_INIT(hkey);
+       mutex_init(&hotkey_mutex);
+
+       /* hotkey not supported on 570 */
+       tp_features.hotkey = hkey_handle != NULL;
+
+       vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
+               str_supported(tp_features.hotkey));
+
+       if (tp_features.hotkey) {
+               hotkey_dev_attributes = create_attr_set(4,
+                                               TPACPI_HOTKEY_SYSFS_GROUP);
+               if (!hotkey_dev_attributes)
+                       return -ENOMEM;
+               res = add_to_attr_set(hotkey_dev_attributes,
+                               &dev_attr_hotkey_enable.attr);
+               if (res)
+                       return res;
+
+               /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+                  A30, R30, R31, T20-22, X20-21, X22-24 */
+               tp_features.hotkey_mask =
+                       acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
+
+               vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
+                       str_supported(tp_features.hotkey_mask));
+
+               res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
+               if (!res && tp_features.hotkey_mask) {
+                       res = add_many_to_attr_set(hotkey_dev_attributes,
+                               hotkey_mask_attributes,
+                               ARRAY_SIZE(hotkey_mask_attributes));
+               }
+               if (!res)
+                       res = register_attr_set_with_sysfs(
+                                       hotkey_dev_attributes,
+                                       &tpacpi_pdev->dev.kobj);
+
+               if (res)
+                       return res;
+       }
+
+       return (tp_features.hotkey)? 0 : 1;
+}
+
+static void hotkey_exit(void)
+{
+       int res;
+
+       if (tp_features.hotkey) {
+               dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n");
+               res = hotkey_set(hotkey_orig_status, hotkey_orig_mask);
+               if (res)
+                       printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n");
+       }
+
+       if (hotkey_dev_attributes) {
+               delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
+               hotkey_dev_attributes = NULL;
+       }
+}
+
+static void hotkey_notify(struct ibm_struct *ibm, u32 event)
+{
+       int hkey;
+
+       if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
+               acpi_bus_generate_event(ibm->acpi->device, event, hkey);
+       else {
+               printk(IBM_ERR "unknown hotkey event %d\n", event);
+               acpi_bus_generate_event(ibm->acpi->device, event, 0);
+       }
+}
+
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_get(int *status, int *mask)
+{
+       if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
+               return -EIO;
+
+       if (tp_features.hotkey_mask)
+               if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
+                       return -EIO;
+
+       return 0;
+}
+
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_set(int status, int mask)
+{
+       int i;
+
+       if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
+               return -EIO;
+
+       if (tp_features.hotkey_mask)
+               for (i = 0; i < 32; i++) {
+                       int bit = ((1 << i) & mask) != 0;
+                       if (!acpi_evalf(hkey_handle,
+                                       NULL, "MHKM", "vdd", i + 1, bit))
+                               return -EIO;
+               }
+
+       return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int hotkey_read(char *p)
+{
+       int res, status, mask;
+       int len = 0;
+
+       if (!tp_features.hotkey) {
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+               return len;
+       }
+
+       res = mutex_lock_interruptible(&hotkey_mutex);
+       if (res < 0)
+               return res;
+       res = hotkey_get(&status, &mask);
+       mutex_unlock(&hotkey_mutex);
+       if (res)
+               return res;
+
+       len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
+       if (tp_features.hotkey_mask) {
+               len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+               len += sprintf(p + len,
+                              "commands:\tenable, disable, reset, <mask>\n");
+       } else {
+               len += sprintf(p + len, "mask:\t\tnot supported\n");
+               len += sprintf(p + len, "commands:\tenable, disable, reset\n");
+       }
+
+       return len;
+}
+
+static int hotkey_write(char *buf)
+{
+       int res, status, mask;
+       char *cmd;
+       int do_cmd = 0;
+
+       if (!tp_features.hotkey)
+               return -ENODEV;
+
+       res = mutex_lock_interruptible(&hotkey_mutex);
+       if (res < 0)
+               return res;
+
+       res = hotkey_get(&status, &mask);
+       if (res)
+               goto errexit;
+
+       res = 0;
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "enable") == 0) {
+                       status = 1;
+               } else if (strlencmp(cmd, "disable") == 0) {
+                       status = 0;
+               } else if (strlencmp(cmd, "reset") == 0) {
+                       status = hotkey_orig_status;
+                       mask = hotkey_orig_mask;
+               } else if (sscanf(cmd, "0x%x", &mask) == 1) {
+                       /* mask set */
+               } else if (sscanf(cmd, "%x", &mask) == 1) {
+                       /* mask set */
+               } else {
+                       res = -EINVAL;
+                       goto errexit;
+               }
+               do_cmd = 1;
+       }
+
+       if (do_cmd)
+               res = hotkey_set(status, mask);
+
+errexit:
+       mutex_unlock(&hotkey_mutex);
+       return res;
+}
+
+static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = {
+       .hid = IBM_HKEY_HID,
+       .notify = hotkey_notify,
+       .handle = &hkey_handle,
+       .type = ACPI_DEVICE_NOTIFY,
+};
+
+static struct ibm_struct hotkey_driver_data = {
+       .name = "hotkey",
+       .read = hotkey_read,
+       .write = hotkey_write,
+       .exit = hotkey_exit,
+       .acpi = &ibm_hotkey_acpidriver,
+};
+
+/*************************************************************************
+ * Bluetooth subdriver
+ */
+
+/* sysfs bluetooth enable ---------------------------------------------- */
+static ssize_t bluetooth_enable_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       int status;
+
+       status = bluetooth_get_radiosw();
+       if (status < 0)
+               return status;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
+}
+
+static ssize_t bluetooth_enable_store(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       unsigned long t;
+       int res;
+
+       if (parse_strtoul(buf, 1, &t))
+               return -EINVAL;
+
+       res = bluetooth_set_radiosw(t);
+
+       return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_bluetooth_enable =
+       __ATTR(enable, S_IWUSR | S_IRUGO,
+               bluetooth_enable_show, bluetooth_enable_store);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *bluetooth_attributes[] = {
+       &dev_attr_bluetooth_enable.attr,
+       NULL
+};
+
+static const struct attribute_group bluetooth_attr_group = {
+       .name = TPACPI_BLUETH_SYSFS_GROUP,
+       .attrs = bluetooth_attributes,
+};
+
+static int __init bluetooth_init(struct ibm_init_struct *iibm)
+{
+       int res;
+       int status = 0;
+
+       vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
+
+       IBM_ACPIHANDLE_INIT(hkey);
+
+       /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+          G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
+       tp_features.bluetooth = hkey_handle &&
+           acpi_evalf(hkey_handle, &status, "GBDC", "qd");
+
+       vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n",
+               str_supported(tp_features.bluetooth),
+               status);
+
+       if (tp_features.bluetooth) {
+               if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
+                       /* no bluetooth hardware present in system */
+                       tp_features.bluetooth = 0;
+                       dbg_printk(TPACPI_DBG_INIT,
+                                  "bluetooth hardware not installed\n");
+               } else {
+                       res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+                                       &bluetooth_attr_group);
+                       if (res)
+                               return res;
+               }
+       }
+
+       return (tp_features.bluetooth)? 0 : 1;
+}
+
+static void bluetooth_exit(void)
+{
+       sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+                       &bluetooth_attr_group);
+}
+
+static int bluetooth_get_radiosw(void)
+{
+       int status;
+
+       if (!tp_features.bluetooth)
+               return -ENODEV;
+
+       if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+               return -EIO;
+
+       return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);
+}
+
+static int bluetooth_set_radiosw(int radio_on)
+{
+       int status;
+
+       if (!tp_features.bluetooth)
+               return -ENODEV;
+
+       if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+               return -EIO;
+       if (radio_on)
+               status |= TP_ACPI_BLUETOOTH_RADIOSSW;
+       else
+               status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
+       if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
+               return -EIO;
+
+       return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int bluetooth_read(char *p)
+{
+       int len = 0;
+       int status = bluetooth_get_radiosw();
+
+       if (!tp_features.bluetooth)
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       else {
+               len += sprintf(p + len, "status:\t\t%s\n",
+                               (status)? "enabled" : "disabled");
+               len += sprintf(p + len, "commands:\tenable, disable\n");
+       }
+
+       return len;
+}
+
+static int bluetooth_write(char *buf)
+{
+       char *cmd;
+
+       if (!tp_features.bluetooth)
+               return -ENODEV;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "enable") == 0) {
+                       bluetooth_set_radiosw(1);
+               } else if (strlencmp(cmd, "disable") == 0) {
+                       bluetooth_set_radiosw(0);
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct ibm_struct bluetooth_driver_data = {
+       .name = "bluetooth",
+       .read = bluetooth_read,
+       .write = bluetooth_write,
+       .exit = bluetooth_exit,
+};
+
+/*************************************************************************
+ * Wan subdriver
+ */
+
+/* sysfs wan enable ---------------------------------------------------- */
+static ssize_t wan_enable_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       int status;
+
+       status = wan_get_radiosw();
+       if (status < 0)
+               return status;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
+}
+
+static ssize_t wan_enable_store(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       unsigned long t;
+       int res;
+
+       if (parse_strtoul(buf, 1, &t))
+               return -EINVAL;
+
+       res = wan_set_radiosw(t);
+
+       return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_wan_enable =
+       __ATTR(enable, S_IWUSR | S_IRUGO,
+               wan_enable_show, wan_enable_store);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *wan_attributes[] = {
+       &dev_attr_wan_enable.attr,
+       NULL
+};
+
+static const struct attribute_group wan_attr_group = {
+       .name = TPACPI_WAN_SYSFS_GROUP,
+       .attrs = wan_attributes,
+};
+
+static int __init wan_init(struct ibm_init_struct *iibm)
+{
+       int res;
+       int status = 0;
+
+       vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
+
+       IBM_ACPIHANDLE_INIT(hkey);
+
+       tp_features.wan = hkey_handle &&
+           acpi_evalf(hkey_handle, &status, "GWAN", "qd");
+
+       vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n",
+               str_supported(tp_features.wan),
+               status);
+
+       if (tp_features.wan) {
+               if (!(status & TP_ACPI_WANCARD_HWPRESENT)) {
+                       /* no wan hardware present in system */
+                       tp_features.wan = 0;
+                       dbg_printk(TPACPI_DBG_INIT,
+                                  "wan hardware not installed\n");
+               } else {
+                       res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+                                       &wan_attr_group);
+                       if (res)
+                               return res;
+               }
+       }
+
+       return (tp_features.wan)? 0 : 1;
+}
+
+static void wan_exit(void)
+{
+       sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+               &wan_attr_group);
+}
+
+static int wan_get_radiosw(void)
+{
+       int status;
+
+       if (!tp_features.wan)
+               return -ENODEV;
+
+       if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+               return -EIO;
+
+       return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0);
+}
+
+static int wan_set_radiosw(int radio_on)
+{
+       int status;
+
+       if (!tp_features.wan)
+               return -ENODEV;
+
+       if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+               return -EIO;
+       if (radio_on)
+               status |= TP_ACPI_WANCARD_RADIOSSW;
+       else
+               status &= ~TP_ACPI_WANCARD_RADIOSSW;
+       if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
+               return -EIO;
+
+       return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int wan_read(char *p)
+{
+       int len = 0;
+       int status = wan_get_radiosw();
+
+       if (!tp_features.wan)
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       else {
+               len += sprintf(p + len, "status:\t\t%s\n",
+                               (status)? "enabled" : "disabled");
+               len += sprintf(p + len, "commands:\tenable, disable\n");
+       }
+
+       return len;
+}
+
+static int wan_write(char *buf)
+{
+       char *cmd;
+
+       if (!tp_features.wan)
+               return -ENODEV;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "enable") == 0) {
+                       wan_set_radiosw(1);
+               } else if (strlencmp(cmd, "disable") == 0) {
+                       wan_set_radiosw(0);
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct ibm_struct wan_driver_data = {
+       .name = "wan",
+       .read = wan_read,
+       .write = wan_write,
+       .exit = wan_exit,
+       .flags.experimental = 1,
+};
+
+/*************************************************************************
+ * Video subdriver
+ */
+
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
+
+IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",     /* 570 */
+          "\\_SB.PCI0.AGP0.VID0",      /* 600e/x, 770x */
+          "\\_SB.PCI0.VID0",   /* 770e */
+          "\\_SB.PCI0.VID",    /* A21e, G4x, R50e, X30, X40 */
+          "\\_SB.PCI0.AGP.VID",        /* all others */
+          );                           /* R30, R31 */
+
+IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
+
+static int __init video_init(struct ibm_init_struct *iibm)
+{
+       int ivga;
+
+       vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
+
+       IBM_ACPIHANDLE_INIT(vid);
+       IBM_ACPIHANDLE_INIT(vid2);
+
+       if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
+               /* G41, assume IVGA doesn't change */
+               vid_handle = vid2_handle;
+
+       if (!vid_handle)
+               /* video switching not supported on R30, R31 */
+               video_supported = TPACPI_VIDEO_NONE;
+       else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
+               /* 570 */
+               video_supported = TPACPI_VIDEO_570;
+       else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
+               /* 600e/x, 770e, 770x */
+               video_supported = TPACPI_VIDEO_770;
+       else
+               /* all others */
+               video_supported = TPACPI_VIDEO_NEW;
+
+       vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n",
+               str_supported(video_supported != TPACPI_VIDEO_NONE),
+               video_supported);
+
+       return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1;
+}
+
+static void video_exit(void)
+{
+       dbg_printk(TPACPI_DBG_EXIT,
+                  "restoring original video autoswitch mode\n");
+       if (video_autosw_set(video_orig_autosw))
+               printk(IBM_ERR "error while trying to restore original "
+                       "video autoswitch mode\n");
+}
+
+static int video_outputsw_get(void)
+{
+       int status = 0;
+       int i;
+
+       switch (video_supported) {
+       case TPACPI_VIDEO_570:
+               if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd",
+                                TP_ACPI_VIDEO_570_PHSCMD))
+                       return -EIO;
+               status = i & TP_ACPI_VIDEO_570_PHSMASK;
+               break;
+       case TPACPI_VIDEO_770:
+               if (!acpi_evalf(NULL, &i, "\\VCDL", "d"))
+                       return -EIO;
+               if (i)
+                       status |= TP_ACPI_VIDEO_S_LCD;
+               if (!acpi_evalf(NULL, &i, "\\VCDC", "d"))
+                       return -EIO;
+               if (i)
+                       status |= TP_ACPI_VIDEO_S_CRT;
+               break;
+       case TPACPI_VIDEO_NEW:
+               if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) ||
+                   !acpi_evalf(NULL, &i, "\\VCDC", "d"))
+                       return -EIO;
+               if (i)
+                       status |= TP_ACPI_VIDEO_S_CRT;
+
+               if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) ||
+                   !acpi_evalf(NULL, &i, "\\VCDL", "d"))
+                       return -EIO;
+               if (i)
+                       status |= TP_ACPI_VIDEO_S_LCD;
+               if (!acpi_evalf(NULL, &i, "\\VCDD", "d"))
+                       return -EIO;
+               if (i)
+                       status |= TP_ACPI_VIDEO_S_DVI;
+               break;
+       default:
+               return -ENOSYS;
+       }
+
+       return status;
+}
+
+static int video_outputsw_set(int status)
+{
+       int autosw;
+       int res = 0;
+
+       switch (video_supported) {
+       case TPACPI_VIDEO_570:
+               res = acpi_evalf(NULL, NULL,
+                                "\\_SB.PHS2", "vdd",
+                                TP_ACPI_VIDEO_570_PHS2CMD,
+                                status | TP_ACPI_VIDEO_570_PHS2SET);
+               break;
+       case TPACPI_VIDEO_770:
+               autosw = video_autosw_get();
+               if (autosw < 0)
+                       return autosw;
+
+               res = video_autosw_set(1);
+               if (res)
+                       return res;
+               res = acpi_evalf(vid_handle, NULL,
+                                "ASWT", "vdd", status * 0x100, 0);
+               if (!autosw && video_autosw_set(autosw)) {
+                       printk(IBM_ERR "video auto-switch left enabled due to error\n");
+                       return -EIO;
+               }
+               break;
+       case TPACPI_VIDEO_NEW:
+               res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
+                       acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
+               break;
+       default:
+               return -ENOSYS;
+       }
+
+       return (res)? 0 : -EIO;
+}
+
+static int video_autosw_get(void)
+{
+       int autosw = 0;
+
+       switch (video_supported) {
+       case TPACPI_VIDEO_570:
+               if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d"))
+                       return -EIO;
+               break;
+       case TPACPI_VIDEO_770:
+       case TPACPI_VIDEO_NEW:
+               if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d"))
+                       return -EIO;
+               break;
+       default:
+               return -ENOSYS;
+       }
+
+       return autosw & 1;
+}
+
+static int video_autosw_set(int enable)
+{
+       if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0))
+               return -EIO;
+       return 0;
+}
+
+static int video_outputsw_cycle(void)
+{
+       int autosw = video_autosw_get();
+       int res;
+
+       if (autosw < 0)
+               return autosw;
+
+       switch (video_supported) {
+       case TPACPI_VIDEO_570:
+               res = video_autosw_set(1);
+               if (res)
+                       return res;
+               res = acpi_evalf(ec_handle, NULL, "_Q16", "v");
+               break;
+       case TPACPI_VIDEO_770:
+       case TPACPI_VIDEO_NEW:
+               res = video_autosw_set(1);
+               if (res)
+                       return res;
+               res = acpi_evalf(vid_handle, NULL, "VSWT", "v");
+               break;
+       default:
+               return -ENOSYS;
+       }
+       if (!autosw && video_autosw_set(autosw)) {
+               printk(IBM_ERR "video auto-switch left enabled due to error\n");
+               return -EIO;
+       }
+
+       return (res)? 0 : -EIO;
+}
+
+static int video_expand_toggle(void)
+{
+       switch (video_supported) {
+       case TPACPI_VIDEO_570:
+               return acpi_evalf(ec_handle, NULL, "_Q17", "v")?
+                       0 : -EIO;
+       case TPACPI_VIDEO_770:
+               return acpi_evalf(vid_handle, NULL, "VEXP", "v")?
+                       0 : -EIO;
+       case TPACPI_VIDEO_NEW:
+               return acpi_evalf(NULL, NULL, "\\VEXP", "v")?
+                       0 : -EIO;
+       default:
+               return -ENOSYS;
+       }
+       /* not reached */
+}
+
+static int video_read(char *p)
+{
+       int status, autosw;
+       int len = 0;
+
+       if (video_supported == TPACPI_VIDEO_NONE) {
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+               return len;
+       }
+
+       status = video_outputsw_get();
+       if (status < 0)
+               return status;
+
+       autosw = video_autosw_get();
+       if (autosw < 0)
+               return autosw;
+
+       len += sprintf(p + len, "status:\t\tsupported\n");
+       len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
+       len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
+       if (video_supported == TPACPI_VIDEO_NEW)
+               len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
+       len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
+       len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
+       len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
+       if (video_supported == TPACPI_VIDEO_NEW)
+               len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
+       len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
+       len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
+
+       return len;
+}
+
+static int video_write(char *buf)
+{
+       char *cmd;
+       int enable, disable, status;
+       int res;
+
+       if (video_supported == TPACPI_VIDEO_NONE)
+               return -ENODEV;
+
+       enable = 0;
+       disable = 0;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "lcd_enable") == 0) {
+                       enable |= TP_ACPI_VIDEO_S_LCD;
+               } else if (strlencmp(cmd, "lcd_disable") == 0) {
+                       disable |= TP_ACPI_VIDEO_S_LCD;
+               } else if (strlencmp(cmd, "crt_enable") == 0) {
+                       enable |= TP_ACPI_VIDEO_S_CRT;
+               } else if (strlencmp(cmd, "crt_disable") == 0) {
+                       disable |= TP_ACPI_VIDEO_S_CRT;
+               } else if (video_supported == TPACPI_VIDEO_NEW &&
+                          strlencmp(cmd, "dvi_enable") == 0) {
+                       enable |= TP_ACPI_VIDEO_S_DVI;
+               } else if (video_supported == TPACPI_VIDEO_NEW &&
+                          strlencmp(cmd, "dvi_disable") == 0) {
+                       disable |= TP_ACPI_VIDEO_S_DVI;
+               } else if (strlencmp(cmd, "auto_enable") == 0) {
+                       res = video_autosw_set(1);
+                       if (res)
+                               return res;
+               } else if (strlencmp(cmd, "auto_disable") == 0) {
+                       res = video_autosw_set(0);
+                       if (res)
+                               return res;
+               } else if (strlencmp(cmd, "video_switch") == 0) {
+                       res = video_outputsw_cycle();
+                       if (res)
+                               return res;
+               } else if (strlencmp(cmd, "expand_toggle") == 0) {
+                       res = video_expand_toggle();
+                       if (res)
+                               return res;
+               } else
+                       return -EINVAL;
+       }
+
+       if (enable || disable) {
+               status = video_outputsw_get();
+               if (status < 0)
+                       return status;
+               res = video_outputsw_set((status & ~disable) | enable);
+               if (res)
+                       return res;
+       }
+
+       return 0;
+}
+
+static struct ibm_struct video_driver_data = {
+       .name = "video",
+       .read = video_read,
+       .write = video_write,
+       .exit = video_exit,
+};
+
+/*************************************************************************
+ * Light (thinklight) subdriver
+ */
+
+IBM_HANDLE(lght, root, "\\LGHT");      /* A21e, A2xm/p, T20-22, X20-21 */
+IBM_HANDLE(ledb, ec, "LEDB");          /* G4x */
+
+static int __init light_init(struct ibm_init_struct *iibm)
+{
+       vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
+
+       IBM_ACPIHANDLE_INIT(ledb);
+       IBM_ACPIHANDLE_INIT(lght);
+       IBM_ACPIHANDLE_INIT(cmos);
+
+       /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
+       tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
+
+       if (tp_features.light)
+               /* light status not supported on
+                  570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
+               tp_features.light_status =
+                       acpi_evalf(ec_handle, NULL, "KBLT", "qv");
+
+       vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
+               str_supported(tp_features.light));
+
+       return (tp_features.light)? 0 : 1;
+}
+
+static int light_read(char *p)
+{
+       int len = 0;
+       int status = 0;
+
+       if (!tp_features.light) {
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       } else if (!tp_features.light_status) {
+               len += sprintf(p + len, "status:\t\tunknown\n");
+               len += sprintf(p + len, "commands:\ton, off\n");
+       } else {
+               if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
+                       return -EIO;
+               len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
+               len += sprintf(p + len, "commands:\ton, off\n");
+       }
+
+       return len;
+}
+
+static int light_write(char *buf)
+{
+       int cmos_cmd, lght_cmd;
+       char *cmd;
+       int success;
+
+       if (!tp_features.light)
+               return -ENODEV;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "on") == 0) {
+                       cmos_cmd = 0x0c;
+                       lght_cmd = 1;
+               } else if (strlencmp(cmd, "off") == 0) {
+                       cmos_cmd = 0x0d;
+                       lght_cmd = 0;
+               } else
+                       return -EINVAL;
+
+               success = cmos_handle ?
+                   acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
+                   acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
+               if (!success)
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static struct ibm_struct light_driver_data = {
+       .name = "light",
+       .read = light_read,
+       .write = light_write,
+};
+
+/*************************************************************************
+ * Dock subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+
+IBM_HANDLE(dock, root, "\\_SB.GDCK",   /* X30, X31, X40 */
+          "\\_SB.PCI0.DOCK",   /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
+          "\\_SB.PCI0.PCI1.DOCK",      /* all others */
+          "\\_SB.PCI.ISA.SLCE",        /* 570 */
+    );                         /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
+
+/* don't list other alternatives as we install a notify handler on the 570 */
+IBM_HANDLE(pci, root, "\\_SB.PCI");    /* 570 */
+
+static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
+       {
+        .notify = dock_notify,
+        .handle = &dock_handle,
+        .type = ACPI_SYSTEM_NOTIFY,
+       },
+       {
+        .hid = IBM_PCI_HID,
+        .notify = dock_notify,
+        .handle = &pci_handle,
+        .type = ACPI_SYSTEM_NOTIFY,
+       },
+};
+
+static struct ibm_struct dock_driver_data[2] = {
+       {
+        .name = "dock",
+        .read = dock_read,
+        .write = dock_write,
+        .acpi = &ibm_dock_acpidriver[0],
+       },
+       {
+        .name = "dock",
+        .acpi = &ibm_dock_acpidriver[1],
+       },
+};
+
+#define dock_docked() (_sta(dock_handle) & 1)
+
+static int __init dock_init(struct ibm_init_struct *iibm)
+{
+       vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
+
+       IBM_ACPIHANDLE_INIT(dock);
+
+       vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
+               str_supported(dock_handle != NULL));
+
+       return (dock_handle)? 0 : 1;
+}
+
+static int __init dock_init2(struct ibm_init_struct *iibm)
+{
+       int dock2_needed;
+
+       vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n");
+
+       if (dock_driver_data[0].flags.acpi_driver_registered &&
+           dock_driver_data[0].flags.acpi_notify_installed) {
+               IBM_ACPIHANDLE_INIT(pci);
+               dock2_needed = (pci_handle != NULL);
+               vdbg_printk(TPACPI_DBG_INIT,
+                           "dock PCI handler for the TP 570 is %s\n",
+                           str_supported(dock2_needed));
+       } else {
+               vdbg_printk(TPACPI_DBG_INIT,
+               "dock subdriver part 2 not required\n");
+               dock2_needed = 0;
+       }
+
+       return (dock2_needed)? 0 : 1;
+}
+
+static void dock_notify(struct ibm_struct *ibm, u32 event)
+{
+       int docked = dock_docked();
+       int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
+
+       if (event == 1 && !pci) /* 570 */
+               acpi_bus_generate_event(ibm->acpi->device, event, 1);   /* button */
+       else if (event == 1 && pci)     /* 570 */
+               acpi_bus_generate_event(ibm->acpi->device, event, 3);   /* dock */
+       else if (event == 3 && docked)
+               acpi_bus_generate_event(ibm->acpi->device, event, 1);   /* button */
+       else if (event == 3 && !docked)
+               acpi_bus_generate_event(ibm->acpi->device, event, 2);   /* undock */
+       else if (event == 0 && docked)
+               acpi_bus_generate_event(ibm->acpi->device, event, 3);   /* dock */
+       else {
+               printk(IBM_ERR "unknown dock event %d, status %d\n",
+                      event, _sta(dock_handle));
+               acpi_bus_generate_event(ibm->acpi->device, event, 0);   /* unknown */
+       }
+}
+
+static int dock_read(char *p)
+{
+       int len = 0;
+       int docked = dock_docked();
+
+       if (!dock_handle)
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       else if (!docked)
+               len += sprintf(p + len, "status:\t\tundocked\n");
+       else {
+               len += sprintf(p + len, "status:\t\tdocked\n");
+               len += sprintf(p + len, "commands:\tdock, undock\n");
+       }
+
+       return len;
+}
+
+static int dock_write(char *buf)
+{
+       char *cmd;
+
+       if (!dock_docked())
+               return -ENODEV;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "undock") == 0) {
+                       if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
+                           !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
+                               return -EIO;
+               } else if (strlencmp(cmd, "dock") == 0) {
+                       if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
+                               return -EIO;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+#endif /* CONFIG_THINKPAD_ACPI_DOCK */
+
+/*************************************************************************
+ * Bay subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST",       /* 570 */
+          "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
+          "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
+          "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
+          );                           /* A21e, R30, R31 */
+IBM_HANDLE(bay_ej, bay, "_EJ3",        /* 600e/x, A2xm/p, A3x */
+          "_EJ0",              /* all others */
+          );                   /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
+IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV",    /* A3x, R32 */
+          "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
+          );                           /* all others */
+IBM_HANDLE(bay2_ej, bay2, "_EJ3",      /* 600e/x, 770e, A3x */
+          "_EJ0",                      /* 770x */
+          );                           /* all others */
+
+static int __init bay_init(struct ibm_init_struct *iibm)
+{
+       vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
+
+       IBM_ACPIHANDLE_INIT(bay);
+       if (bay_handle)
+               IBM_ACPIHANDLE_INIT(bay_ej);
+       IBM_ACPIHANDLE_INIT(bay2);
+       if (bay2_handle)
+               IBM_ACPIHANDLE_INIT(bay2_ej);
+
+       tp_features.bay_status = bay_handle &&
+               acpi_evalf(bay_handle, NULL, "_STA", "qv");
+       tp_features.bay_status2 = bay2_handle &&
+               acpi_evalf(bay2_handle, NULL, "_STA", "qv");
+
+       tp_features.bay_eject = bay_handle && bay_ej_handle &&
+               (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
+       tp_features.bay_eject2 = bay2_handle && bay2_ej_handle &&
+               (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
+
+       vdbg_printk(TPACPI_DBG_INIT,
+               "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n",
+               str_supported(tp_features.bay_status),
+               str_supported(tp_features.bay_eject),
+               str_supported(tp_features.bay_status2),
+               str_supported(tp_features.bay_eject2));
+
+       return (tp_features.bay_status || tp_features.bay_eject ||
+               tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1;
+}
+
+static void bay_notify(struct ibm_struct *ibm, u32 event)
+{
+       acpi_bus_generate_event(ibm->acpi->device, event, 0);
+}
+
+#define bay_occupied(b) (_sta(b##_handle) & 1)
+
+static int bay_read(char *p)
+{
+       int len = 0;
+       int occupied = bay_occupied(bay);
+       int occupied2 = bay_occupied(bay2);
+       int eject, eject2;
+
+       len += sprintf(p + len, "status:\t\t%s\n",
+               tp_features.bay_status ?
+                       (occupied ? "occupied" : "unoccupied") :
+                               "not supported");
+       if (tp_features.bay_status2)
+               len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
+                              "occupied" : "unoccupied");
+
+       eject = tp_features.bay_eject && occupied;
+       eject2 = tp_features.bay_eject2 && occupied2;
+
+       if (eject && eject2)
+               len += sprintf(p + len, "commands:\teject, eject2\n");
+       else if (eject)
+               len += sprintf(p + len, "commands:\teject\n");
+       else if (eject2)
+               len += sprintf(p + len, "commands:\teject2\n");
+
+       return len;
+}
+
+static int bay_write(char *buf)
+{
+       char *cmd;
+
+       if (!tp_features.bay_eject && !tp_features.bay_eject2)
+               return -ENODEV;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) {
+                       if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
+                               return -EIO;
+               } else if (tp_features.bay_eject2 &&
+                          strlencmp(cmd, "eject2") == 0) {
+                       if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
+                               return -EIO;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct tp_acpi_drv_struct ibm_bay_acpidriver = {
+       .notify = bay_notify,
+       .handle = &bay_handle,
+       .type = ACPI_SYSTEM_NOTIFY,
+};
+
+static struct ibm_struct bay_driver_data = {
+       .name = "bay",
+       .read = bay_read,
+       .write = bay_write,
+       .acpi = &ibm_bay_acpidriver,
+};
+
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+
+/*************************************************************************
+ * CMOS subdriver
+ */
+
+/* sysfs cmos_command -------------------------------------------------- */
+static ssize_t cmos_command_store(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       unsigned long cmos_cmd;
+       int res;
+
+       if (parse_strtoul(buf, 21, &cmos_cmd))
+               return -EINVAL;
+
+       res = issue_thinkpad_cmos_command(cmos_cmd);
+       return (res)? res : count;
+}
+
+static struct device_attribute dev_attr_cmos_command =
+       __ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store);
+
+/* --------------------------------------------------------------------- */
+
+static int __init cmos_init(struct ibm_init_struct *iibm)
+{
+       int res;
+
+       vdbg_printk(TPACPI_DBG_INIT,
+               "initializing cmos commands subdriver\n");
+
+       IBM_ACPIHANDLE_INIT(cmos);
+
+       vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
+               str_supported(cmos_handle != NULL));
+
+       res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
+       if (res)
+               return res;
+
+       return (cmos_handle)? 0 : 1;
+}
+
+static void cmos_exit(void)
+{
+       device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
+}
+
+static int cmos_read(char *p)
+{
+       int len = 0;
+
+       /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+          R30, R31, T20-22, X20-21 */
+       if (!cmos_handle)
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       else {
+               len += sprintf(p + len, "status:\t\tsupported\n");
+               len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
+       }
+
+       return len;
+}
+
+static int cmos_write(char *buf)
+{
+       char *cmd;
+       int cmos_cmd, res;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
+                   cmos_cmd >= 0 && cmos_cmd <= 21) {
+                       /* cmos_cmd set */
+               } else
+                       return -EINVAL;
+
+               res = issue_thinkpad_cmos_command(cmos_cmd);
+               if (res)
+                       return res;
+       }
+
+       return 0;
+}
+
+static struct ibm_struct cmos_driver_data = {
+       .name = "cmos",
+       .read = cmos_read,
+       .write = cmos_write,
+       .exit = cmos_exit,
+};
+
+/*************************************************************************
+ * LED subdriver
+ */
+
+static enum led_access_mode led_supported;
+
+IBM_HANDLE(led, ec, "SLED",    /* 570 */
+          "SYSL",              /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+          "LED",               /* all others */
+          );                   /* R30, R31 */
+
+static int __init led_init(struct ibm_init_struct *iibm)
+{
+       vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
+
+       IBM_ACPIHANDLE_INIT(led);
+
+       if (!led_handle)
+               /* led not supported on R30, R31 */
+               led_supported = TPACPI_LED_NONE;
+       else if (strlencmp(led_path, "SLED") == 0)
+               /* 570 */
+               led_supported = TPACPI_LED_570;
+       else if (strlencmp(led_path, "SYSL") == 0)
+               /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+               led_supported = TPACPI_LED_OLD;
+       else
+               /* all others */
+               led_supported = TPACPI_LED_NEW;
+
+       vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
+               str_supported(led_supported), led_supported);
+
+       return (led_supported != TPACPI_LED_NONE)? 0 : 1;
+}
+
+#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
+
+static int led_read(char *p)
+{
+       int len = 0;
+
+       if (!led_supported) {
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+               return len;
+       }
+       len += sprintf(p + len, "status:\t\tsupported\n");
+
+       if (led_supported == TPACPI_LED_570) {
+               /* 570 */
+               int i, status;
+               for (i = 0; i < 8; i++) {
+                       if (!acpi_evalf(ec_handle,
+                                       &status, "GLED", "dd", 1 << i))
+                               return -EIO;
+                       len += sprintf(p + len, "%d:\t\t%s\n",
+                                      i, led_status(status));
+               }
+       }
+
+       len += sprintf(p + len, "commands:\t"
+                      "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
+
+       return len;
+}
+
+/* off, on, blink */
+static const int led_sled_arg1[] = { 0, 1, 3 };
+static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
+static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
+static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
+
+static int led_write(char *buf)
+{
+       char *cmd;
+       int led, ind, ret;
+
+       if (!led_supported)
+               return -ENODEV;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
+                       return -EINVAL;
+
+               if (strstr(cmd, "off")) {
+                       ind = 0;
+               } else if (strstr(cmd, "on")) {
+                       ind = 1;
+               } else if (strstr(cmd, "blink")) {
+                       ind = 2;
+               } else
+                       return -EINVAL;
+
+               if (led_supported == TPACPI_LED_570) {
+                       /* 570 */
+                       led = 1 << led;
+                       if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+                                       led, led_sled_arg1[ind]))
+                               return -EIO;
+               } else if (led_supported == TPACPI_LED_OLD) {
+                       /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
+                       led = 1 << led;
+                       ret = ec_write(TPACPI_LED_EC_HLMS, led);
+                       if (ret >= 0)
+                               ret =
+                                   ec_write(TPACPI_LED_EC_HLBL,
+                                            led * led_exp_hlbl[ind]);
+                       if (ret >= 0)
+                               ret =
+                                   ec_write(TPACPI_LED_EC_HLCL,
+                                            led * led_exp_hlcl[ind]);
+                       if (ret < 0)
+                               return ret;
+               } else {
+                       /* all others */
+                       if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+                                       led, led_led_arg1[ind]))
+                               return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static struct ibm_struct led_driver_data = {
+       .name = "led",
+       .read = led_read,
+       .write = led_write,
+};
+
+/*************************************************************************
+ * Beep subdriver
+ */
+
+IBM_HANDLE(beep, ec, "BEEP");  /* all except R30, R31 */
+
+static int __init beep_init(struct ibm_init_struct *iibm)
+{
+       vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
+
+       IBM_ACPIHANDLE_INIT(beep);
+
+       vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
+               str_supported(beep_handle != NULL));
+
+       return (beep_handle)? 0 : 1;
+}
+
+static int beep_read(char *p)
+{
+       int len = 0;
+
+       if (!beep_handle)
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       else {
+               len += sprintf(p + len, "status:\t\tsupported\n");
+               len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
+       }
+
+       return len;
+}
+
+static int beep_write(char *buf)
+{
+       char *cmd;
+       int beep_cmd;
+
+       if (!beep_handle)
+               return -ENODEV;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
+                   beep_cmd >= 0 && beep_cmd <= 17) {
+                       /* beep_cmd set */
+               } else
+                       return -EINVAL;
+               if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static struct ibm_struct beep_driver_data = {
+       .name = "beep",
+       .read = beep_read,
+       .write = beep_write,
+};
+
+/*************************************************************************
+ * Thermal subdriver
+ */
+
+static enum thermal_access_mode thermal_read_mode;
+
+/* sysfs temp##_input -------------------------------------------------- */
+
+static ssize_t thermal_temp_input_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       struct sensor_device_attribute *sensor_attr =
+                                       to_sensor_dev_attr(attr);
+       int idx = sensor_attr->index;
+       s32 value;
+       int res;
+
+       res = thermal_get_sensor(idx, &value);
+       if (res)
+               return res;
+       if (value == TP_EC_THERMAL_TMP_NA * 1000)
+               return -ENXIO;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
+        SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB)
+
+static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
+       THERMAL_SENSOR_ATTR_TEMP(1, 0),
+       THERMAL_SENSOR_ATTR_TEMP(2, 1),
+       THERMAL_SENSOR_ATTR_TEMP(3, 2),
+       THERMAL_SENSOR_ATTR_TEMP(4, 3),
+       THERMAL_SENSOR_ATTR_TEMP(5, 4),
+       THERMAL_SENSOR_ATTR_TEMP(6, 5),
+       THERMAL_SENSOR_ATTR_TEMP(7, 6),
+       THERMAL_SENSOR_ATTR_TEMP(8, 7),
+       THERMAL_SENSOR_ATTR_TEMP(9, 8),
+       THERMAL_SENSOR_ATTR_TEMP(10, 9),
+       THERMAL_SENSOR_ATTR_TEMP(11, 10),
+       THERMAL_SENSOR_ATTR_TEMP(12, 11),
+       THERMAL_SENSOR_ATTR_TEMP(13, 12),
+       THERMAL_SENSOR_ATTR_TEMP(14, 13),
+       THERMAL_SENSOR_ATTR_TEMP(15, 14),
+       THERMAL_SENSOR_ATTR_TEMP(16, 15),
+};
+
+#define THERMAL_ATTRS(X) \
+       &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr
+
+static struct attribute *thermal_temp_input_attr[] = {
+       THERMAL_ATTRS(8),
+       THERMAL_ATTRS(9),
+       THERMAL_ATTRS(10),
+       THERMAL_ATTRS(11),
+       THERMAL_ATTRS(12),
+       THERMAL_ATTRS(13),
+       THERMAL_ATTRS(14),
+       THERMAL_ATTRS(15),
+       THERMAL_ATTRS(0),
+       THERMAL_ATTRS(1),
+       THERMAL_ATTRS(2),
+       THERMAL_ATTRS(3),
+       THERMAL_ATTRS(4),
+       THERMAL_ATTRS(5),
+       THERMAL_ATTRS(6),
+       THERMAL_ATTRS(7),
+       NULL
+};
+
+static const struct attribute_group thermal_temp_input16_group = {
+       .attrs = thermal_temp_input_attr
+};
+
+static const struct attribute_group thermal_temp_input8_group = {
+       .attrs = &thermal_temp_input_attr[8]
+};
+
+#undef THERMAL_SENSOR_ATTR_TEMP
+#undef THERMAL_ATTRS
+
+/* --------------------------------------------------------------------- */
+
+static int __init thermal_init(struct ibm_init_struct *iibm)
+{
+       u8 t, ta1, ta2;
+       int i;
+       int acpi_tmp7;
+       int res;
+
+       vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n");
+
+       acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
+
+       if (ibm_thinkpad_ec_found && experimental) {
+               /*
+                * Direct EC access mode: sensors at registers
+                * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
+                * non-implemented, thermal sensors return 0x80 when
+                * not available
+                */
+
+               ta1 = ta2 = 0;
+               for (i = 0; i < 8; i++) {
+                       if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) {
+                               ta1 |= t;
+                       } else {
+                               ta1 = 0;
+                               break;
+                       }
+                       if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) {
+                               ta2 |= t;
+                       } else {
+                               ta1 = 0;
+                               break;
+                       }
+               }
+               if (ta1 == 0) {
+                       /* This is sheer paranoia, but we handle it anyway */
+                       if (acpi_tmp7) {
+                               printk(IBM_ERR
+                                      "ThinkPad ACPI EC access misbehaving, "
+                                      "falling back to ACPI TMPx access mode\n");
+                               thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
+                       } else {
+                               printk(IBM_ERR
+                                      "ThinkPad ACPI EC access misbehaving, "
+                                      "disabling thermal sensors access\n");
+                               thermal_read_mode = TPACPI_THERMAL_NONE;
+                       }
+               } else {
+                       thermal_read_mode =
+                           (ta2 != 0) ?
+                           TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8;
+               }
+       } else if (acpi_tmp7) {
+               if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
+                       /* 600e/x, 770e, 770x */
+                       thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT;
+               } else {
+                       /* Standard ACPI TMPx access, max 8 sensors */
+                       thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
+               }
+       } else {
+               /* temperatures not supported on 570, G4x, R30, R31, R32 */
+               thermal_read_mode = TPACPI_THERMAL_NONE;
+       }
+
+       vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n",
+               str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
+               thermal_read_mode);
+
+       switch(thermal_read_mode) {
+       case TPACPI_THERMAL_TPEC_16:
+               res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+                               &thermal_temp_input16_group);
+               if (res)
+                       return res;
+               break;
+       case TPACPI_THERMAL_TPEC_8:
+       case TPACPI_THERMAL_ACPI_TMP07:
+       case TPACPI_THERMAL_ACPI_UPDT:
+               res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+                               &thermal_temp_input8_group);
+               if (res)
+                       return res;
+               break;
+       case TPACPI_THERMAL_NONE:
+       default:
+               return 1;
+       }
+
+       return 0;
+}
+
+static void thermal_exit(void)
+{
+       switch(thermal_read_mode) {
+       case TPACPI_THERMAL_TPEC_16:
+               sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+                                  &thermal_temp_input16_group);
+               break;
+       case TPACPI_THERMAL_TPEC_8:
+       case TPACPI_THERMAL_ACPI_TMP07:
+       case TPACPI_THERMAL_ACPI_UPDT:
+               sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+                                  &thermal_temp_input16_group);
+               break;
+       case TPACPI_THERMAL_NONE:
+       default:
+               break;
+       }
+}
+
+/* idx is zero-based */
+static int thermal_get_sensor(int idx, s32 *value)
+{
+       int t;
+       s8 tmp;
+       char tmpi[5];
+
+       t = TP_EC_THERMAL_TMP0;
+
+       switch (thermal_read_mode) {
+#if TPACPI_MAX_THERMAL_SENSORS >= 16
+       case TPACPI_THERMAL_TPEC_16:
+               if (idx >= 8 && idx <= 15) {
+                       t = TP_EC_THERMAL_TMP8;
+                       idx -= 8;
+               }
+               /* fallthrough */
+#endif
+       case TPACPI_THERMAL_TPEC_8:
+               if (idx <= 7) {
+                       if (!acpi_ec_read(t + idx, &tmp))
+                               return -EIO;
+                       *value = tmp * 1000;
+                       return 0;
+               }
+               break;
+
+       case TPACPI_THERMAL_ACPI_UPDT:
+               if (idx <= 7) {
+                       snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+                       if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+                               return -EIO;
+                       if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+                               return -EIO;
+                       *value = (t - 2732) * 100;
+                       return 0;
+               }
+               break;
+
+       case TPACPI_THERMAL_ACPI_TMP07:
+               if (idx <= 7) {
+                       snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+                       if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+                               return -EIO;
+                       *value = t * 1000;
+                       return 0;
+               }
+               break;
+
+       case TPACPI_THERMAL_NONE:
+       default:
+               return -ENOSYS;
+       }
+
+       return -EINVAL;
+}
+
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
+{
+       int res, i;
+       int n;
+
+       n = 8;
+       i = 0;
+
+       if (!s)
+               return -EINVAL;
+
+       if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
+               n = 16;
+
+       for(i = 0 ; i < n; i++) {
+               res = thermal_get_sensor(i, &s->temp[i]);
+               if (res)
+                       return res;
+       }
+
+       return n;
+}
+
+static int thermal_read(char *p)
+{
+       int len = 0;
+       int n, i;
+       struct ibm_thermal_sensors_struct t;
+
+       n = thermal_get_sensors(&t);
+       if (unlikely(n < 0))
+               return n;
+
+       len += sprintf(p + len, "temperatures:\t");
+
+       if (n > 0) {
+               for (i = 0; i < (n - 1); i++)
+                       len += sprintf(p + len, "%d ", t.temp[i] / 1000);
+               len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
+       } else
+               len += sprintf(p + len, "not supported\n");
+
+       return len;
+}
+
+static struct ibm_struct thermal_driver_data = {
+       .name = "thermal",
+       .read = thermal_read,
+       .exit = thermal_exit,
+};
+
+/*************************************************************************
+ * EC Dump subdriver
+ */
+
+static u8 ecdump_regs[256];
+
+static int ecdump_read(char *p)
+{
+       int len = 0;
+       int i, j;
+       u8 v;
+
+       len += sprintf(p + len, "EC      "
+                      " +00 +01 +02 +03 +04 +05 +06 +07"
+                      " +08 +09 +0a +0b +0c +0d +0e +0f\n");
+       for (i = 0; i < 256; i += 16) {
+               len += sprintf(p + len, "EC 0x%02x:", i);
+               for (j = 0; j < 16; j++) {
+                       if (!acpi_ec_read(i + j, &v))
+                               break;
+                       if (v != ecdump_regs[i + j])
+                               len += sprintf(p + len, " *%02x", v);
+                       else
+                               len += sprintf(p + len, "  %02x", v);
+                       ecdump_regs[i + j] = v;
+               }
+               len += sprintf(p + len, "\n");
+               if (j != 16)
+                       break;
+       }
+
+       /* These are way too dangerous to advertise openly... */
+#if 0
+       len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
+                      " (<offset> is 00-ff, <value> is 00-ff)\n");
+       len += sprintf(p + len, "commands:\t0x<offset> <value>  "
+                      " (<offset> is 00-ff, <value> is 0-255)\n");
+#endif
+       return len;
+}
+
+static int ecdump_write(char *buf)
+{
+       char *cmd;
+       int i, v;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
+                       /* i and v set */
+               } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
+                       /* i and v set */
+               } else
+                       return -EINVAL;
+               if (i >= 0 && i < 256 && v >= 0 && v < 256) {
+                       if (!acpi_ec_write(i, v))
+                               return -EIO;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct ibm_struct ecdump_driver_data = {
+       .name = "ecdump",
+       .read = ecdump_read,
+       .write = ecdump_write,
+       .flags.experimental = 1,
+};
+
+/*************************************************************************
+ * Backlight/brightness subdriver
+ */
+
+static struct backlight_device *ibm_backlight_device = NULL;
+
+static struct backlight_ops ibm_backlight_data = {
+        .get_brightness = brightness_get,
+        .update_status  = brightness_update_status,
+};
+
+static int __init brightness_init(struct ibm_init_struct *iibm)
+{
+       int b;
+
+       vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
+
+       b = brightness_get(NULL);
+       if (b < 0)
+               return b;
+
+       ibm_backlight_device = backlight_device_register(
+                                       TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
+                                       &ibm_backlight_data);
+       if (IS_ERR(ibm_backlight_device)) {
+               printk(IBM_ERR "Could not register backlight device\n");
+               return PTR_ERR(ibm_backlight_device);
+       }
+       vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
+
+       ibm_backlight_device->props.max_brightness = 7;
+       ibm_backlight_device->props.brightness = b;
+       backlight_update_status(ibm_backlight_device);
+
+       return 0;
+}
+
+static void brightness_exit(void)
+{
+       if (ibm_backlight_device) {
+               vdbg_printk(TPACPI_DBG_EXIT,
+                           "calling backlight_device_unregister()\n");
+               backlight_device_unregister(ibm_backlight_device);
+               ibm_backlight_device = NULL;
+       }
+}
+
+static int brightness_update_status(struct backlight_device *bd)
+{
+       return brightness_set(
+               (bd->props.fb_blank == FB_BLANK_UNBLANK &&
+                bd->props.power == FB_BLANK_UNBLANK) ?
+                               bd->props.brightness : 0);
+}
+
+static int brightness_get(struct backlight_device *bd)
+{
+       u8 level;
+       if (!acpi_ec_read(brightness_offset, &level))
+               return -EIO;
+
+       level &= 0x7;
+
+       return level;
+}
+
+static int brightness_set(int value)
+{
+       int cmos_cmd, inc, i;
+       int current_value = brightness_get(NULL);
+
+       value &= 7;
+
+       cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
+       inc = value > current_value ? 1 : -1;
+       for (i = current_value; i != value; i += inc) {
+               if (issue_thinkpad_cmos_command(cmos_cmd))
+                       return -EIO;
+               if (!acpi_ec_write(brightness_offset, i + inc))
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static int brightness_read(char *p)
+{
+       int len = 0;
+       int level;
+
+       if ((level = brightness_get(NULL)) < 0) {
+               len += sprintf(p + len, "level:\t\tunreadable\n");
+       } else {
+               len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
+               len += sprintf(p + len, "commands:\tup, down\n");
+               len += sprintf(p + len, "commands:\tlevel <level>"
+                              " (<level> is 0-7)\n");
+       }
+
+       return len;
+}
+
+static int brightness_write(char *buf)
+{
+       int level;
+       int new_level;
+       char *cmd;
+
+       while ((cmd = next_cmd(&buf))) {
+               if ((level = brightness_get(NULL)) < 0)
+                       return level;
+               level &= 7;
+
+               if (strlencmp(cmd, "up") == 0) {
+                       new_level = level == 7 ? 7 : level + 1;
+               } else if (strlencmp(cmd, "down") == 0) {
+                       new_level = level == 0 ? 0 : level - 1;
+               } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
+                          new_level >= 0 && new_level <= 7) {
+                       /* new_level set */
+               } else
+                       return -EINVAL;
+
+               brightness_set(new_level);
+       }
+
+       return 0;
+}
+
+static struct ibm_struct brightness_driver_data = {
+       .name = "brightness",
+       .read = brightness_read,
+       .write = brightness_write,
+       .exit = brightness_exit,
+};
+
+/*************************************************************************
+ * Volume subdriver
+ */
+
+static int volume_read(char *p)
+{
+       int len = 0;
+       u8 level;
+
+       if (!acpi_ec_read(volume_offset, &level)) {
+               len += sprintf(p + len, "level:\t\tunreadable\n");
+       } else {
+               len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
+               len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
+               len += sprintf(p + len, "commands:\tup, down, mute\n");
+               len += sprintf(p + len, "commands:\tlevel <level>"
+                              " (<level> is 0-15)\n");
+       }
+
+       return len;
+}
+
+static int volume_write(char *buf)
+{
+       int cmos_cmd, inc, i;
+       u8 level, mute;
+       int new_level, new_mute;
+       char *cmd;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (!acpi_ec_read(volume_offset, &level))
+                       return -EIO;
+               new_mute = mute = level & 0x40;
+               new_level = level = level & 0xf;
+
+               if (strlencmp(cmd, "up") == 0) {
+                       if (mute)
+                               new_mute = 0;
+                       else
+                               new_level = level == 15 ? 15 : level + 1;
+               } else if (strlencmp(cmd, "down") == 0) {
+                       if (mute)
+                               new_mute = 0;
+                       else
+                               new_level = level == 0 ? 0 : level - 1;
+               } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
+                          new_level >= 0 && new_level <= 15) {
+                       /* new_level set */
+               } else if (strlencmp(cmd, "mute") == 0) {
+                       new_mute = 0x40;
+               } else
+                       return -EINVAL;
+
+               if (new_level != level) {       /* mute doesn't change */
+                       cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
+                       inc = new_level > level ? 1 : -1;
+
+                       if (mute && (issue_thinkpad_cmos_command(cmos_cmd) ||
+                                    !acpi_ec_write(volume_offset, level)))
+                               return -EIO;
+
+                       for (i = level; i != new_level; i += inc)
+                               if (issue_thinkpad_cmos_command(cmos_cmd) ||
+                                   !acpi_ec_write(volume_offset, i + inc))
+                                       return -EIO;
+
+                       if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
+                                    !acpi_ec_write(volume_offset,
+                                                   new_level + mute)))
+                               return -EIO;
+               }
+
+               if (new_mute != mute) { /* level doesn't change */
+                       cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
+
+                       if (issue_thinkpad_cmos_command(cmos_cmd) ||
+                           !acpi_ec_write(volume_offset, level + new_mute))
+                               return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static struct ibm_struct volume_driver_data = {
+       .name = "volume",
+       .read = volume_read,
+       .write = volume_write,
+};
+
+/*************************************************************************
+ * Fan subdriver
+ */
+
+/*
+ * FAN ACCESS MODES
+ *
+ * TPACPI_FAN_RD_ACPI_GFAN:
+ *     ACPI GFAN method: returns fan level
+ *
+ *     see TPACPI_FAN_WR_ACPI_SFAN
+ *     EC 0x2f (HFSP) not available if GFAN exists
+ *
+ * TPACPI_FAN_WR_ACPI_SFAN:
+ *     ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
+ *
+ *     EC 0x2f (HFSP) might be available *for reading*, but do not use
+ *     it for writing.
+ *
+ * TPACPI_FAN_WR_TPEC:
+ *     ThinkPad EC register 0x2f (HFSP): fan control loop mode
+ *     Supported on almost all ThinkPads
+ *
+ *     Fan speed changes of any sort (including those caused by the
+ *     disengaged mode) are usually done slowly by the firmware as the
+ *     maximum ammount of fan duty cycle change per second seems to be
+ *     limited.
+ *
+ *     Reading is not available if GFAN exists.
+ *     Writing is not available if SFAN exists.
+ *
+ *     Bits
+ *      7      automatic mode engaged;
+ *             (default operation mode of the ThinkPad)
+ *             fan level is ignored in this mode.
+ *      6      full speed mode (takes precedence over bit 7);
+ *             not available on all thinkpads.  May disable
+ *             the tachometer while the fan controller ramps up
+ *             the speed (which can take up to a few *minutes*).
+ *             Speeds up fan to 100% duty-cycle, which is far above
+ *             the standard RPM levels.  It is not impossible that
+ *             it could cause hardware damage.
+ *     5-3     unused in some models.  Extra bits for fan level
+ *             in others, but still useless as all values above
+ *             7 map to the same speed as level 7 in these models.
+ *     2-0     fan level (0..7 usually)
+ *                     0x00 = stop
+ *                     0x07 = max (set when temperatures critical)
+ *             Some ThinkPads may have other levels, see
+ *             TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
+ *
+ *     FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
+ *     boot. Apparently the EC does not intialize it, so unless ACPI DSDT
+ *     does so, its initial value is meaningless (0x07).
+ *
+ *     For firmware bugs, refer to:
+ *     http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ *     ----
+ *
+ *     ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
+ *     Main fan tachometer reading (in RPM)
+ *
+ *     This register is present on all ThinkPads with a new-style EC, and
+ *     it is known not to be present on the A21m/e, and T22, as there is
+ *     something else in offset 0x84 according to the ACPI DSDT.  Other
+ *     ThinkPads from this same time period (and earlier) probably lack the
+ *     tachometer as well.
+ *
+ *     Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
+ *     was never fixed by IBM to report the EC firmware version string
+ *     probably support the tachometer (like the early X models), so
+ *     detecting it is quite hard.  We need more data to know for sure.
+ *
+ *     FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
+ *     might result.
+ *
+ *     FIRMWARE BUG: may go stale while the EC is switching to full speed
+ *     mode.
+ *
+ *     For firmware bugs, refer to:
+ *     http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * TPACPI_FAN_WR_ACPI_FANS:
+ *     ThinkPad X31, X40, X41.  Not available in the X60.
+ *
+ *     FANS ACPI handle: takes three arguments: low speed, medium speed,
+ *     high speed.  ACPI DSDT seems to map these three speeds to levels
+ *     as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
+ *     (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
+ *
+ *     The speeds are stored on handles
+ *     (FANA:FAN9), (FANC:FANB), (FANE:FAND).
+ *
+ *     There are three default speed sets, acessible as handles:
+ *     FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
+ *
+ *     ACPI DSDT switches which set is in use depending on various
+ *     factors.
+ *
+ *     TPACPI_FAN_WR_TPEC is also available and should be used to
+ *     command the fan.  The X31/X40/X41 seems to have 8 fan levels,
+ *     but the ACPI tables just mention level 7.
+ */
+
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
+
+static u8 fan_control_initial_status;
+static u8 fan_control_desired_level;
+
+static void fan_watchdog_fire(struct work_struct *ignored);
+static int fan_watchdog_maxinterval;
+static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
+
+IBM_HANDLE(fans, ec, "FANS");  /* X31, X40, X41 */
+IBM_HANDLE(gfan, ec, "GFAN",   /* 570 */
+          "\\FSPD",            /* 600e/x, 770e, 770x */
+          );                   /* all others */
+IBM_HANDLE(sfan, ec, "SFAN",   /* 570 */
+          "JFNS",              /* 770x-JL */
+          );                   /* all others */
+
+/*
+ * SYSFS fan layout: hwmon compatible (device)
+ *
+ * pwm*_enable:
+ *     0: "disengaged" mode
+ *     1: manual mode
+ *     2: native EC "auto" mode (recommended, hardware default)
+ *
+ * pwm*: set speed in manual mode, ignored otherwise.
+ *     0 is level 0; 255 is level 7. Intermediate points done with linear
+ *     interpolation.
+ *
+ * fan*_input: tachometer reading, RPM
+ *
+ *
+ * SYSFS fan layout: extensions
+ *
+ * fan_watchdog (driver):
+ *     fan watchdog interval in seconds, 0 disables (default), max 120
+ */
+
+/* sysfs fan pwm1_enable ----------------------------------------------- */
+static ssize_t fan_pwm1_enable_show(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       int res, mode;
+       u8 status;
+
+       res = fan_get_status_safe(&status);
+       if (res)
+               return res;
+
+       if (unlikely(tp_features.fan_ctrl_status_undef)) {
+               if (status != fan_control_initial_status) {
+                       tp_features.fan_ctrl_status_undef = 0;
+               } else {
+                       /* Return most likely status. In fact, it
+                        * might be the only possible status */
+                       status = TP_EC_FAN_AUTO;
+               }
+       }
+
+       if (status & TP_EC_FAN_FULLSPEED) {
+               mode = 0;
+       } else if (status & TP_EC_FAN_AUTO) {
+               mode = 2;
+       } else
+               mode = 1;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", mode);
+}
+
+static ssize_t fan_pwm1_enable_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       unsigned long t;
+       int res, level;
+
+       if (parse_strtoul(buf, 2, &t))
+               return -EINVAL;
+
+       switch (t) {
+       case 0:
+               level = TP_EC_FAN_FULLSPEED;
+               break;
+       case 1:
+               level = TPACPI_FAN_LAST_LEVEL;
+               break;
+       case 2:
+               level = TP_EC_FAN_AUTO;
+               break;
+       case 3:
+               /* reserved for software-controlled auto mode */
+               return -ENOSYS;
+       default:
+               return -EINVAL;
+       }
+
+       res = fan_set_level_safe(level);
+       if (res == -ENXIO)
+               return -EINVAL;
+       else if (res < 0)
+               return res;
+
+       fan_watchdog_reset();
+
+       return count;
+}
+
+static struct device_attribute dev_attr_fan_pwm1_enable =
+       __ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+               fan_pwm1_enable_show, fan_pwm1_enable_store);
+
+/* sysfs fan pwm1 ------------------------------------------------------ */
+static ssize_t fan_pwm1_show(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       int res;
+       u8 status;
+
+       res = fan_get_status_safe(&status);
+       if (res)
+               return res;
+
+       if (unlikely(tp_features.fan_ctrl_status_undef)) {
+               if (status != fan_control_initial_status) {
+                       tp_features.fan_ctrl_status_undef = 0;
+               } else {
+                       status = TP_EC_FAN_AUTO;
+               }
+       }
+
+       if ((status &
+            (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
+               status = fan_control_desired_level;
+
+       if (status > 7)
+               status = 7;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7);
+}
+
+static ssize_t fan_pwm1_store(struct device *dev,
+                             struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       unsigned long s;
+       int rc;
+       u8 status, newlevel;
+
+       if (parse_strtoul(buf, 255, &s))
+               return -EINVAL;
+
+       /* scale down from 0-255 to 0-7 */
+       newlevel = (s >> 5) & 0x07;
+
+       rc = mutex_lock_interruptible(&fan_mutex);
+       if (rc < 0)
+               return rc;
+
+       rc = fan_get_status(&status);
+       if (!rc && (status &
+                   (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+               rc = fan_set_level(newlevel);
+               if (rc == -ENXIO)
+                       rc = -EINVAL;
+               else if (!rc) {
+                       fan_update_desired_level(newlevel);
+                       fan_watchdog_reset();
+               }
+       }
+
+       mutex_unlock(&fan_mutex);
+       return (rc)? rc : count;
+}
+
+static struct device_attribute dev_attr_fan_pwm1 =
+       __ATTR(pwm1, S_IWUSR | S_IRUGO,
+               fan_pwm1_show, fan_pwm1_store);
+
+/* sysfs fan fan1_input ------------------------------------------------ */
+static ssize_t fan_fan1_input_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       int res;
+       unsigned int speed;
+
+       res = fan_get_speed(&speed);
+       if (res < 0)
+               return res;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", speed);
+}
+
+static struct device_attribute dev_attr_fan_fan1_input =
+       __ATTR(fan1_input, S_IRUGO,
+               fan_fan1_input_show, NULL);
+
+/* sysfs fan fan_watchdog (driver) ------------------------------------- */
+static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
+                                    char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval);
+}
+
+static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
+                                     const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 120, &t))
+               return -EINVAL;
+
+       if (!fan_control_allowed)
+               return -EPERM;
+
+       fan_watchdog_maxinterval = t;
+       fan_watchdog_reset();
+
+       return count;
+}
+
+static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
+               fan_fan_watchdog_show, fan_fan_watchdog_store);
+
+/* --------------------------------------------------------------------- */
+static struct attribute *fan_attributes[] = {
+       &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
+       &dev_attr_fan_fan1_input.attr,
+       NULL
+};
+
+static const struct attribute_group fan_attr_group = {
+       .attrs = fan_attributes,
+};
+
+static int __init fan_init(struct ibm_init_struct *iibm)
+{
+       int rc;
+
+       vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
+
+       mutex_init(&fan_mutex);
+       fan_status_access_mode = TPACPI_FAN_NONE;
+       fan_control_access_mode = TPACPI_FAN_WR_NONE;
+       fan_control_commands = 0;
+       fan_watchdog_maxinterval = 0;
+       tp_features.fan_ctrl_status_undef = 0;
+       fan_control_desired_level = 7;
+
+       IBM_ACPIHANDLE_INIT(fans);
+       IBM_ACPIHANDLE_INIT(gfan);
+       IBM_ACPIHANDLE_INIT(sfan);
+
+       if (gfan_handle) {
+               /* 570, 600e/x, 770e, 770x */
+               fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
+       } else {
+               /* all other ThinkPads: note that even old-style
+                * ThinkPad ECs supports the fan control register */
+               if (likely(acpi_ec_read(fan_status_offset,
+                                       &fan_control_initial_status))) {
+                       fan_status_access_mode = TPACPI_FAN_RD_TPEC;
+
+                       /* In some ThinkPads, neither the EC nor the ACPI
+                        * DSDT initialize the fan status, and it ends up
+                        * being set to 0x07 when it *could* be either
+                        * 0x07 or 0x80.
+                        *
+                        * Enable for TP-1Y (T43), TP-78 (R51e),
+                        * TP-76 (R52), TP-70 (T43, R52), which are known
+                        * to be buggy. */
+                       if (fan_control_initial_status == 0x07 &&
+                           ibm_thinkpad_ec_found &&
+                           ((ibm_thinkpad_ec_found[0] == '1' &&
+                             ibm_thinkpad_ec_found[1] == 'Y') ||
+                            (ibm_thinkpad_ec_found[0] == '7' &&
+                             (ibm_thinkpad_ec_found[1] == '6' ||
+                              ibm_thinkpad_ec_found[1] == '8' ||
+                              ibm_thinkpad_ec_found[1] == '0'))
+                           )) {
+                               printk(IBM_NOTICE
+                                      "fan_init: initial fan status is "
+                                      "unknown, assuming it is in auto "
+                                      "mode\n");
+                               tp_features.fan_ctrl_status_undef = 1;
+                       }
+               } else {
+                       printk(IBM_ERR
+                              "ThinkPad ACPI EC access misbehaving, "
+                              "fan status and control unavailable\n");
+                       return 1;
+               }
+       }
+
+       if (sfan_handle) {
+               /* 570, 770x-JL */
+               fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN;
+               fan_control_commands |=
+                   TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE;
+       } else {
+               if (!gfan_handle) {
+                       /* gfan without sfan means no fan control */
+                       /* all other models implement TP EC 0x2f control */
+
+                       if (fans_handle) {
+                               /* X31, X40, X41 */
+                               fan_control_access_mode =
+                                   TPACPI_FAN_WR_ACPI_FANS;
+                               fan_control_commands |=
+                                   TPACPI_FAN_CMD_SPEED |
+                                   TPACPI_FAN_CMD_LEVEL |
+                                   TPACPI_FAN_CMD_ENABLE;
+                       } else {
+                               fan_control_access_mode = TPACPI_FAN_WR_TPEC;
+                               fan_control_commands |=
+                                   TPACPI_FAN_CMD_LEVEL |
+                                   TPACPI_FAN_CMD_ENABLE;
+                       }
+               }
+       }
+
+       vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n",
+               str_supported(fan_status_access_mode != TPACPI_FAN_NONE ||
+                 fan_control_access_mode != TPACPI_FAN_WR_NONE),
+               fan_status_access_mode, fan_control_access_mode);
+
+       /* fan control master switch */
+       if (!fan_control_allowed) {
+               fan_control_access_mode = TPACPI_FAN_WR_NONE;
+               fan_control_commands = 0;
+               dbg_printk(TPACPI_DBG_INIT,
+                          "fan control features disabled by parameter\n");
+       }
+
+       /* update fan_control_desired_level */
+       if (fan_status_access_mode != TPACPI_FAN_NONE)
+               fan_get_status_safe(NULL);
+
+       if (fan_status_access_mode != TPACPI_FAN_NONE ||
+           fan_control_access_mode != TPACPI_FAN_WR_NONE) {
+               rc = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+                                        &fan_attr_group);
+               if (!(rc < 0))
+                       rc = driver_create_file(&tpacpi_pdriver.driver,
+                                       &driver_attr_fan_watchdog);
+               if (rc < 0)
+                       return rc;
+               return 0;
+       } else
+               return 1;
+}
+
+/*
+ * Call with fan_mutex held
+ */
+static void fan_update_desired_level(u8 status)
+{
+       if ((status &
+            (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+               if (status > 7)
+                       fan_control_desired_level = 7;
+               else
+                       fan_control_desired_level = status;
+       }
+}
+
+static int fan_get_status(u8 *status)
+{
+       u8 s;
+
+       /* TODO:
+        * Add TPACPI_FAN_RD_ACPI_FANS ? */
+
+       switch (fan_status_access_mode) {
+       case TPACPI_FAN_RD_ACPI_GFAN:
+               /* 570, 600e/x, 770e, 770x */
+
+               if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
+                       return -EIO;
+
+               if (likely(status))
+                       *status = s & 0x07;
+
+               break;
+
+       case TPACPI_FAN_RD_TPEC:
+               /* all except 570, 600e/x, 770e, 770x */
+               if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
+                       return -EIO;
+
+               if (likely(status))
+                       *status = s;
+
+               break;
+
+       default:
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int fan_get_status_safe(u8 *status)
+{
+       int rc;
+       u8 s;
+
+       rc = mutex_lock_interruptible(&fan_mutex);
+       if (rc < 0)
+               return rc;
+       rc = fan_get_status(&s);
+       if (!rc)
+               fan_update_desired_level(s);
+       mutex_unlock(&fan_mutex);
+
+       if (status)
+               *status = s;
+
+       return rc;
+}
+
+static void fan_exit(void)
+{
+       vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
+
+       /* FIXME: can we really do this unconditionally? */
+       sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group);
+       driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog);
+
+       cancel_delayed_work(&fan_watchdog_task);
+       flush_scheduled_work();
+}
+
+static int fan_get_speed(unsigned int *speed)
+{
+       u8 hi, lo;
+
+       switch (fan_status_access_mode) {
+       case TPACPI_FAN_RD_TPEC:
+               /* all except 570, 600e/x, 770e, 770x */
+               if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
+                            !acpi_ec_read(fan_rpm_offset + 1, &hi)))
+                       return -EIO;
+
+               if (likely(speed))
+                       *speed = (hi << 8) | lo;
+
+               break;
+
+       default:
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static void fan_watchdog_fire(struct work_struct *ignored)
+{
+       int rc;
+
+       printk(IBM_NOTICE "fan watchdog: enabling fan\n");
+       rc = fan_set_enable();
+       if (rc < 0) {
+               printk(IBM_ERR "fan watchdog: error %d while enabling fan, "
+                       "will try again later...\n", -rc);
+               /* reschedule for later */
+               fan_watchdog_reset();
+       }
+}
+
+static void fan_watchdog_reset(void)
+{
+       static int fan_watchdog_active = 0;
+
+       if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
+               return;
+
+       if (fan_watchdog_active)
+               cancel_delayed_work(&fan_watchdog_task);
+
+       if (fan_watchdog_maxinterval > 0) {
+               fan_watchdog_active = 1;
+               if (!schedule_delayed_work(&fan_watchdog_task,
+                               msecs_to_jiffies(fan_watchdog_maxinterval
+                                                * 1000))) {
+                       printk(IBM_ERR "failed to schedule the fan watchdog, "
+                              "watchdog will not trigger\n");
+               }
+       } else
+               fan_watchdog_active = 0;
+}
+
+static int fan_set_level(int level)
+{
+       if (!fan_control_allowed)
+               return -EPERM;
+
+       switch (fan_control_access_mode) {
+       case TPACPI_FAN_WR_ACPI_SFAN:
+               if (level >= 0 && level <= 7) {
+                       if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
+                               return -EIO;
+               } else
+                       return -EINVAL;
+               break;
+
+       case TPACPI_FAN_WR_ACPI_FANS:
+       case TPACPI_FAN_WR_TPEC:
+               if ((level != TP_EC_FAN_AUTO) &&
+                   (level != TP_EC_FAN_FULLSPEED) &&
+                   ((level < 0) || (level > 7)))
+                       return -EINVAL;
+
+               /* safety net should the EC not support AUTO
+                * or FULLSPEED mode bits and just ignore them */
+               if (level & TP_EC_FAN_FULLSPEED)
+                       level |= 7;     /* safety min speed 7 */
+               else if (level & TP_EC_FAN_FULLSPEED)
+                       level |= 4;     /* safety min speed 4 */
+
+               if (!acpi_ec_write(fan_status_offset, level))
+                       return -EIO;
+               else
+                       tp_features.fan_ctrl_status_undef = 0;
+               break;
+
+       default:
+               return -ENXIO;
+       }
+       return 0;
+}
+
+static int fan_set_level_safe(int level)
+{
+       int rc;
+
+       if (!fan_control_allowed)
+               return -EPERM;
+
+       rc = mutex_lock_interruptible(&fan_mutex);
+       if (rc < 0)
+               return rc;
+
+       if (level == TPACPI_FAN_LAST_LEVEL)
+               level = fan_control_desired_level;
+
+       rc = fan_set_level(level);
+       if (!rc)
+               fan_update_desired_level(level);
+
+       mutex_unlock(&fan_mutex);
+       return rc;
+}
+
+static int fan_set_enable(void)
+{
+       u8 s;
+       int rc;
+
+       if (!fan_control_allowed)
+               return -EPERM;
+
+       rc = mutex_lock_interruptible(&fan_mutex);
+       if (rc < 0)
+               return rc;
+
+       switch (fan_control_access_mode) {
+       case TPACPI_FAN_WR_ACPI_FANS:
+       case TPACPI_FAN_WR_TPEC:
+               rc = fan_get_status(&s);
+               if (rc < 0)
+                       break;
+
+               /* Don't go out of emergency fan mode */
+               if (s != 7) {
+                       s &= 0x07;
+                       s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
+               }
+
+               if (!acpi_ec_write(fan_status_offset, s))
+                       rc = -EIO;
+               else {
+                       tp_features.fan_ctrl_status_undef = 0;
+                       rc = 0;
+               }
+               break;
+
+       case TPACPI_FAN_WR_ACPI_SFAN:
+               rc = fan_get_status(&s);
+               if (rc < 0)
+                       break;
+
+               s &= 0x07;
+
+               /* Set fan to at least level 4 */
+               s |= 4;
+
+               if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
+                       rc= -EIO;
+               else
+                       rc = 0;
+               break;
+
+       default:
+               rc = -ENXIO;
+       }
+
+       mutex_unlock(&fan_mutex);
+       return rc;
+}
+
+static int fan_set_disable(void)
+{
+       int rc;
+
+       if (!fan_control_allowed)
+               return -EPERM;
+
+       rc = mutex_lock_interruptible(&fan_mutex);
+       if (rc < 0)
+               return rc;
+
+       rc = 0;
+       switch (fan_control_access_mode) {
+       case TPACPI_FAN_WR_ACPI_FANS:
+       case TPACPI_FAN_WR_TPEC:
+               if (!acpi_ec_write(fan_status_offset, 0x00))
+                       rc = -EIO;
+               else {
+                       fan_control_desired_level = 0;
+                       tp_features.fan_ctrl_status_undef = 0;
+               }
+               break;
+
+       case TPACPI_FAN_WR_ACPI_SFAN:
+               if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
+                       rc = -EIO;
+               else
+                       fan_control_desired_level = 0;
+               break;
+
+       default:
+               rc = -ENXIO;
+       }
+
+
+       mutex_unlock(&fan_mutex);
+       return rc;
+}
+
+static int fan_set_speed(int speed)
+{
+       int rc;
+
+       if (!fan_control_allowed)
+               return -EPERM;
+
+       rc = mutex_lock_interruptible(&fan_mutex);
+       if (rc < 0)
+               return rc;
+
+       rc = 0;
+       switch (fan_control_access_mode) {
+       case TPACPI_FAN_WR_ACPI_FANS:
+               if (speed >= 0 && speed <= 65535) {
+                       if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
+                                       speed, speed, speed))
+                               rc = -EIO;
+               } else
+                       rc = -EINVAL;
+               break;
+
+       default:
+               rc = -ENXIO;
+       }
+
+       mutex_unlock(&fan_mutex);
+       return rc;
+}
+
+static int fan_read(char *p)
+{
+       int len = 0;
+       int rc;
+       u8 status;
+       unsigned int speed = 0;
+
+       switch (fan_status_access_mode) {
+       case TPACPI_FAN_RD_ACPI_GFAN:
+               /* 570, 600e/x, 770e, 770x */
+               if ((rc = fan_get_status_safe(&status)) < 0)
+                       return rc;
+
+               len += sprintf(p + len, "status:\t\t%s\n"
+                              "level:\t\t%d\n",
+                              (status != 0) ? "enabled" : "disabled", status);
+               break;
+
+       case TPACPI_FAN_RD_TPEC:
+               /* all except 570, 600e/x, 770e, 770x */
+               if ((rc = fan_get_status_safe(&status)) < 0)
+                       return rc;
+
+               if (unlikely(tp_features.fan_ctrl_status_undef)) {
+                       if (status != fan_control_initial_status)
+                               tp_features.fan_ctrl_status_undef = 0;
+                       else
+                               /* Return most likely status. In fact, it
+                                * might be the only possible status */
+                               status = TP_EC_FAN_AUTO;
+               }
+
+               len += sprintf(p + len, "status:\t\t%s\n",
+                              (status != 0) ? "enabled" : "disabled");
+
+               if ((rc = fan_get_speed(&speed)) < 0)
+                       return rc;
+
+               len += sprintf(p + len, "speed:\t\t%d\n", speed);
+
+               if (status & TP_EC_FAN_FULLSPEED)
+                       /* Disengaged mode takes precedence */
+                       len += sprintf(p + len, "level:\t\tdisengaged\n");
+               else if (status & TP_EC_FAN_AUTO)
+                       len += sprintf(p + len, "level:\t\tauto\n");
+               else
+                       len += sprintf(p + len, "level:\t\t%d\n", status);
+               break;
+
+       case TPACPI_FAN_NONE:
+       default:
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       }
+
+       if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) {
+               len += sprintf(p + len, "commands:\tlevel <level>");
+
+               switch (fan_control_access_mode) {
+               case TPACPI_FAN_WR_ACPI_SFAN:
+                       len += sprintf(p + len, " (<level> is 0-7)\n");
+                       break;
+
+               default:
+                       len += sprintf(p + len, " (<level> is 0-7, "
+                                      "auto, disengaged, full-speed)\n");
+                       break;
+               }
+       }
+
+       if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
+               len += sprintf(p + len, "commands:\tenable, disable\n"
+                              "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
+                              "1-120 (seconds))\n");
+
+       if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
+               len += sprintf(p + len, "commands:\tspeed <speed>"
+                              " (<speed> is 0-65535)\n");
+
+       return len;
+}
+
+static int fan_write_cmd_level(const char *cmd, int *rc)
+{
+       int level;
+
+       if (strlencmp(cmd, "level auto") == 0)
+               level = TP_EC_FAN_AUTO;
+       else if ((strlencmp(cmd, "level disengaged") == 0) |
+                (strlencmp(cmd, "level full-speed") == 0))
+               level = TP_EC_FAN_FULLSPEED;
+       else if (sscanf(cmd, "level %d", &level) != 1)
+               return 0;
+
+       if ((*rc = fan_set_level_safe(level)) == -ENXIO)
+               printk(IBM_ERR "level command accepted for unsupported "
+                      "access mode %d", fan_control_access_mode);
+
+       return 1;
+}
+
+static int fan_write_cmd_enable(const char *cmd, int *rc)
+{
+       if (strlencmp(cmd, "enable") != 0)
+               return 0;
+
+       if ((*rc = fan_set_enable()) == -ENXIO)
+               printk(IBM_ERR "enable command accepted for unsupported "
+                      "access mode %d", fan_control_access_mode);
+
+       return 1;
+}
+
+static int fan_write_cmd_disable(const char *cmd, int *rc)
+{
+       if (strlencmp(cmd, "disable") != 0)
+               return 0;
+
+       if ((*rc = fan_set_disable()) == -ENXIO)
+               printk(IBM_ERR "disable command accepted for unsupported "
+                      "access mode %d", fan_control_access_mode);
+
+       return 1;
+}
+
+static int fan_write_cmd_speed(const char *cmd, int *rc)
+{
+       int speed;
+
+       /* TODO:
+        * Support speed <low> <medium> <high> ? */
+
+       if (sscanf(cmd, "speed %d", &speed) != 1)
+               return 0;
+
+       if ((*rc = fan_set_speed(speed)) == -ENXIO)
+               printk(IBM_ERR "speed command accepted for unsupported "
+                      "access mode %d", fan_control_access_mode);
+
+       return 1;
+}
+
+static int fan_write_cmd_watchdog(const char *cmd, int *rc)
+{
+       int interval;
+
+       if (sscanf(cmd, "watchdog %d", &interval) != 1)
+               return 0;
+
+       if (interval < 0 || interval > 120)
+               *rc = -EINVAL;
+       else
+               fan_watchdog_maxinterval = interval;
+
+       return 1;
+}
+
+static int fan_write(char *buf)
+{
+       char *cmd;
+       int rc = 0;
+
+       while (!rc && (cmd = next_cmd(&buf))) {
+               if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) &&
+                     fan_write_cmd_level(cmd, &rc)) &&
+                   !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) &&
+                     (fan_write_cmd_enable(cmd, &rc) ||
+                      fan_write_cmd_disable(cmd, &rc) ||
+                      fan_write_cmd_watchdog(cmd, &rc))) &&
+                   !((fan_control_commands & TPACPI_FAN_CMD_SPEED) &&
+                     fan_write_cmd_speed(cmd, &rc))
+                   )
+                       rc = -EINVAL;
+               else if (!rc)
+                       fan_watchdog_reset();
+       }
+
+       return rc;
+}
+
+static struct ibm_struct fan_driver_data = {
+       .name = "fan",
+       .read = fan_read,
+       .write = fan_write,
+       .exit = fan_exit,
+};
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Infrastructure
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/* /proc support */
+static struct proc_dir_entry *proc_dir = NULL;
+
+/* Subdriver registry */
+static LIST_HEAD(tpacpi_all_drivers);
+
+
+/*
+ * Module and infrastructure proble, init and exit handling
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DEBUG
+static const char * __init str_supported(int is_supported)
+{
+       static char text_unsupported[] __initdata = "not supported";
+
+       return (is_supported)? &text_unsupported[4] : &text_unsupported[0];
+}
+#endif /* CONFIG_THINKPAD_ACPI_DEBUG */
+
+static int __init ibm_init(struct ibm_init_struct *iibm)
+{
+       int ret;
+       struct ibm_struct *ibm = iibm->data;
+       struct proc_dir_entry *entry;
+
+       BUG_ON(ibm == NULL);
+
+       INIT_LIST_HEAD(&ibm->all_drivers);
+
+       if (ibm->flags.experimental && !experimental)
+               return 0;
+
+       dbg_printk(TPACPI_DBG_INIT,
+               "probing for %s\n", ibm->name);
+
+       if (iibm->init) {
+               ret = iibm->init(iibm);
+               if (ret > 0)
+                       return 0;       /* probe failed */
+               if (ret)
+                       return ret;
+
+               ibm->flags.init_called = 1;
+       }
+
+       if (ibm->acpi) {
+               if (ibm->acpi->hid) {
+                       ret = register_tpacpi_subdriver(ibm);
+                       if (ret)
+                               goto err_out;
+               }
+
+               if (ibm->acpi->notify) {
+                       ret = setup_acpi_notify(ibm);
+                       if (ret == -ENODEV) {
+                               printk(IBM_NOTICE "disabling subdriver %s\n",
+                                       ibm->name);
+                               ret = 0;
+                               goto err_out;
+                       }
+                       if (ret < 0)
+                               goto err_out;
+               }
+       }
+
+       dbg_printk(TPACPI_DBG_INIT,
+               "%s installed\n", ibm->name);
+
+       if (ibm->read) {
+               entry = create_proc_entry(ibm->name,
+                                         S_IFREG | S_IRUGO | S_IWUSR,
+                                         proc_dir);
+               if (!entry) {
+                       printk(IBM_ERR "unable to create proc entry %s\n",
+                              ibm->name);
+                       ret = -ENODEV;
+                       goto err_out;
+               }
+               entry->owner = THIS_MODULE;
+               entry->data = ibm;
+               entry->read_proc = &dispatch_procfs_read;
+               if (ibm->write)
+                       entry->write_proc = &dispatch_procfs_write;
+               ibm->flags.proc_created = 1;
+       }
+
+       list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers);
+
+       return 0;
+
+err_out:
+       dbg_printk(TPACPI_DBG_INIT,
+               "%s: at error exit path with result %d\n",
+               ibm->name, ret);
+
+       ibm_exit(ibm);
+       return (ret < 0)? ret : 0;
+}
+
+static void ibm_exit(struct ibm_struct *ibm)
+{
+       dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
+
+       list_del_init(&ibm->all_drivers);
+
+       if (ibm->flags.acpi_notify_installed) {
+               dbg_printk(TPACPI_DBG_EXIT,
+                       "%s: acpi_remove_notify_handler\n", ibm->name);
+               BUG_ON(!ibm->acpi);
+               acpi_remove_notify_handler(*ibm->acpi->handle,
+                                          ibm->acpi->type,
+                                          dispatch_acpi_notify);
+               ibm->flags.acpi_notify_installed = 0;
+               ibm->flags.acpi_notify_installed = 0;
+       }
+
+       if (ibm->flags.proc_created) {
+               dbg_printk(TPACPI_DBG_EXIT,
+                       "%s: remove_proc_entry\n", ibm->name);
+               remove_proc_entry(ibm->name, proc_dir);
+               ibm->flags.proc_created = 0;
+       }
+
+       if (ibm->flags.acpi_driver_registered) {
+               dbg_printk(TPACPI_DBG_EXIT,
+                       "%s: acpi_bus_unregister_driver\n", ibm->name);
+               BUG_ON(!ibm->acpi);
+               acpi_bus_unregister_driver(ibm->acpi->driver);
+               kfree(ibm->acpi->driver);
+               ibm->acpi->driver = NULL;
+               ibm->flags.acpi_driver_registered = 0;
+       }
+
+       if (ibm->flags.init_called && ibm->exit) {
+               ibm->exit();
+               ibm->flags.init_called = 0;
+       }
+
+       dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
+}
+
+/* Probing */
+
+static char *ibm_thinkpad_ec_found = NULL;
+
+static char* __init check_dmi_for_ec(void)
+{
+       struct dmi_device *dev = NULL;
+       char ec_fw_string[18];
+
+       /*
+        * ThinkPad T23 or newer, A31 or newer, R50e or newer,
+        * X32 or newer, all Z series;  Some models must have an
+        * up-to-date BIOS or they will not be detected.
+        *
+        * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+        */
+       while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+               if (sscanf(dev->name,
+                          "IBM ThinkPad Embedded Controller -[%17c",
+                          ec_fw_string) == 1) {
+                       ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
+                       ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
+                       return kstrdup(ec_fw_string, GFP_KERNEL);
+               }
+       }
+       return NULL;
+}
+
+static int __init probe_for_thinkpad(void)
+{
+       int is_thinkpad;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       /*
+        * Non-ancient models have better DMI tagging, but very old models
+        * don't.
+        */
+       is_thinkpad = dmi_name_in_vendors("ThinkPad");
+
+       /* ec is required because many other handles are relative to it */
+       IBM_ACPIHANDLE_INIT(ec);
+       if (!ec_handle) {
+               if (is_thinkpad)
+                       printk(IBM_ERR
+                               "Not yet supported ThinkPad detected!\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Risks a regression on very old machines, but reduces potential
+        * false positives a damn great deal
+        */
+       if (!is_thinkpad)
+               is_thinkpad = dmi_name_in_vendors("IBM");
+
+       if (!is_thinkpad && !force_load)
+               return -ENODEV;
+
+       return 0;
+}
+
+
+/* Module init, exit, parameters */
+
+static struct ibm_init_struct ibms_init[] __initdata = {
+       {
+               .init = thinkpad_acpi_driver_init,
+               .data = &thinkpad_acpi_driver_data,
+       },
+       {
+               .init = hotkey_init,
+               .data = &hotkey_driver_data,
+       },
+       {
+               .init = bluetooth_init,
+               .data = &bluetooth_driver_data,
+       },
+       {
+               .init = wan_init,
+               .data = &wan_driver_data,
+       },
+       {
+               .init = video_init,
+               .data = &video_driver_data,
+       },
+       {
+               .init = light_init,
+               .data = &light_driver_data,
+       },
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+       {
+               .init = dock_init,
+               .data = &dock_driver_data[0],
+       },
+       {
+               .init = dock_init2,
+               .data = &dock_driver_data[1],
+       },
+#endif
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+       {
+               .init = bay_init,
+               .data = &bay_driver_data,
+       },
+#endif
+       {
+               .init = cmos_init,
+               .data = &cmos_driver_data,
+       },
+       {
+               .init = led_init,
+               .data = &led_driver_data,
+       },
+       {
+               .init = beep_init,
+               .data = &beep_driver_data,
+       },
+       {
+               .init = thermal_init,
+               .data = &thermal_driver_data,
+       },
+       {
+               .data = &ecdump_driver_data,
+       },
+       {
+               .init = brightness_init,
+               .data = &brightness_driver_data,
+       },
+       {
+               .data = &volume_driver_data,
+       },
+       {
+               .init = fan_init,
+               .data = &fan_driver_data,
+       },
+};
+
+static int __init set_ibm_param(const char *val, struct kernel_param *kp)
+{
+       unsigned int i;
+       struct ibm_struct *ibm;
+
+       for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
+               ibm = ibms_init[i].data;
+               BUG_ON(ibm == NULL);
+
+               if (strcmp(ibm->name, kp->name) == 0 && ibm->write) {
+                       if (strlen(val) > sizeof(ibms_init[i].param) - 2)
+                               return -ENOSPC;
+                       strcpy(ibms_init[i].param, val);
+                       strcat(ibms_init[i].param, ",");
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int experimental;
+module_param(experimental, int, 0);
+
+static u32 dbg_level;
+module_param_named(debug, dbg_level, uint, 0);
+
+static int force_load;
+module_param(force_load, int, 0);
+
+static int fan_control_allowed;
+module_param_named(fan_control, fan_control_allowed, int, 0);
+
+#define IBM_PARAM(feature) \
+       module_param_call(feature, set_ibm_param, NULL, NULL, 0)
+
+IBM_PARAM(hotkey);
+IBM_PARAM(bluetooth);
+IBM_PARAM(video);
+IBM_PARAM(light);
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+IBM_PARAM(dock);
+#endif
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+IBM_PARAM(bay);
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+IBM_PARAM(cmos);
+IBM_PARAM(led);
+IBM_PARAM(beep);
+IBM_PARAM(ecdump);
+IBM_PARAM(brightness);
+IBM_PARAM(volume);
+IBM_PARAM(fan);
+
+static int __init thinkpad_acpi_module_init(void)
+{
+       int ret, i;
+
+       /* Driver-level probe */
+       ret = probe_for_thinkpad();
+       if (ret)
+               return ret;
+
+       /* Driver initialization */
+       ibm_thinkpad_ec_found = check_dmi_for_ec();
+       IBM_ACPIHANDLE_INIT(ecrd);
+       IBM_ACPIHANDLE_INIT(ecwr);
+
+       proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir);
+       if (!proc_dir) {
+               printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR);
+               thinkpad_acpi_module_exit();
+               return -ENODEV;
+       }
+       proc_dir->owner = THIS_MODULE;
+
+       ret = platform_driver_register(&tpacpi_pdriver);
+       if (ret) {
+               printk(IBM_ERR "unable to register platform driver\n");
+               thinkpad_acpi_module_exit();
+               return ret;
+       }
+       ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
+       if (ret) {
+               printk(IBM_ERR "unable to create sysfs driver attributes\n");
+               thinkpad_acpi_module_exit();
+               return ret;
+       }
+
+
+       /* Device initialization */
+       tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1,
+                                                       NULL, 0);
+       if (IS_ERR(tpacpi_pdev)) {
+               ret = PTR_ERR(tpacpi_pdev);
+               tpacpi_pdev = NULL;
+               printk(IBM_ERR "unable to register platform device\n");
+               thinkpad_acpi_module_exit();
+               return ret;
+       }
+       tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev);
+       if (IS_ERR(tpacpi_hwmon)) {
+               ret = PTR_ERR(tpacpi_hwmon);
+               tpacpi_hwmon = NULL;
+               printk(IBM_ERR "unable to register hwmon device\n");
+               thinkpad_acpi_module_exit();
+               return ret;
+       }
+       for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
+               ret = ibm_init(&ibms_init[i]);
+               if (ret >= 0 && *ibms_init[i].param)
+                       ret = ibms_init[i].data->write(ibms_init[i].param);
+               if (ret < 0) {
+                       thinkpad_acpi_module_exit();
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void thinkpad_acpi_module_exit(void)
+{
+       struct ibm_struct *ibm, *itmp;
+
+       list_for_each_entry_safe_reverse(ibm, itmp,
+                                        &tpacpi_all_drivers,
+                                        all_drivers) {
+               ibm_exit(ibm);
+       }
+
+       dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
+
+       if (tpacpi_hwmon)
+               hwmon_device_unregister(tpacpi_hwmon);
+
+       if (tpacpi_pdev)
+               platform_device_unregister(tpacpi_pdev);
+
+       tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+       platform_driver_unregister(&tpacpi_pdriver);
+
+       if (proc_dir)
+               remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
+
+       kfree(ibm_thinkpad_ec_found);
+}
+
+module_init(thinkpad_acpi_module_init);
+module_exit(thinkpad_acpi_module_exit);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
new file mode 100644 (file)
index 0000000..440145a
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ *  thinkpad_acpi.h - ThinkPad ACPI Extras
+ *
+ *
+ *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ *  Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef __THINKPAD_ACPI_H__
+#define __THINKPAD_ACPI_H__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+#include <linux/proc_fs.h>
+#include <linux/sysfs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/uaccess.h>
+
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+
+#include <acpi/acpi_drivers.h>
+#include <acpi/acnamesp.h>
+
+
+/****************************************************************************
+ * Main driver
+ */
+
+#define IBM_NAME "thinkpad"
+#define IBM_DESC "ThinkPad ACPI Extras"
+#define IBM_FILE "thinkpad_acpi"
+#define IBM_URL "http://ibm-acpi.sf.net/"
+#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
+
+#define IBM_PROC_DIR "ibm"
+#define IBM_ACPI_EVENT_PREFIX "ibm"
+#define IBM_DRVR_NAME IBM_FILE
+
+#define IBM_LOG IBM_FILE ": "
+#define IBM_ERR           KERN_ERR    IBM_LOG
+#define IBM_NOTICE KERN_NOTICE IBM_LOG
+#define IBM_INFO   KERN_INFO   IBM_LOG
+#define IBM_DEBUG  KERN_DEBUG  IBM_LOG
+
+#define IBM_MAX_ACPI_ARGS 3
+
+/* ThinkPad CMOS commands */
+#define TP_CMOS_VOLUME_DOWN    0
+#define TP_CMOS_VOLUME_UP      1
+#define TP_CMOS_VOLUME_MUTE    2
+#define TP_CMOS_BRIGHTNESS_UP  4
+#define TP_CMOS_BRIGHTNESS_DOWN        5
+
+#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
+#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
+#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
+
+/* Debugging */
+#define TPACPI_DBG_ALL         0xffff
+#define TPACPI_DBG_ALL         0xffff
+#define TPACPI_DBG_INIT                0x0001
+#define TPACPI_DBG_EXIT                0x0002
+#define dbg_printk(a_dbg_level, format, arg...) \
+       do { if (dbg_level & a_dbg_level) \
+               printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0)
+#ifdef CONFIG_THINKPAD_ACPI_DEBUG
+#define vdbg_printk(a_dbg_level, format, arg...) \
+       dbg_printk(a_dbg_level, format, ## arg)
+static const char *str_supported(int is_supported);
+#else
+#define vdbg_printk(a_dbg_level, format, arg...)
+#endif
+
+/* ACPI HIDs */
+#define IBM_HKEY_HID    "IBM0068"
+#define IBM_PCI_HID     "PNP0A03"
+
+/* ACPI helpers */
+static int __must_check acpi_evalf(acpi_handle handle,
+                     void *res, char *method, char *fmt, ...);
+static int __must_check acpi_ec_read(int i, u8 * p);
+static int __must_check acpi_ec_write(int i, u8 v);
+static int __must_check _sta(acpi_handle handle);
+
+/* ACPI handles */
+static acpi_handle root_handle;                        /* root namespace */
+static acpi_handle ec_handle;                  /* EC */
+static acpi_handle ecrd_handle, ecwr_handle;   /* 570 EC access */
+static acpi_handle cmos_handle, hkey_handle;   /* basic thinkpad handles */
+
+static void drv_acpi_handle_init(char *name,
+                  acpi_handle *handle, acpi_handle parent,
+                  char **paths, int num_paths, char **path);
+#define IBM_ACPIHANDLE_INIT(object)                                            \
+       drv_acpi_handle_init(#object, &object##_handle, *object##_parent,       \
+               object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
+
+/* ThinkPad ACPI helpers */
+static int issue_thinkpad_cmos_command(int cmos_cmd);
+
+/* procfs support */
+static struct proc_dir_entry *proc_dir;
+
+/* procfs helpers */
+static int dispatch_procfs_read(char *page, char **start, off_t off,
+               int count, int *eof, void *data);
+static int dispatch_procfs_write(struct file *file,
+               const char __user * userbuf,
+               unsigned long count, void *data);
+static char *next_cmd(char **cmds);
+
+/* sysfs support */
+struct attribute_set {
+       unsigned int members, max_members;
+       struct attribute_group group;
+};
+
+static struct attribute_set *create_attr_set(unsigned int max_members,
+                                               const char* name);
+#define destroy_attr_set(_set) \
+       kfree(_set);
+static int add_to_attr_set(struct attribute_set* s, struct attribute *attr);
+static int add_many_to_attr_set(struct attribute_set* s,
+                       struct attribute **attr,
+                       unsigned int count);
+#define register_attr_set_with_sysfs(_attr_set, _kobj) \
+       sysfs_create_group(_kobj, &_attr_set->group)
+static void delete_attr_set(struct attribute_set* s, struct kobject *kobj);
+
+static int parse_strtoul(const char *buf, unsigned long max,
+                       unsigned long *value);
+
+/* Device model */
+static struct platform_device *tpacpi_pdev;
+static struct class_device *tpacpi_hwmon;
+static struct platform_driver tpacpi_pdriver;
+static int tpacpi_create_driver_attributes(struct device_driver *drv);
+static void tpacpi_remove_driver_attributes(struct device_driver *drv);
+
+/* Module */
+static int experimental;
+static u32 dbg_level;
+static int force_load;
+static char *ibm_thinkpad_ec_found;
+
+static char* check_dmi_for_ec(void);
+static int thinkpad_acpi_module_init(void);
+static void thinkpad_acpi_module_exit(void);
+
+
+/****************************************************************************
+ * Subdrivers
+ */
+
+struct ibm_struct;
+
+struct tp_acpi_drv_struct {
+       char *hid;
+       struct acpi_driver *driver;
+
+       void (*notify) (struct ibm_struct *, u32);
+       acpi_handle *handle;
+       u32 type;
+       struct acpi_device *device;
+};
+
+struct ibm_struct {
+       char *name;
+
+       int (*read) (char *);
+       int (*write) (char *);
+       void (*exit) (void);
+
+       struct list_head all_drivers;
+
+       struct tp_acpi_drv_struct *acpi;
+
+       struct {
+               u8 acpi_driver_registered:1;
+               u8 acpi_notify_installed:1;
+               u8 proc_created:1;
+               u8 init_called:1;
+               u8 experimental:1;
+       } flags;
+};
+
+struct ibm_init_struct {
+       char param[32];
+
+       int (*init) (struct ibm_init_struct *);
+       struct ibm_struct *data;
+};
+
+static struct {
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+       u16 bay_status:1;
+       u16 bay_eject:1;
+       u16 bay_status2:1;
+       u16 bay_eject2:1;
+#endif
+       u16 bluetooth:1;
+       u16 hotkey:1;
+       u16 hotkey_mask:1;
+       u16 light:1;
+       u16 light_status:1;
+       u16 wan:1;
+       u16 fan_ctrl_status_undef:1;
+} tp_features;
+
+static struct list_head tpacpi_all_drivers;
+
+static struct ibm_init_struct ibms_init[];
+static int set_ibm_param(const char *val, struct kernel_param *kp);
+static int ibm_init(struct ibm_init_struct *iibm);
+static void ibm_exit(struct ibm_struct *ibm);
+
+
+/*
+ * procfs master subdriver
+ */
+static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm);
+static int thinkpad_acpi_driver_read(char *p);
+
+
+/*
+ * Bay subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+static acpi_handle bay_handle, bay_ej_handle;
+static acpi_handle bay2_handle, bay2_ej_handle;
+
+static int bay_init(struct ibm_init_struct *iibm);
+static void bay_notify(struct ibm_struct *ibm, u32 event);
+static int bay_read(char *p);
+static int bay_write(char *buf);
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+
+
+/*
+ * Beep subdriver
+ */
+
+static acpi_handle beep_handle;
+
+static int beep_read(char *p);
+static int beep_write(char *buf);
+
+
+/*
+ * Bluetooth subdriver
+ */
+
+#define TPACPI_BLUETH_SYSFS_GROUP "bluetooth"
+
+enum {
+       /* ACPI GBDC/SBDC bits */
+       TP_ACPI_BLUETOOTH_HWPRESENT     = 0x01, /* Bluetooth hw available */
+       TP_ACPI_BLUETOOTH_RADIOSSW      = 0x02, /* Bluetooth radio enabled */
+       TP_ACPI_BLUETOOTH_UNK           = 0x04, /* unknown function */
+};
+
+static int bluetooth_init(struct ibm_init_struct *iibm);
+static int bluetooth_get_radiosw(void);
+static int bluetooth_set_radiosw(int radio_on);
+static int bluetooth_read(char *p);
+static int bluetooth_write(char *buf);
+
+
+/*
+ * Brightness (backlight) subdriver
+ */
+
+#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
+
+static struct backlight_device *ibm_backlight_device;
+static int brightness_offset = 0x31;
+
+static int brightness_init(struct ibm_init_struct *iibm);
+static void brightness_exit(void);
+static int brightness_get(struct backlight_device *bd);
+static int brightness_set(int value);
+static int brightness_update_status(struct backlight_device *bd);
+static int brightness_read(char *p);
+static int brightness_write(char *buf);
+
+
+/*
+ * CMOS subdriver
+ */
+
+static int cmos_read(char *p);
+static int cmos_write(char *buf);
+
+
+/*
+ * Dock subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+static acpi_handle pci_handle;
+static acpi_handle dock_handle;
+
+static void dock_notify(struct ibm_struct *ibm, u32 event);
+static int dock_read(char *p);
+static int dock_write(char *buf);
+#endif /* CONFIG_THINKPAD_ACPI_DOCK */
+
+
+/*
+ * EC dump subdriver
+ */
+
+static int ecdump_read(char *p) ;
+static int ecdump_write(char *buf);
+
+
+/*
+ * Fan subdriver
+ */
+
+enum {                                 /* Fan control constants */
+       fan_status_offset = 0x2f,       /* EC register 0x2f */
+       fan_rpm_offset = 0x84,          /* EC register 0x84: LSB, 0x85 MSB (RPM)
+                                        * 0x84 must be read before 0x85 */
+
+       TP_EC_FAN_FULLSPEED = 0x40,     /* EC fan mode: full speed */
+       TP_EC_FAN_AUTO      = 0x80,     /* EC fan mode: auto fan control */
+
+       TPACPI_FAN_LAST_LEVEL = 0x100,  /* Use cached last-seen fan level */
+};
+
+enum fan_status_access_mode {
+       TPACPI_FAN_NONE = 0,            /* No fan status or control */
+       TPACPI_FAN_RD_ACPI_GFAN,        /* Use ACPI GFAN */
+       TPACPI_FAN_RD_TPEC,             /* Use ACPI EC regs 0x2f, 0x84-0x85 */
+};
+
+enum fan_control_access_mode {
+       TPACPI_FAN_WR_NONE = 0,         /* No fan control */
+       TPACPI_FAN_WR_ACPI_SFAN,        /* Use ACPI SFAN */
+       TPACPI_FAN_WR_TPEC,             /* Use ACPI EC reg 0x2f */
+       TPACPI_FAN_WR_ACPI_FANS,        /* Use ACPI FANS and EC reg 0x2f */
+};
+
+enum fan_control_commands {
+       TPACPI_FAN_CMD_SPEED    = 0x0001,       /* speed command */
+       TPACPI_FAN_CMD_LEVEL    = 0x0002,       /* level command  */
+       TPACPI_FAN_CMD_ENABLE   = 0x0004,       /* enable/disable cmd,
+                                                * and also watchdog cmd */
+};
+
+static int fan_control_allowed;
+
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
+static u8 fan_control_initial_status;
+static u8 fan_control_desired_level;
+static int fan_watchdog_maxinterval;
+
+static struct mutex fan_mutex;
+
+static acpi_handle fans_handle, gfan_handle, sfan_handle;
+
+static int fan_init(struct ibm_init_struct *iibm);
+static void fan_exit(void);
+static int fan_get_status(u8 *status);
+static int fan_get_status_safe(u8 *status);
+static int fan_get_speed(unsigned int *speed);
+static void fan_update_desired_level(u8 status);
+static void fan_watchdog_fire(struct work_struct *ignored);
+static void fan_watchdog_reset(void);
+static int fan_set_level(int level);
+static int fan_set_level_safe(int level);
+static int fan_set_enable(void);
+static int fan_set_disable(void);
+static int fan_set_speed(int speed);
+static int fan_read(char *p);
+static int fan_write(char *buf);
+static int fan_write_cmd_level(const char *cmd, int *rc);
+static int fan_write_cmd_enable(const char *cmd, int *rc);
+static int fan_write_cmd_disable(const char *cmd, int *rc);
+static int fan_write_cmd_speed(const char *cmd, int *rc);
+static int fan_write_cmd_watchdog(const char *cmd, int *rc);
+
+
+/*
+ * Hotkey subdriver
+ */
+
+#define TPACPI_HOTKEY_SYSFS_GROUP "hotkey"
+
+static int hotkey_orig_status;
+static int hotkey_orig_mask;
+
+static struct mutex hotkey_mutex;
+
+static int hotkey_init(struct ibm_init_struct *iibm);
+static void hotkey_exit(void);
+static int hotkey_get(int *status, int *mask);
+static int hotkey_set(int status, int mask);
+static void hotkey_notify(struct ibm_struct *ibm, u32 event);
+static int hotkey_read(char *p);
+static int hotkey_write(char *buf);
+
+
+/*
+ * LED subdriver
+ */
+
+enum led_access_mode {
+       TPACPI_LED_NONE = 0,
+       TPACPI_LED_570, /* 570 */
+       TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+       TPACPI_LED_NEW, /* all others */
+};
+
+enum { /* For TPACPI_LED_OLD */
+       TPACPI_LED_EC_HLCL = 0x0c,      /* EC reg to get led to power on */
+       TPACPI_LED_EC_HLBL = 0x0d,      /* EC reg to blink a lit led */
+       TPACPI_LED_EC_HLMS = 0x0e,      /* EC reg to select led to command */
+};
+
+static enum led_access_mode led_supported;
+static acpi_handle led_handle;
+
+static int led_init(struct ibm_init_struct *iibm);
+static int led_read(char *p);
+static int led_write(char *buf);
+
+/*
+ * Light (thinklight) subdriver
+ */
+
+static acpi_handle lght_handle, ledb_handle;
+
+static int light_init(struct ibm_init_struct *iibm);
+static int light_read(char *p);
+static int light_write(char *buf);
+
+
+/*
+ * Thermal subdriver
+ */
+
+enum thermal_access_mode {
+       TPACPI_THERMAL_NONE = 0,        /* No thermal support */
+       TPACPI_THERMAL_ACPI_TMP07,      /* Use ACPI TMP0-7 */
+       TPACPI_THERMAL_ACPI_UPDT,       /* Use ACPI TMP0-7 with UPDT */
+       TPACPI_THERMAL_TPEC_8,          /* Use ACPI EC regs, 8 sensors */
+       TPACPI_THERMAL_TPEC_16,         /* Use ACPI EC regs, 16 sensors */
+};
+
+enum { /* TPACPI_THERMAL_TPEC_* */
+       TP_EC_THERMAL_TMP0 = 0x78,      /* ACPI EC regs TMP 0..7 */
+       TP_EC_THERMAL_TMP8 = 0xC0,      /* ACPI EC regs TMP 8..15 */
+       TP_EC_THERMAL_TMP_NA = -128,    /* ACPI EC sensor not available */
+};
+
+#define TPACPI_MAX_THERMAL_SENSORS 16  /* Max thermal sensors supported */
+struct ibm_thermal_sensors_struct {
+       s32 temp[TPACPI_MAX_THERMAL_SENSORS];
+};
+
+static enum thermal_access_mode thermal_read_mode;
+
+static int thermal_init(struct ibm_init_struct *iibm);
+static int thermal_get_sensor(int idx, s32 *value);
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s);
+static int thermal_read(char *p);
+
+
+/*
+ * Video subdriver
+ */
+
+enum video_access_mode {
+       TPACPI_VIDEO_NONE = 0,
+       TPACPI_VIDEO_570,       /* 570 */
+       TPACPI_VIDEO_770,       /* 600e/x, 770e, 770x */
+       TPACPI_VIDEO_NEW,       /* all others */
+};
+
+enum { /* video status flags, based on VIDEO_570 */
+       TP_ACPI_VIDEO_S_LCD = 0x01,     /* LCD output enabled */
+       TP_ACPI_VIDEO_S_CRT = 0x02,     /* CRT output enabled */
+       TP_ACPI_VIDEO_S_DVI = 0x08,     /* DVI output enabled */
+};
+
+enum {  /* TPACPI_VIDEO_570 constants */
+       TP_ACPI_VIDEO_570_PHSCMD = 0x87,        /* unknown magic constant :( */
+       TP_ACPI_VIDEO_570_PHSMASK = 0x03,       /* PHS bits that map to
+                                                * video_status_flags */
+       TP_ACPI_VIDEO_570_PHS2CMD = 0x8b,       /* unknown magic constant :( */
+       TP_ACPI_VIDEO_570_PHS2SET = 0x80,       /* unknown magic constant :( */
+};
+
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
+static acpi_handle vid_handle, vid2_handle;
+
+static int video_init(struct ibm_init_struct *iibm);
+static void video_exit(void);
+static int video_outputsw_get(void);
+static int video_outputsw_set(int status);
+static int video_autosw_get(void);
+static int video_autosw_set(int enable);
+static int video_outputsw_cycle(void);
+static int video_expand_toggle(void);
+static int video_read(char *p);
+static int video_write(char *buf);
+
+
+/*
+ * Volume subdriver
+ */
+
+static int volume_offset = 0x30;
+
+static int volume_read(char *p);
+static int volume_write(char *buf);
+
+
+/*
+ * Wan subdriver
+ */
+
+#define TPACPI_WAN_SYSFS_GROUP "wwan"
+
+enum {
+       /* ACPI GWAN/SWAN bits */
+       TP_ACPI_WANCARD_HWPRESENT       = 0x01, /* Wan hw available */
+       TP_ACPI_WANCARD_RADIOSSW        = 0x02, /* Wan radio enabled */
+       TP_ACPI_WANCARD_UNK             = 0x04, /* unknown function */
+};
+
+static int wan_init(struct ibm_init_struct *iibm);
+static int wan_get_radiosw(void);
+static int wan_set_radiosw(int radio_on);
+static int wan_read(char *p);
+static int wan_write(char *buf);
+
+
+#endif /* __THINKPAD_ACPI_H */
index c7511c4d3b68f358959183d8e21874026a86f9d7..9588da3a30e7ccd75b32ff8536d864ee964cb4c7 100644 (file)
@@ -83,7 +83,6 @@ static int max_interrupt_work = 10;
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/pm.h>
-#include <linux/pm_legacy.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>       /* for udelay() */
 #include <linux/spinlock.h>
index 32a3003893d8893e272ae4aa5b8e4f34beb280c6..dcdad217df51ef439a695215177c1fd1a177274b 100644 (file)
@@ -486,8 +486,8 @@ config SGI_IOC3_ETH_HW_TX_CSUM
          enables offloading for checksums on transmit.  If unsure, say Y.
 
 config MIPS_SIM_NET
-       tristate "MIPS simulator Network device (EXPERIMENTAL)"
-       depends on MIPS_SIM && EXPERIMENTAL
+       tristate "MIPS simulator Network device"
+       depends on NET_ETHERNET && MIPS_SIM
        help
          The MIPSNET device is a simple Ethernet network device which is
          emulated by the MIPS Simulator.
@@ -1444,7 +1444,8 @@ config CS89x0
 
 config TC35815
        tristate "TOSHIBA TC35815 Ethernet support"
-       depends on NET_PCI && PCI && TOSHIBA_JMR3927
+       depends on NET_PCI && PCI && MIPS
+       select MII
 
 config DGRS
        tristate "Digi Intl. RightSwitch SE-X support"
@@ -2273,11 +2274,12 @@ config GFAR_NAPI
        depends on GIANFAR
 
 config UCC_GETH
-       tristate "Freescale QE UCC GETH"
-       depends on QUICC_ENGINE && UCC_FAST
+       tristate "Freescale QE Gigabit Ethernet"
+       depends on QUICC_ENGINE
+       select UCC_FAST
        help
-         This driver supports the Gigabit Ethernet mode of QE UCC.
-         QE can be found on MPC836x CPUs.
+         This driver supports the Gigabit Ethernet mode of the QUICC Engine,
+         which is available on some Freescale SOCs.
 
 config UGETH_NAPI
        bool "NAPI Support"
@@ -2291,14 +2293,10 @@ config UGETH_FILTERING
        bool "Mac address filtering support"
        depends on UCC_GETH
 
-config UGETH_TX_ON_DEMOND
-       bool "Transmit on Demond support"
+config UGETH_TX_ON_DEMAND
+       bool "Transmit on Demand support"
        depends on UCC_GETH
 
-config UGETH_HAS_GIGA
-       bool
-       depends on UCC_GETH && PPC_MPC836x
-
 config MV643XX_ETH
        tristate "MV-643XX Ethernet support"
        depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32)
index 58527322a39dd2a4f3f6cef9e12fe78bb498a322..59c0459a037c7d4027ac7d1c7415d98ef687694e 100644 (file)
@@ -18,7 +18,7 @@ gianfar_driver-objs := gianfar.o \
                gianfar_sysfs.o
 
 obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
-ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o
+ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o
 
 #
 # link order important here
index 382d23f810ab823189cf108751e24e4970537217..743ad8b41b5edce3eeb833cb3aed185904126038 100644 (file)
@@ -4,8 +4,6 @@
 
 obj-$(CONFIG_CHELSIO_T1) += cxgb.o
 
-cxgb-$(CONFIG_CHELSIO_T1_1G) += ixf1010.o mac.o mv88e1xxx.o vsc7326.o vsc8244.o
+cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o
 cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \
             mv88x201x.o my3126.o $(cxgb-y)
-
-
index 787f2f2820fe461625da7392c8c8b1af49d74314..8ba702c8b560c8b9cab8816e9f60f7e07a0c7bc0 100644 (file)
@@ -322,9 +322,9 @@ struct board_info {
        unsigned char           mdio_mdiinv;
        unsigned char           mdio_mdc;
        unsigned char           mdio_phybaseaddr;
-       struct gmac            *gmac;
-       struct gphy            *gphy;
-       struct mdio_ops        *mdio_ops;
+       const struct gmac      *gmac;
+       const struct gphy      *gphy;
+       const struct mdio_ops  *mdio_ops;
        const char             *desc;
 };
 
index cf9143499882dc1d128f65ed0031cf919b09775b..79d855e267e0238a5d314d3c72098529f1df5a90 100644 (file)
@@ -100,7 +100,7 @@ struct cphy {
 
        u32 elmer_gpo;
 
-       struct cphy_ops *ops;                /* PHY operations */
+       const struct cphy_ops *ops;            /* PHY operations */
        int (*mdio_read)(adapter_t *adapter, int phy_addr, int mmd_addr,
                         int reg_addr, unsigned int *val);
        int (*mdio_write)(adapter_t *adapter, int phy_addr, int mmd_addr,
@@ -136,7 +136,7 @@ static inline int simple_mdio_write(struct cphy *cphy, int reg,
 /* Convenience initializer */
 static inline void cphy_init(struct cphy *phy, adapter_t *adapter,
                             int phy_addr, struct cphy_ops *phy_ops,
-                            struct mdio_ops *mdio_ops)
+                            const struct mdio_ops *mdio_ops)
 {
        phy->adapter = adapter;
        phy->addr    = phy_addr;
@@ -151,7 +151,7 @@ static inline void cphy_init(struct cphy *phy, adapter_t *adapter,
 struct gphy {
        /* Construct a PHY instance with the given PHY address */
        struct cphy *(*create)(adapter_t *adapter, int phy_addr,
-                              struct mdio_ops *mdio_ops);
+                              const struct mdio_ops *mdio_ops);
 
        /*
         * Reset the PHY chip.  This resets the whole PHY chip, not individual
@@ -160,11 +160,9 @@ struct gphy {
        int (*reset)(adapter_t *adapter);
 };
 
-extern struct gphy t1_my3126_ops;
-extern struct gphy t1_mv88e1xxx_ops;
-extern struct gphy t1_vsc8244_ops;
-extern struct gphy t1_xpak_ops;
-extern struct gphy t1_mv88x201x_ops;
-extern struct gphy t1_dummy_phy_ops;
+extern const struct gphy t1_my3126_ops;
+extern const struct gphy t1_mv88e1xxx_ops;
+extern const struct gphy t1_vsc8244_ops;
+extern const struct gphy t1_mv88x201x_ops;
 
 #endif /* _CXGB_CPHY_H_ */
index 006a2eb2d3624a0aeeb28de15080dbdd1c8798a8..d42337457cf74bdc62e625a9688d1cb2728cd929 100644 (file)
@@ -126,7 +126,7 @@ typedef struct _cmac_instance cmac_instance;
 struct cmac {
        struct cmac_statistics stats;
        adapter_t *adapter;
-       struct cmac_ops *ops;
+       const struct cmac_ops *ops;
        cmac_instance *instance;
 };
 
@@ -136,11 +136,7 @@ struct gmac {
        int (*reset)(adapter_t *);
 };
 
-extern struct gmac t1_pm3393_ops;
-extern struct gmac t1_chelsio_mac_ops;
-extern struct gmac t1_vsc7321_ops;
-extern struct gmac t1_vsc7326_ops;
-extern struct gmac t1_ixf1010_ops;
-extern struct gmac t1_dummy_mac_ops;
+extern const struct gmac t1_pm3393_ops;
+extern const struct gmac t1_vsc7326_ops;
 
 #endif /* _CXGB_GMAC_H_ */
diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c
deleted file mode 100644 (file)
index 10b2a9a..0000000
+++ /dev/null
@@ -1,505 +0,0 @@
-/* $Date: 2005/11/12 02:13:49 $ $RCSfile: ixf1010.c,v $ $Revision: 1.36 $ */
-#include "gmac.h"
-#include "elmer0.h"
-
-/* Update fast changing statistics every 15 seconds */
-#define STATS_TICK_SECS 15
-/* 30 minutes for full statistics update */
-#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS)
-
-/*
- * The IXF1010 can handle frames up to 16383 bytes but it's optimized for
- * frames up to 9831 (0x2667) bytes, so we limit jumbo frame size to this.
- * This length includes ethernet header and FCS.
- */
-#define MAX_FRAME_SIZE 0x2667
-
-/* MAC registers */
-enum {
-       /* Per-port registers */
-       REG_MACADDR_LOW = 0,
-       REG_MACADDR_HIGH = 0x4,
-       REG_FDFC_TYPE = 0xC,
-       REG_FC_TX_TIMER_VALUE = 0x1c,
-       REG_IPG_RX_TIME1 = 0x28,
-       REG_IPG_RX_TIME2 = 0x2c,
-       REG_IPG_TX_TIME = 0x30,
-       REG_PAUSE_THRES = 0x38,
-       REG_MAX_FRAME_SIZE = 0x3c,
-       REG_RGMII_SPEED = 0x40,
-       REG_FC_ENABLE = 0x48,
-       REG_DISCARD_CTRL_FRAMES = 0x54,
-       REG_DIVERSE_CONFIG = 0x60,
-       REG_RX_FILTER = 0x64,
-       REG_MC_ADDR_LOW = 0x68,
-       REG_MC_ADDR_HIGH = 0x6c,
-
-       REG_RX_OCTETS_OK = 0x80,
-       REG_RX_OCTETS_BAD = 0x84,
-       REG_RX_UC_PKTS = 0x88,
-       REG_RX_MC_PKTS = 0x8c,
-       REG_RX_BC_PKTS = 0x90,
-       REG_RX_FCS_ERR = 0xb0,
-       REG_RX_TAGGED = 0xb4,
-       REG_RX_DATA_ERR = 0xb8,
-       REG_RX_ALIGN_ERR = 0xbc,
-       REG_RX_LONG_ERR = 0xc0,
-       REG_RX_JABBER_ERR = 0xc4,
-       REG_RX_PAUSE_FRAMES = 0xc8,
-       REG_RX_UNKNOWN_CTRL_FRAMES = 0xcc,
-       REG_RX_VERY_LONG_ERR = 0xd0,
-       REG_RX_RUNT_ERR = 0xd4,
-       REG_RX_SHORT_ERR = 0xd8,
-       REG_RX_SYMBOL_ERR = 0xe4,
-
-       REG_TX_OCTETS_OK = 0x100,
-       REG_TX_OCTETS_BAD = 0x104,
-       REG_TX_UC_PKTS = 0x108,
-       REG_TX_MC_PKTS = 0x10c,
-       REG_TX_BC_PKTS = 0x110,
-       REG_TX_EXCESSIVE_LEN_DROP = 0x14c,
-       REG_TX_UNDERRUN = 0x150,
-       REG_TX_TAGGED = 0x154,
-       REG_TX_PAUSE_FRAMES = 0x15C,
-
-       /* Global registers */
-       REG_PORT_ENABLE = 0x1400,
-
-       REG_JTAG_ID = 0x1430,
-
-       RX_FIFO_HIGH_WATERMARK_BASE = 0x1600,
-       RX_FIFO_LOW_WATERMARK_BASE = 0x1628,
-       RX_FIFO_FRAMES_REMOVED_BASE = 0x1650,
-
-       REG_RX_ERR_DROP = 0x167c,
-       REG_RX_FIFO_OVERFLOW_EVENT = 0x1680,
-
-       TX_FIFO_HIGH_WATERMARK_BASE = 0x1800,
-       TX_FIFO_LOW_WATERMARK_BASE = 0x1828,
-       TX_FIFO_XFER_THRES_BASE = 0x1850,
-
-       REG_TX_FIFO_OVERFLOW_EVENT = 0x1878,
-       REG_TX_FIFO_OOS_EVENT = 0x1884,
-
-       TX_FIFO_FRAMES_REMOVED_BASE = 0x1888,
-
-       REG_SPI_RX_BURST = 0x1c00,
-       REG_SPI_RX_TRAINING = 0x1c04,
-       REG_SPI_RX_CALENDAR = 0x1c08,
-       REG_SPI_TX_SYNC = 0x1c0c
-};
-
-enum {                     /* RMON registers */
-       REG_RxOctetsTotalOK = 0x80,
-       REG_RxOctetsBad = 0x84,
-       REG_RxUCPkts = 0x88,
-       REG_RxMCPkts = 0x8c,
-       REG_RxBCPkts = 0x90,
-       REG_RxJumboPkts = 0xac,
-       REG_RxFCSErrors = 0xb0,
-       REG_RxDataErrors = 0xb8,
-       REG_RxAlignErrors = 0xbc,
-       REG_RxLongErrors = 0xc0,
-       REG_RxJabberErrors = 0xc4,
-       REG_RxPauseMacControlCounter = 0xc8,
-       REG_RxVeryLongErrors = 0xd0,
-       REG_RxRuntErrors = 0xd4,
-       REG_RxShortErrors = 0xd8,
-       REG_RxSequenceErrors = 0xe0,
-       REG_RxSymbolErrors = 0xe4,
-
-       REG_TxOctetsTotalOK = 0x100,
-       REG_TxOctetsBad = 0x104,
-       REG_TxUCPkts = 0x108,
-       REG_TxMCPkts = 0x10c,
-       REG_TxBCPkts = 0x110,
-       REG_TxJumboPkts = 0x12C,
-       REG_TxTotalCollisions = 0x134,
-       REG_TxExcessiveLengthDrop = 0x14c,
-       REG_TxUnderrun = 0x150,
-       REG_TxCRCErrors = 0x158,
-       REG_TxPauseFrames = 0x15c
-};
-
-enum {
-       DIVERSE_CONFIG_PAD_ENABLE = 0x80,
-       DIVERSE_CONFIG_CRC_ADD = 0x40
-};
-
-#define MACREG_BASE            0
-#define MACREG(mac, mac_reg)   ((mac)->instance->mac_base + (mac_reg))
-
-struct _cmac_instance {
-       u32 mac_base;
-       u32 index;
-       u32 version;
-       u32 ticks;
-};
-
-static void disable_port(struct cmac *mac)
-{
-       u32 val;
-
-       t1_tpi_read(mac->adapter, REG_PORT_ENABLE, &val);
-       val &= ~(1 << mac->instance->index);
-       t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val);
-}
-
-/*
- * Read the current values of the RMON counters and add them to the cumulative
- * port statistics.  The HW RMON counters are cleared by this operation.
- */
-static void port_stats_update(struct cmac *mac)
-{
-       static struct {
-               unsigned int reg;
-               unsigned int offset;
-       } hw_stats[] = {
-
-#define HW_STAT(name, stat_name) \
-       { REG_##name, \
-         (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
-
-               /* Rx stats */
-               HW_STAT(RxOctetsTotalOK, RxOctetsOK),
-               HW_STAT(RxOctetsBad, RxOctetsBad),
-               HW_STAT(RxUCPkts, RxUnicastFramesOK),
-               HW_STAT(RxMCPkts, RxMulticastFramesOK),
-               HW_STAT(RxBCPkts, RxBroadcastFramesOK),
-               HW_STAT(RxJumboPkts, RxJumboFramesOK),
-               HW_STAT(RxFCSErrors, RxFCSErrors),
-               HW_STAT(RxAlignErrors, RxAlignErrors),
-               HW_STAT(RxLongErrors, RxFrameTooLongErrors),
-               HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors),
-               HW_STAT(RxPauseMacControlCounter, RxPauseFrames),
-               HW_STAT(RxDataErrors, RxDataErrors),
-               HW_STAT(RxJabberErrors, RxJabberErrors),
-               HW_STAT(RxRuntErrors, RxRuntErrors),
-               HW_STAT(RxShortErrors, RxRuntErrors),
-               HW_STAT(RxSequenceErrors, RxSequenceErrors),
-               HW_STAT(RxSymbolErrors, RxSymbolErrors),
-
-               /* Tx stats (skip collision stats as we are full-duplex only) */
-               HW_STAT(TxOctetsTotalOK, TxOctetsOK),
-               HW_STAT(TxOctetsBad, TxOctetsBad),
-               HW_STAT(TxUCPkts, TxUnicastFramesOK),
-               HW_STAT(TxMCPkts, TxMulticastFramesOK),
-               HW_STAT(TxBCPkts, TxBroadcastFramesOK),
-               HW_STAT(TxJumboPkts, TxJumboFramesOK),
-               HW_STAT(TxPauseFrames, TxPauseFrames),
-               HW_STAT(TxExcessiveLengthDrop, TxLengthErrors),
-               HW_STAT(TxUnderrun, TxUnderrun),
-               HW_STAT(TxCRCErrors, TxFCSErrors)
-       }, *p = hw_stats;
-       u64 *stats = (u64 *) &mac->stats;
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
-               u32 val;
-
-               t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val);
-               stats[p->offset] += val;
-       }
-}
-
-/* No-op interrupt operation as this MAC does not support interrupts */
-static int mac_intr_op(struct cmac *mac)
-{
-       return 0;
-}
-
-/* Expect MAC address to be in network byte order. */
-static int mac_set_address(struct cmac *mac, u8 addr[6])
-{
-       u32 addr_lo, addr_hi;
-
-       addr_lo = addr[2];
-       addr_lo = (addr_lo << 8) | addr[3];
-       addr_lo = (addr_lo << 8) | addr[4];
-       addr_lo = (addr_lo << 8) | addr[5];
-
-       addr_hi = addr[0];
-       addr_hi = (addr_hi << 8) | addr[1];
-
-       t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_LOW), addr_lo);
-       t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), addr_hi);
-       return 0;
-}
-
-static int mac_get_address(struct cmac *mac, u8 addr[6])
-{
-       u32 addr_lo, addr_hi;
-
-       t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_LOW), &addr_lo);
-       t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), &addr_hi);
-
-       addr[0] = (u8) (addr_hi >> 8);
-       addr[1] = (u8) addr_hi;
-       addr[2] = (u8) (addr_lo >> 24);
-       addr[3] = (u8) (addr_lo >> 16);
-       addr[4] = (u8) (addr_lo >> 8);
-       addr[5] = (u8) addr_lo;
-       return 0;
-}
-
-/* This is intended to reset a port, not the whole MAC */
-static int mac_reset(struct cmac *mac)
-{
-       return 0;
-}
-
-static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
-{
-       u32 val, new_mode;
-       adapter_t *adapter = mac->adapter;
-       u32 addr_lo, addr_hi;
-       u8 *addr;
-
-       t1_tpi_read(adapter, MACREG(mac, REG_RX_FILTER), &val);
-       new_mode = val & ~7;
-       if (!t1_rx_mode_promisc(rm) && mac->instance->version > 0)
-               new_mode |= 1;     /* only set if version > 0 due to erratum */
-       if (!t1_rx_mode_promisc(rm) && !t1_rx_mode_allmulti(rm)
-            && t1_rx_mode_mc_cnt(rm) <= 1)
-               new_mode |= 2;
-       if (new_mode != val)
-               t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), new_mode);
-       switch (t1_rx_mode_mc_cnt(rm)) {
-       case 0:
-               t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), 0);
-               t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), 0);
-               break;
-       case 1:
-               addr = t1_get_next_mcaddr(rm);
-               addr_lo = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |
-                       addr[5];
-               addr_hi = (addr[0] << 8) | addr[1];
-               t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), addr_lo);
-               t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), addr_hi);
-               break;
-       default:
-               break;
-       }
-       return 0;
-}
-
-static int mac_set_mtu(struct cmac *mac, int mtu)
-{
-       /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */
-       if (mtu > (MAX_FRAME_SIZE - 14 - 4))
-               return -EINVAL;
-       t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE),
-                    mtu + 14 + 4);
-       return 0;
-}
-
-static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
-                                  int fc)
-{
-       u32 val;
-
-       if (speed >= 0 && speed != SPEED_100 && speed != SPEED_1000)
-               return -1;
-       if (duplex >= 0 && duplex != DUPLEX_FULL)
-               return -1;
-
-       if (speed >= 0) {
-               val = speed == SPEED_100 ? 1 : 2;
-               t1_tpi_write(mac->adapter, MACREG(mac, REG_RGMII_SPEED), val);
-       }
-
-       t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val);
-       val &= ~3;
-       if (fc & PAUSE_RX)
-               val |= 1;
-       if (fc & PAUSE_TX)
-               val |= 2;
-       t1_tpi_write(mac->adapter, MACREG(mac, REG_FC_ENABLE), val);
-       return 0;
-}
-
-static int mac_get_speed_duplex_fc(struct cmac *mac, int *speed, int *duplex,
-                                  int *fc)
-{
-       u32 val;
-
-       if (duplex)
-               *duplex = DUPLEX_FULL;
-       if (speed) {
-               t1_tpi_read(mac->adapter, MACREG(mac, REG_RGMII_SPEED),
-                        &val);
-               *speed = (val & 2) ? SPEED_1000 : SPEED_100;
-       }
-       if (fc) {
-               t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val);
-               *fc = 0;
-               if (val & 1)
-                       *fc |= PAUSE_RX;
-               if (val & 2)
-                       *fc |= PAUSE_TX;
-       }
-       return 0;
-}
-
-static void enable_port(struct cmac *mac)
-{
-       u32 val;
-       u32 index = mac->instance->index;
-       adapter_t *adapter = mac->adapter;
-
-       t1_tpi_read(adapter, MACREG(mac, REG_DIVERSE_CONFIG), &val);
-       val |= DIVERSE_CONFIG_CRC_ADD | DIVERSE_CONFIG_PAD_ENABLE;
-       t1_tpi_write(adapter, MACREG(mac, REG_DIVERSE_CONFIG), val);
-       if (mac->instance->version > 0)
-               t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 3);
-       else /* Don't enable unicast address filtering due to IXF1010 bug */
-               t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 2);
-
-       t1_tpi_read(adapter, REG_RX_ERR_DROP, &val);
-       val |= (1 << index);
-       t1_tpi_write(adapter, REG_RX_ERR_DROP, val);
-
-       /*
-        * Clear the port RMON registers by adding their current values to the
-        * cumulatice port stats and then clearing the stats.  Really.
-        */
-       port_stats_update(mac);
-       memset(&mac->stats, 0, sizeof(struct cmac_statistics));
-       mac->instance->ticks = 0;
-
-       t1_tpi_read(adapter, REG_PORT_ENABLE, &val);
-       val |= (1 << index);
-       t1_tpi_write(adapter, REG_PORT_ENABLE, val);
-
-       index <<= 2;
-       if (is_T2(adapter)) {
-               /* T204: set the Fifo water level & threshold */
-               t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740);
-               t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730);
-               t1_tpi_write(adapter, TX_FIFO_HIGH_WATERMARK_BASE + index, 0x600);
-               t1_tpi_write(adapter, TX_FIFO_LOW_WATERMARK_BASE + index, 0x1d0);
-               t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x1100);
-       } else {
-       /*
-        * Set the TX Fifo Threshold to 0x400 instead of 0x100 to work around
-        * Underrun problem. Intel has blessed this solution.
-        */
-               t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x400);
-       }
-}
-
-/* IXF1010 ports do not have separate enables for TX and RX */
-static int mac_enable(struct cmac *mac, int which)
-{
-       if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX))
-               enable_port(mac);
-       return 0;
-}
-
-static int mac_disable(struct cmac *mac, int which)
-{
-       if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX))
-               disable_port(mac);
-       return 0;
-}
-
-#define RMON_UPDATE(mac, name, stat_name) \
-       t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
-       (mac)->stats.stat_name += val;
-
-/*
- * This function is called periodically to accumulate the current values of the
- * RMON counters into the port statistics.  Since the counters are only 32 bits
- * some of them can overflow in less than a minute at GigE speeds, so this
- * function should be called every 30 seconds or so.
- *
- * To cut down on reading costs we update only the octet counters at each tick
- * and do a full update at major ticks, which can be every 30 minutes or more.
- */
-static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
-                                                          int flag)
-{
-       if (flag == MAC_STATS_UPDATE_FULL ||
-           MAJOR_UPDATE_TICKS <= mac->instance->ticks) {
-               port_stats_update(mac);
-               mac->instance->ticks = 0;
-       } else {
-               u32 val;
-
-               RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
-               RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
-               mac->instance->ticks++;
-       }
-       return &mac->stats;
-}
-
-static void mac_destroy(struct cmac *mac)
-{
-       kfree(mac);
-}
-
-static struct cmac_ops ixf1010_ops = {
-       .destroy                  = mac_destroy,
-       .reset                    = mac_reset,
-       .interrupt_enable         = mac_intr_op,
-       .interrupt_disable        = mac_intr_op,
-       .interrupt_clear          = mac_intr_op,
-       .enable                   = mac_enable,
-       .disable                  = mac_disable,
-       .set_mtu                  = mac_set_mtu,
-       .set_rx_mode              = mac_set_rx_mode,
-       .set_speed_duplex_fc      = mac_set_speed_duplex_fc,
-       .get_speed_duplex_fc      = mac_get_speed_duplex_fc,
-       .statistics_update        = mac_update_statistics,
-       .macaddress_get           = mac_get_address,
-       .macaddress_set           = mac_set_address,
-};
-
-static int ixf1010_mac_reset(adapter_t *adapter)
-{
-       u32 val;
-
-       t1_tpi_read(adapter, A_ELMER0_GPO, &val);
-       if ((val & 1) != 0) {
-               val &= ~1;
-               t1_tpi_write(adapter, A_ELMER0_GPO, val);
-               udelay(2);
-       }
-       val |= 1;
-       t1_tpi_write(adapter, A_ELMER0_GPO, val);
-       udelay(2);
-
-       t1_tpi_write(adapter, REG_PORT_ENABLE, 0);
-       return 0;
-}
-
-static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index)
-{
-       struct cmac *mac;
-       u32 val;
-
-       if (index > 9)
-               return NULL;
-
-       mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
-       if (!mac)
-               return NULL;
-
-       mac->ops = &ixf1010_ops;
-       mac->instance = (cmac_instance *)(mac + 1);
-
-       mac->instance->mac_base = MACREG_BASE + (index * 0x200);
-       mac->instance->index    = index;
-       mac->adapter  = adapter;
-       mac->instance->ticks    = 0;
-
-       t1_tpi_read(adapter, REG_JTAG_ID, &val);
-       mac->instance->version = val >> 28;
-       return mac;
-}
-
-struct gmac t1_ixf1010_ops = {
-       STATS_TICK_SECS,
-       ixf1010_mac_create,
-       ixf1010_mac_reset
-};
index 6af39dc704596bdd684a45e999c13d4886c0dfdb..1d972825eac3dfca9f6c94968056ca08b1a3ce22 100644 (file)
@@ -363,6 +363,6 @@ static struct cmac *mac_create(adapter_t *adapter, int index)
        return mac;
 }
 
-struct gmac t1_chelsio_mac_ops = {
+const struct gmac t1_chelsio_mac_ops = {
        .create = mac_create
 };
index 5867e3b0a887fbf9496fb496ea11a494c8fb38cf..0632be0d6494310b1b11cd87cc202cb721491216 100644 (file)
@@ -354,7 +354,7 @@ static struct cphy_ops mv88e1xxx_ops = {
 };
 
 static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
-                                        struct mdio_ops *mdio_ops)
+                                        const struct mdio_ops *mdio_ops)
 {
        struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
 
@@ -390,7 +390,7 @@ static int mv88e1xxx_phy_reset(adapter_t* adapter)
        return 0;
 }
 
-struct gphy t1_mv88e1xxx_ops = {
-       mv88e1xxx_phy_create,
-       mv88e1xxx_phy_reset
+const struct gphy t1_mv88e1xxx_ops = {
+       .create = mv88e1xxx_phy_create,
+       .reset =  mv88e1xxx_phy_reset
 };
index c8e89480d90601415308f7bb6c1263440571e75b..cd856041af34dfe861c54be45e84ce630102d6c8 100644 (file)
@@ -208,7 +208,7 @@ static struct cphy_ops mv88x201x_ops = {
 };
 
 static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr,
-                                        struct mdio_ops *mdio_ops)
+                                        const struct mdio_ops *mdio_ops)
 {
        u32 val;
        struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
@@ -252,7 +252,7 @@ static int mv88x201x_phy_reset(adapter_t *adapter)
        return 0;
 }
 
-struct gphy t1_mv88x201x_ops = {
-       mv88x201x_phy_create,
-       mv88x201x_phy_reset
+const struct gphy t1_mv88x201x_ops = {
+       .create = mv88x201x_phy_create,
+       .reset = mv88x201x_phy_reset
 };
index 87dde3e600468a465bfb6bc7c5b73ae01c45d85a..040acd29995a2c5681f2816c620b43e64e0d17f0 100644 (file)
@@ -166,7 +166,7 @@ static struct cphy_ops my3126_ops = {
 };
 
 static struct cphy *my3126_phy_create(adapter_t *adapter,
-                       int phy_addr, struct mdio_ops *mdio_ops)
+                       int phy_addr, const struct mdio_ops *mdio_ops)
 {
        struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL);
 
@@ -201,7 +201,7 @@ static int my3126_phy_reset(adapter_t * adapter)
        return 0;
 }
 
-struct gphy t1_my3126_ops = {
-       my3126_phy_create,
-       my3126_phy_reset
+const struct gphy t1_my3126_ops = {
+       .create = my3126_phy_create,
+       .reset = my3126_phy_reset
 };
index 69129edeefd64ad266e35785f346ed5171303bd2..678778a8d1338ca55adb7c824d8153e40f1495cb 100644 (file)
@@ -807,8 +807,8 @@ static int pm3393_mac_reset(adapter_t * adapter)
        return successful_reset ? 0 : 1;
 }
 
-struct gmac t1_pm3393_ops = {
-       STATS_TICK_SECS,
-       pm3393_mac_create,
-       pm3393_mac_reset
+const struct gmac t1_pm3393_ops = {
+       .stats_update_period = STATS_TICK_SECS,
+       .create              = pm3393_mac_create,
+       .reset               = pm3393_mac_reset,
 };
index c2522cdfab3759fbc3638d9a690062e53b288c42..7de9a611e1f7dac5d4582f70a968119797d00198 100644 (file)
@@ -321,10 +321,10 @@ static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr,
 }
 
 #if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
-static struct mdio_ops mi1_mdio_ops = {
-       mi1_mdio_init,
-       mi1_mdio_read,
-       mi1_mdio_write
+static const struct mdio_ops mi1_mdio_ops = {
+       .init = mi1_mdio_init,
+       .read = mi1_mdio_read,
+       .write = mi1_mdio_write
 };
 #endif
 
@@ -377,10 +377,10 @@ static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr,
        return 0;
 }
 
-static struct mdio_ops mi1_mdio_ext_ops = {
-       mi1_mdio_init,
-       mi1_mdio_ext_read,
-       mi1_mdio_ext_write
+static const struct mdio_ops mi1_mdio_ext_ops = {
+       .init = mi1_mdio_init,
+       .read = mi1_mdio_ext_read,
+       .write = mi1_mdio_ext_write
 };
 
 enum {
@@ -392,63 +392,136 @@ enum {
        CH_BRD_N204_4CU,
 };
 
-static struct board_info t1_board[] = {
-
-{ CHBT_BOARD_CHT110, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T1,
-  CHBT_MAC_PM3393, CHBT_PHY_MY3126,
-  125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/,
-  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
-  1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
-  &t1_my3126_ops, &mi1_mdio_ext_ops,
-  "Chelsio T110 1x10GBase-CX4 TOE" },
-
-{ CHBT_BOARD_N110, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
-  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
-  125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
-  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
-  0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
-  &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
-  "Chelsio N110 1x10GBaseX NIC" },
-
-{ CHBT_BOARD_N210, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T2,
-  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
-  125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
-  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
-  0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
-  &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
-  "Chelsio N210 1x10GBaseX NIC" },
-
-{ CHBT_BOARD_CHT210, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
-  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
-  125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
-  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
-  0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
-  &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
-  "Chelsio T210 1x10GBaseX TOE" },
-
-{ CHBT_BOARD_CHT210, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
-  CHBT_MAC_PM3393, CHBT_PHY_MY3126,
-  125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
-  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
-  1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
-  &t1_my3126_ops, &mi1_mdio_ext_ops,
-  "Chelsio T210 1x10GBase-CX4 TOE" },
+static const struct board_info t1_board[] = {
+       {
+               .board          = CHBT_BOARD_CHT110,
+               .port_number    = 1,
+               .caps           = SUPPORTED_10000baseT_Full,
+               .chip_term      = CHBT_TERM_T1,
+               .chip_mac       = CHBT_MAC_PM3393,
+               .chip_phy       = CHBT_PHY_MY3126,
+               .clock_core     = 125000000,
+               .clock_mc3      = 150000000,
+               .clock_mc4      = 125000000,
+               .espi_nports    = 1,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 1,
+               .mdio_mdiinv    = 1,
+               .mdio_mdc       = 1,
+               .mdio_phybaseaddr = 1,
+               .gmac           = &t1_pm3393_ops,
+               .gphy           = &t1_my3126_ops,
+               .mdio_ops       = &mi1_mdio_ext_ops,
+               .desc           = "Chelsio T110 1x10GBase-CX4 TOE",
+       },
+
+       {
+               .board          = CHBT_BOARD_N110,
+               .port_number    = 1,
+               .caps           = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,
+               .chip_term      = CHBT_TERM_T1,
+               .chip_mac       = CHBT_MAC_PM3393,
+               .chip_phy       = CHBT_PHY_88X2010,
+               .clock_core     = 125000000,
+               .espi_nports    = 1,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 0,
+               .mdio_mdiinv    = 0,
+               .mdio_mdc       = 1,
+               .mdio_phybaseaddr = 0,
+               .gmac           = &t1_pm3393_ops,
+               .gphy           = &t1_mv88x201x_ops,
+               .mdio_ops       = &mi1_mdio_ext_ops,
+               .desc           = "Chelsio N110 1x10GBaseX NIC",
+       },
+
+       {
+               .board          = CHBT_BOARD_N210,
+               .port_number    = 1,
+               .caps           = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,
+               .chip_term      = CHBT_TERM_T2,
+               .chip_mac       = CHBT_MAC_PM3393,
+               .chip_phy       = CHBT_PHY_88X2010,
+               .clock_core     = 125000000,
+               .espi_nports    = 1,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 0,
+               .mdio_mdiinv    = 0,
+               .mdio_mdc       = 1,
+               .mdio_phybaseaddr = 0,
+               .gmac           = &t1_pm3393_ops,
+               .gphy           = &t1_mv88x201x_ops,
+               .mdio_ops       = &mi1_mdio_ext_ops,
+               .desc           = "Chelsio N210 1x10GBaseX NIC",
+       },
+
+       {
+               .board          = CHBT_BOARD_CHT210,
+               .port_number    = 1,
+               .caps           = SUPPORTED_10000baseT_Full,
+               .chip_term      = CHBT_TERM_T2,
+               .chip_mac       = CHBT_MAC_PM3393,
+               .chip_phy       = CHBT_PHY_88X2010,
+               .clock_core     = 125000000,
+               .clock_mc3      = 133000000,
+               .clock_mc4      = 125000000,
+               .espi_nports    = 1,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 0,
+               .mdio_mdiinv    = 0,
+               .mdio_mdc       = 1,
+               .mdio_phybaseaddr = 0,
+               .gmac           = &t1_pm3393_ops,
+               .gphy           = &t1_mv88x201x_ops,
+               .mdio_ops       = &mi1_mdio_ext_ops,
+               .desc           = "Chelsio T210 1x10GBaseX TOE",
+       },
+
+       {
+               .board          = CHBT_BOARD_CHT210,
+               .port_number    = 1,
+               .caps           = SUPPORTED_10000baseT_Full,
+               .chip_term      = CHBT_TERM_T2,
+               .chip_mac       = CHBT_MAC_PM3393,
+               .chip_phy       = CHBT_PHY_MY3126,
+               .clock_core     = 125000000,
+               .clock_mc3      = 133000000,
+               .clock_mc4      = 125000000,
+               .espi_nports    = 1,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 1,
+               .mdio_mdiinv    = 1,
+               .mdio_mdc       = 1,
+               .mdio_phybaseaddr = 1,
+               .gmac           = &t1_pm3393_ops,
+               .gphy           = &t1_my3126_ops,
+               .mdio_ops       = &mi1_mdio_ext_ops,
+               .desc           = "Chelsio T210 1x10GBase-CX4 TOE",
+       },
 
 #ifdef CONFIG_CHELSIO_T1_1G
-{ CHBT_BOARD_CHN204, 4/*ports#*/,
-  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half |
-  SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
-  SUPPORTED_PAUSE | SUPPORTED_TP /*caps*/, CHBT_TERM_T2, CHBT_MAC_VSC7321, CHBT_PHY_88E1111,
-  100000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
-  4/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
-  0/*mdiinv*/, 1/*mdc*/, 4/*phybaseaddr*/, &t1_vsc7326_ops,
-  &t1_mv88e1xxx_ops, &mi1_mdio_ops,
-  "Chelsio N204 4x100/1000BaseT NIC" },
+       {
+               .board          = CHBT_BOARD_CHN204,
+               .port_number    = 4,
+               .caps           = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
+                               | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
+                               | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+                                 SUPPORTED_PAUSE | SUPPORTED_TP,
+               .chip_term      = CHBT_TERM_T2,
+               .chip_mac       = CHBT_MAC_VSC7321,
+               .chip_phy       = CHBT_PHY_88E1111,
+               .clock_core     = 100000000,
+               .espi_nports    = 4,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 0,
+               .mdio_mdiinv    = 0,
+               .mdio_mdc       = 0,
+               .mdio_phybaseaddr = 4,
+               .gmac           = &t1_vsc7326_ops,
+               .gphy           = &t1_mv88e1xxx_ops,
+               .mdio_ops       = &mi1_mdio_ops,
+               .desc           = "Chelsio N204 4x100/1000BaseT NIC",
+       },
 #endif
 
 };
index 534ffa0f616ec944ac3596dcbf3987a37b804ac8..99b51f61fe77af62904615cf73feef6a169e2ceb 100644 (file)
@@ -723,7 +723,7 @@ static int vsc7326_mac_reset(adapter_t *adapter)
        return 0;
 }
 
-struct gmac t1_vsc7326_ops = {
+const struct gmac t1_vsc7326_ops = {
        .stats_update_period = STATS_TICK_SECS,
        .create              = vsc7326_mac_create,
        .reset               = vsc7326_mac_reset,
diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c
deleted file mode 100644 (file)
index 251d485..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * This file is part of the Chelsio T2 Ethernet driver.
- *
- * Copyright (C) 2005 Chelsio Communications.  All rights reserved.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the LICENSE file included in this
- * release for licensing terms and conditions.
- */
-
-#include "common.h"
-#include "cphy.h"
-#include "elmer0.h"
-
-#ifndef ADVERTISE_PAUSE_CAP
-# define ADVERTISE_PAUSE_CAP 0x400
-#endif
-#ifndef ADVERTISE_PAUSE_ASYM
-# define ADVERTISE_PAUSE_ASYM 0x800
-#endif
-
-/* Gigabit MII registers */
-#ifndef MII_CTRL1000
-# define MII_CTRL1000 9
-#endif
-
-#ifndef ADVERTISE_1000FULL
-# define ADVERTISE_1000FULL 0x200
-# define ADVERTISE_1000HALF 0x100
-#endif
-
-/* VSC8244 PHY specific registers. */
-enum {
-       VSC8244_INTR_ENABLE   = 25,
-       VSC8244_INTR_STATUS   = 26,
-       VSC8244_AUX_CTRL_STAT = 28,
-};
-
-enum {
-       VSC_INTR_RX_ERR     = 1 << 0,
-       VSC_INTR_MS_ERR     = 1 << 1,  /* master/slave resolution error */
-       VSC_INTR_CABLE      = 1 << 2,  /* cable impairment */
-       VSC_INTR_FALSE_CARR = 1 << 3,  /* false carrier */
-       VSC_INTR_MEDIA_CHG  = 1 << 4,  /* AMS media change */
-       VSC_INTR_RX_FIFO    = 1 << 5,  /* Rx FIFO over/underflow */
-       VSC_INTR_TX_FIFO    = 1 << 6,  /* Tx FIFO over/underflow */
-       VSC_INTR_DESCRAMBL  = 1 << 7,  /* descrambler lock-lost */
-       VSC_INTR_SYMBOL_ERR = 1 << 8,  /* symbol error */
-       VSC_INTR_NEG_DONE   = 1 << 10, /* autoneg done */
-       VSC_INTR_NEG_ERR    = 1 << 11, /* autoneg error */
-       VSC_INTR_LINK_CHG   = 1 << 13, /* link change */
-       VSC_INTR_ENABLE     = 1 << 15, /* interrupt enable */
-};
-
-#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
-                          VSC_INTR_NEG_DONE)
-#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
-                  VSC_INTR_ENABLE)
-
-/* PHY specific auxiliary control & status register fields */
-#define S_ACSR_ACTIPHY_TMR    0
-#define M_ACSR_ACTIPHY_TMR    0x3
-#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
-
-#define S_ACSR_SPEED    3
-#define M_ACSR_SPEED    0x3
-#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
-
-#define S_ACSR_DUPLEX 5
-#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
-
-#define S_ACSR_ACTIPHY 6
-#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
-
-/*
- * Reset the PHY.  This PHY completes reset immediately so we never wait.
- */
-static int vsc8244_reset(struct cphy *cphy, int wait)
-{
-       int err;
-       unsigned int ctl;
-
-       err = simple_mdio_read(cphy, MII_BMCR, &ctl);
-       if (err)
-               return err;
-
-       ctl &= ~BMCR_PDOWN;
-       ctl |= BMCR_RESET;
-       return simple_mdio_write(cphy, MII_BMCR, ctl);
-}
-
-static int vsc8244_intr_enable(struct cphy *cphy)
-{
-       simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK);
-
-       /* Enable interrupts through Elmer */
-       if (t1_is_asic(cphy->adapter)) {
-               u32 elmer;
-
-               t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
-               elmer |= ELMER0_GP_BIT1;
-               if (is_T2(cphy->adapter))
-                   elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-               t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
-       }
-
-       return 0;
-}
-
-static int vsc8244_intr_disable(struct cphy *cphy)
-{
-       simple_mdio_write(cphy, VSC8244_INTR_ENABLE, 0);
-
-       if (t1_is_asic(cphy->adapter)) {
-               u32 elmer;
-
-               t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
-               elmer &= ~ELMER0_GP_BIT1;
-               if (is_T2(cphy->adapter))
-                   elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
-               t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
-       }
-
-       return 0;
-}
-
-static int vsc8244_intr_clear(struct cphy *cphy)
-{
-       u32 val;
-       u32 elmer;
-
-       /* Clear PHY interrupts by reading the register. */
-       simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val);
-
-       if (t1_is_asic(cphy->adapter)) {
-               t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
-               elmer |= ELMER0_GP_BIT1;
-               if (is_T2(cphy->adapter))
-                   elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-               t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
-       }
-
-       return 0;
-}
-
-/*
- * Force the PHY speed and duplex.  This also disables auto-negotiation, except
- * for 1Gb/s, where auto-negotiation is mandatory.
- */
-static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex)
-{
-       int err;
-       unsigned int ctl;
-
-       err = simple_mdio_read(phy, MII_BMCR, &ctl);
-       if (err)
-               return err;
-
-       if (speed >= 0) {
-               ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
-               if (speed == SPEED_100)
-                       ctl |= BMCR_SPEED100;
-               else if (speed == SPEED_1000)
-                       ctl |= BMCR_SPEED1000;
-       }
-       if (duplex >= 0) {
-               ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
-               if (duplex == DUPLEX_FULL)
-                       ctl |= BMCR_FULLDPLX;
-       }
-       if (ctl & BMCR_SPEED1000)  /* auto-negotiation required for 1Gb/s */
-               ctl |= BMCR_ANENABLE;
-       return simple_mdio_write(phy, MII_BMCR, ctl);
-}
-
-int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits)
-{
-       int ret;
-       unsigned int val;
-
-       ret = mdio_read(phy, mmd, reg, &val);
-       if (!ret)
-               ret = mdio_write(phy, mmd, reg, val | bits);
-       return ret;
-}
-
-static int vsc8244_autoneg_enable(struct cphy *cphy)
-{
-       return t1_mdio_set_bits(cphy, 0, MII_BMCR,
-                               BMCR_ANENABLE | BMCR_ANRESTART);
-}
-
-static int vsc8244_autoneg_restart(struct cphy *cphy)
-{
-       return t1_mdio_set_bits(cphy, 0, MII_BMCR, BMCR_ANRESTART);
-}
-
-static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map)
-{
-       int err;
-       unsigned int val = 0;
-
-       err = simple_mdio_read(phy, MII_CTRL1000, &val);
-       if (err)
-               return err;
-
-       val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
-       if (advertise_map & ADVERTISED_1000baseT_Half)
-               val |= ADVERTISE_1000HALF;
-       if (advertise_map & ADVERTISED_1000baseT_Full)
-               val |= ADVERTISE_1000FULL;
-
-       err = simple_mdio_write(phy, MII_CTRL1000, val);
-       if (err)
-               return err;
-
-       val = 1;
-       if (advertise_map & ADVERTISED_10baseT_Half)
-               val |= ADVERTISE_10HALF;
-       if (advertise_map & ADVERTISED_10baseT_Full)
-               val |= ADVERTISE_10FULL;
-       if (advertise_map & ADVERTISED_100baseT_Half)
-               val |= ADVERTISE_100HALF;
-       if (advertise_map & ADVERTISED_100baseT_Full)
-               val |= ADVERTISE_100FULL;
-       if (advertise_map & ADVERTISED_PAUSE)
-               val |= ADVERTISE_PAUSE_CAP;
-       if (advertise_map & ADVERTISED_ASYM_PAUSE)
-               val |= ADVERTISE_PAUSE_ASYM;
-       return simple_mdio_write(phy, MII_ADVERTISE, val);
-}
-
-static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok,
-                                  int *speed, int *duplex, int *fc)
-{
-       unsigned int bmcr, status, lpa, adv;
-       int err, sp = -1, dplx = -1, pause = 0;
-
-       err = simple_mdio_read(cphy, MII_BMCR, &bmcr);
-       if (!err)
-               err = simple_mdio_read(cphy, MII_BMSR, &status);
-       if (err)
-               return err;
-
-       if (link_ok) {
-               /*
-                * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
-                * once more to get the current link state.
-                */
-               if (!(status & BMSR_LSTATUS))
-                       err = simple_mdio_read(cphy, MII_BMSR, &status);
-               if (err)
-                       return err;
-               *link_ok = (status & BMSR_LSTATUS) != 0;
-       }
-       if (!(bmcr & BMCR_ANENABLE)) {
-               dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
-               if (bmcr & BMCR_SPEED1000)
-                       sp = SPEED_1000;
-               else if (bmcr & BMCR_SPEED100)
-                       sp = SPEED_100;
-               else
-                       sp = SPEED_10;
-       } else if (status & BMSR_ANEGCOMPLETE) {
-               err = simple_mdio_read(cphy, VSC8244_AUX_CTRL_STAT, &status);
-               if (err)
-                       return err;
-
-               dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
-               sp = G_ACSR_SPEED(status);
-               if (sp == 0)
-                       sp = SPEED_10;
-               else if (sp == 1)
-                       sp = SPEED_100;
-               else
-                       sp = SPEED_1000;
-
-               if (fc && dplx == DUPLEX_FULL) {
-                       err = simple_mdio_read(cphy, MII_LPA, &lpa);
-                       if (!err)
-                               err = simple_mdio_read(cphy, MII_ADVERTISE,
-                                                      &adv);
-                       if (err)
-                               return err;
-
-                       if (lpa & adv & ADVERTISE_PAUSE_CAP)
-                               pause = PAUSE_RX | PAUSE_TX;
-                       else if ((lpa & ADVERTISE_PAUSE_CAP) &&
-                                (lpa & ADVERTISE_PAUSE_ASYM) &&
-                                (adv & ADVERTISE_PAUSE_ASYM))
-                               pause = PAUSE_TX;
-                       else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
-                                (adv & ADVERTISE_PAUSE_CAP))
-                               pause = PAUSE_RX;
-               }
-       }
-       if (speed)
-               *speed = sp;
-       if (duplex)
-               *duplex = dplx;
-       if (fc)
-               *fc = pause;
-       return 0;
-}
-
-static int vsc8244_intr_handler(struct cphy *cphy)
-{
-       unsigned int cause;
-       int err, cphy_cause = 0;
-
-       err = simple_mdio_read(cphy, VSC8244_INTR_STATUS, &cause);
-       if (err)
-               return err;
-
-       cause &= INTR_MASK;
-       if (cause & CFG_CHG_INTR_MASK)
-               cphy_cause |= cphy_cause_link_change;
-       if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
-               cphy_cause |= cphy_cause_fifo_error;
-       return cphy_cause;
-}
-
-static void vsc8244_destroy(struct cphy *cphy)
-{
-       kfree(cphy);
-}
-
-static struct cphy_ops vsc8244_ops = {
-       .destroy              = vsc8244_destroy,
-       .reset                = vsc8244_reset,
-       .interrupt_enable     = vsc8244_intr_enable,
-       .interrupt_disable    = vsc8244_intr_disable,
-       .interrupt_clear      = vsc8244_intr_clear,
-       .interrupt_handler    = vsc8244_intr_handler,
-       .autoneg_enable       = vsc8244_autoneg_enable,
-       .autoneg_restart      = vsc8244_autoneg_restart,
-       .advertise            = vsc8244_advertise,
-       .set_speed_duplex     = vsc8244_set_speed_duplex,
-       .get_link_status      = vsc8244_get_link_status
-};
-
-static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr,
-                                      struct mdio_ops *mdio_ops)
-{
-       struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
-
-       if (!cphy)
-               return NULL;
-
-       cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops);
-
-       return cphy;
-}
-
-
-static int vsc8244_phy_reset(adapter_t* adapter)
-{
-       return 0;
-}
-
-struct gphy t1_vsc8244_ops = {
-       vsc8244_phy_create,
-       vsc8244_phy_reset
-};
-
-
diff --git a/drivers/net/chelsio/vsc8244_reg.h b/drivers/net/chelsio/vsc8244_reg.h
deleted file mode 100644 (file)
index d3c1829..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/* $Date: 2005/11/23 16:28:53 $ $RCSfile: vsc8244_reg.h,v $ $Revision: 1.1 $ */
-#ifndef CHELSIO_MV8E1XXX_H
-#define CHELSIO_MV8E1XXX_H
-
-#ifndef BMCR_SPEED1000
-# define BMCR_SPEED1000 0x40
-#endif
-
-#ifndef ADVERTISE_PAUSE
-# define ADVERTISE_PAUSE 0x400
-#endif
-#ifndef ADVERTISE_PAUSE_ASYM
-# define ADVERTISE_PAUSE_ASYM 0x800
-#endif
-
-/* Gigabit MII registers */
-#define MII_GBMR 1       /* 1000Base-T mode register */
-#define MII_GBCR 9       /* 1000Base-T control register */
-#define MII_GBSR 10      /* 1000Base-T status register */
-
-/* 1000Base-T control register fields */
-#define GBCR_ADV_1000HALF         0x100
-#define GBCR_ADV_1000FULL         0x200
-#define GBCR_PREFER_MASTER        0x400
-#define GBCR_MANUAL_AS_MASTER     0x800
-#define GBCR_MANUAL_CONFIG_ENABLE 0x1000
-
-/* 1000Base-T status register fields */
-#define GBSR_LP_1000HALF  0x400
-#define GBSR_LP_1000FULL  0x800
-#define GBSR_REMOTE_OK    0x1000
-#define GBSR_LOCAL_OK     0x2000
-#define GBSR_LOCAL_MASTER 0x4000
-#define GBSR_MASTER_FAULT 0x8000
-
-/* Vitesse PHY interrupt status bits. */
-#if 0
-#define VSC8244_INTR_JABBER          0x0001
-#define VSC8244_INTR_POLARITY_CHNG   0x0002
-#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010
-#define VSC8244_INTR_DOWNSHIFT       0x0020
-#define VSC8244_INTR_MDI_XOVER_CHNG  0x0040
-#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080
-#define VSC8244_INTR_FALSE_CARRIER   0x0100
-#define VSC8244_INTR_SYMBOL_ERROR    0x0200
-#define VSC8244_INTR_LINK_CHNG       0x0400
-#define VSC8244_INTR_AUTONEG_DONE    0x0800
-#define VSC8244_INTR_PAGE_RECV       0x1000
-#define VSC8244_INTR_DUPLEX_CHNG     0x2000
-#define VSC8244_INTR_SPEED_CHNG      0x4000
-#define VSC8244_INTR_AUTONEG_ERR     0x8000
-#else
-//#define VSC8244_INTR_JABBER          0x0001
-//#define VSC8244_INTR_POLARITY_CHNG   0x0002
-//#define VSC8244_INTR_BIT2            0x0004
-//#define VSC8244_INTR_BIT3            0x0008
-#define VSC8244_INTR_RX_ERR          0x0001
-#define VSC8244_INTR_MASTER_SLAVE    0x0002
-#define VSC8244_INTR_CABLE_IMPAIRED  0x0004
-#define VSC8244_INTR_FALSE_CARRIER   0x0008
-//#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010
-//#define VSC8244_INTR_DOWNSHIFT       0x0020
-//#define VSC8244_INTR_MDI_XOVER_CHNG  0x0040
-//#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080
-#define VSC8244_INTR_BIT4            0x0010
-#define VSC8244_INTR_FIFO_RX         0x0020
-#define VSC8244_INTR_FIFO_OVER_UNDER 0x0040
-#define VSC8244_INTR_LOCK_LOST       0x0080
-//#define VSC8244_INTR_FALSE_CARRIER   0x0100
-//#define VSC8244_INTR_SYMBOL_ERROR    0x0200
-//#define VSC8244_INTR_LINK_CHNG       0x0400
-//#define VSC8244_INTR_AUTONEG_DONE    0x0800
-#define VSC8244_INTR_SYMBOL_ERROR    0x0100
-#define VSC8244_INTR_ENG_DETECT_CHNG 0x0200
-#define VSC8244_INTR_AUTONEG_DONE    0x0400
-#define VSC8244_INTR_AUTONEG_ERR     0x0800
-//#define VSC8244_INTR_PAGE_RECV       0x1000
-//#define VSC8244_INTR_DUPLEX_CHNG     0x2000
-//#define VSC8244_INTR_SPEED_CHNG      0x4000
-//#define VSC8244_INTR_AUTONEG_ERR     0x8000
-#define VSC8244_INTR_DUPLEX_CHNG     0x1000
-#define VSC8244_INTR_LINK_CHNG       0x2000
-#define VSC8244_INTR_SPEED_CHNG      0x4000
-#define VSC8244_INTR_STATUS          0x8000
-#endif
-
-
-/* Vitesse PHY specific registers. */
-#define VSC8244_SPECIFIC_CNTRL_REGISTER               16
-#define VSC8244_SPECIFIC_STATUS_REGISTER              0x1c
-#define VSC8244_INTERRUPT_ENABLE_REGISTER             0x19
-#define VSC8244_INTERRUPT_STATUS_REGISTER             0x1a
-#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_REGISTER       20
-#define VSC8244_RECV_ERR_CNTR_REGISTER                21
-#define VSC8244_RES_REGISTER                          22
-#define VSC8244_GLOBAL_STATUS_REGISTER                23
-#define VSC8244_LED_CONTROL_REGISTER                  24
-#define VSC8244_MANUAL_LED_OVERRIDE_REGISTER          25
-#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_2_REGISTER     26
-#define VSC8244_EXT_PHY_SPECIFIC_STATUS_REGISTER      27
-#define VSC8244_VIRTUAL_CABLE_TESTER_REGISTER         28
-#define VSC8244_EXTENDED_ADDR_REGISTER                29
-#define VSC8244_EXTENDED_REGISTER                     30
-
-/* PHY specific control register fields */
-#define S_PSCR_MDI_XOVER_MODE    5
-#define M_PSCR_MDI_XOVER_MODE    0x3
-#define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE)
-#define G_PSCR_MDI_XOVER_MODE(x) (((x) >> S_PSCR_MDI_XOVER_MODE) & M_PSCR_MDI_XOVER_MODE)
-
-/* Extended PHY specific control register fields */
-#define S_DOWNSHIFT_ENABLE 8
-#define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE)
-
-#define S_DOWNSHIFT_CNT    9
-#define M_DOWNSHIFT_CNT    0x7
-#define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT)
-#define G_DOWNSHIFT_CNT(x) (((x) >> S_DOWNSHIFT_CNT) & M_DOWNSHIFT_CNT)
-
-/* PHY specific status register fields */
-#define S_PSSR_JABBER 0
-#define V_PSSR_JABBER (1 << S_PSSR_JABBER)
-
-#define S_PSSR_POLARITY 1
-#define V_PSSR_POLARITY (1 << S_PSSR_POLARITY)
-
-#define S_PSSR_RX_PAUSE 2
-#define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE)
-
-#define S_PSSR_TX_PAUSE 3
-#define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE)
-
-#define S_PSSR_ENERGY_DETECT 4
-#define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT)
-
-#define S_PSSR_DOWNSHIFT_STATUS 5
-#define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS)
-
-#define S_PSSR_MDI 6
-#define V_PSSR_MDI (1 << S_PSSR_MDI)
-
-#define S_PSSR_CABLE_LEN    7
-#define M_PSSR_CABLE_LEN    0x7
-#define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN)
-#define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN)
-
-//#define S_PSSR_LINK 10
-//#define S_PSSR_LINK 13
-#define S_PSSR_LINK 2
-#define V_PSSR_LINK (1 << S_PSSR_LINK)
-
-//#define S_PSSR_STATUS_RESOLVED 11
-//#define S_PSSR_STATUS_RESOLVED 10
-#define S_PSSR_STATUS_RESOLVED 15
-#define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED)
-
-#define S_PSSR_PAGE_RECEIVED 12
-#define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED)
-
-//#define S_PSSR_DUPLEX 13
-//#define S_PSSR_DUPLEX 12
-#define S_PSSR_DUPLEX 5
-#define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX)
-
-//#define S_PSSR_SPEED    14
-//#define S_PSSR_SPEED    14
-#define S_PSSR_SPEED    3
-#define M_PSSR_SPEED    0x3
-#define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED)
-#define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED)
-
-#endif
index 4d0e0aea72bfebdb99c139a572043b4192baaf97..61696637a21edcc0b646e1c8894c3b89f632dadd 100644 (file)
 
 #define DRV_NAME               "e100"
 #define DRV_EXT                        "-NAPI"
-#define DRV_VERSION            "3.5.17-k2"DRV_EXT
+#define DRV_VERSION            "3.5.17-k4"DRV_EXT
 #define DRV_DESCRIPTION                "Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT          "Copyright(c) 1999-2006 Intel Corporation"
 #define PFX                    DRV_NAME ": "
@@ -174,10 +174,13 @@ MODULE_VERSION(DRV_VERSION);
 
 static int debug = 3;
 static int eeprom_bad_csum_allow = 0;
+static int use_io = 0;
 module_param(debug, int, 0);
 module_param(eeprom_bad_csum_allow, int, 0);
+module_param(use_io, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
+MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
 #define DPRINTK(nlevel, klevel, fmt, args...) \
        (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
        printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
@@ -282,12 +285,6 @@ enum scb_status {
        rus_mask         = 0x3C,
 };
 
-enum ru_state  {
-       RU_SUSPENDED = 0,
-       RU_RUNNING       = 1,
-       RU_UNINITIALIZED = -1,
-};
-
 enum scb_stat_ack {
        stat_ack_not_ours    = 0x00,
        stat_ack_sw_gen      = 0x04,
@@ -529,7 +526,6 @@ struct nic {
        struct rx *rx_to_use;
        struct rx *rx_to_clean;
        struct rfd blank_rfd;
-       enum ru_state ru_running;
 
        spinlock_t cb_lock                      ____cacheline_aligned;
        spinlock_t cmd_lock;
@@ -591,7 +587,7 @@ static inline void e100_write_flush(struct nic *nic)
 {
        /* Flush previous PCI writes through intermediate bridges
         * by doing a benign read */
-       (void)readb(&nic->csr->scb.status);
+       (void)ioread8(&nic->csr->scb.status);
 }
 
 static void e100_enable_irq(struct nic *nic)
@@ -599,7 +595,7 @@ static void e100_enable_irq(struct nic *nic)
        unsigned long flags;
 
        spin_lock_irqsave(&nic->cmd_lock, flags);
-       writeb(irq_mask_none, &nic->csr->scb.cmd_hi);
+       iowrite8(irq_mask_none, &nic->csr->scb.cmd_hi);
        e100_write_flush(nic);
        spin_unlock_irqrestore(&nic->cmd_lock, flags);
 }
@@ -609,7 +605,7 @@ static void e100_disable_irq(struct nic *nic)
        unsigned long flags;
 
        spin_lock_irqsave(&nic->cmd_lock, flags);
-       writeb(irq_mask_all, &nic->csr->scb.cmd_hi);
+       iowrite8(irq_mask_all, &nic->csr->scb.cmd_hi);
        e100_write_flush(nic);
        spin_unlock_irqrestore(&nic->cmd_lock, flags);
 }
@@ -618,11 +614,11 @@ static void e100_hw_reset(struct nic *nic)
 {
        /* Put CU and RU into idle with a selective reset to get
         * device off of PCI bus */
-       writel(selective_reset, &nic->csr->port);
+       iowrite32(selective_reset, &nic->csr->port);
        e100_write_flush(nic); udelay(20);
 
        /* Now fully reset device */
-       writel(software_reset, &nic->csr->port);
+       iowrite32(software_reset, &nic->csr->port);
        e100_write_flush(nic); udelay(20);
 
        /* Mask off our interrupt line - it's unmasked after reset */
@@ -639,7 +635,7 @@ static int e100_self_test(struct nic *nic)
        nic->mem->selftest.signature = 0;
        nic->mem->selftest.result = 0xFFFFFFFF;
 
-       writel(selftest | dma_addr, &nic->csr->port);
+       iowrite32(selftest | dma_addr, &nic->csr->port);
        e100_write_flush(nic);
        /* Wait 10 msec for self-test to complete */
        msleep(10);
@@ -677,23 +673,23 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data)
        for(j = 0; j < 3; j++) {
 
                /* Chip select */
-               writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+               iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
                e100_write_flush(nic); udelay(4);
 
                for(i = 31; i >= 0; i--) {
                        ctrl = (cmd_addr_data[j] & (1 << i)) ?
                                eecs | eedi : eecs;
-                       writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+                       iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
                        e100_write_flush(nic); udelay(4);
 
-                       writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+                       iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
                        e100_write_flush(nic); udelay(4);
                }
                /* Wait 10 msec for cmd to complete */
                msleep(10);
 
                /* Chip deselect */
-               writeb(0, &nic->csr->eeprom_ctrl_lo);
+               iowrite8(0, &nic->csr->eeprom_ctrl_lo);
                e100_write_flush(nic); udelay(4);
        }
 };
@@ -709,21 +705,21 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
        cmd_addr_data = ((op_read << *addr_len) | addr) << 16;
 
        /* Chip select */
-       writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+       iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
        e100_write_flush(nic); udelay(4);
 
        /* Bit-bang to read word from eeprom */
        for(i = 31; i >= 0; i--) {
                ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
-               writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+               iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
                e100_write_flush(nic); udelay(4);
 
-               writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+               iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
                e100_write_flush(nic); udelay(4);
 
                /* Eeprom drives a dummy zero to EEDO after receiving
                 * complete address.  Use this to adjust addr_len. */
-               ctrl = readb(&nic->csr->eeprom_ctrl_lo);
+               ctrl = ioread8(&nic->csr->eeprom_ctrl_lo);
                if(!(ctrl & eedo) && i > 16) {
                        *addr_len -= (i - 16);
                        i = 17;
@@ -733,7 +729,7 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
        }
 
        /* Chip deselect */
-       writeb(0, &nic->csr->eeprom_ctrl_lo);
+       iowrite8(0, &nic->csr->eeprom_ctrl_lo);
        e100_write_flush(nic); udelay(4);
 
        return le16_to_cpu(data);
@@ -804,7 +800,7 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
 
        /* Previous command is accepted when SCB clears */
        for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) {
-               if(likely(!readb(&nic->csr->scb.cmd_lo)))
+               if(likely(!ioread8(&nic->csr->scb.cmd_lo)))
                        break;
                cpu_relax();
                if(unlikely(i > E100_WAIT_SCB_FAST))
@@ -816,8 +812,8 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
        }
 
        if(unlikely(cmd != cuc_resume))
-               writel(dma_addr, &nic->csr->scb.gen_ptr);
-       writeb(cmd, &nic->csr->scb.cmd_lo);
+               iowrite32(dma_addr, &nic->csr->scb.gen_ptr);
+       iowrite8(cmd, &nic->csr->scb.cmd_lo);
 
 err_unlock:
        spin_unlock_irqrestore(&nic->cmd_lock, flags);
@@ -895,7 +891,7 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
         */
        spin_lock_irqsave(&nic->mdio_lock, flags);
        for (i = 100; i; --i) {
-               if (readl(&nic->csr->mdi_ctrl) & mdi_ready)
+               if (ioread32(&nic->csr->mdi_ctrl) & mdi_ready)
                        break;
                udelay(20);
        }
@@ -905,11 +901,11 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
                spin_unlock_irqrestore(&nic->mdio_lock, flags);
                return 0;               /* No way to indicate timeout error */
        }
-       writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
+       iowrite32((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
 
        for (i = 0; i < 100; i++) {
                udelay(20);
-               if ((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready)
+               if ((data_out = ioread32(&nic->csr->mdi_ctrl)) & mdi_ready)
                        break;
        }
        spin_unlock_irqrestore(&nic->mdio_lock, flags);
@@ -951,7 +947,7 @@ static void e100_get_defaults(struct nic *nic)
                ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
 
        /* Template for a freshly allocated RFD */
-       nic->blank_rfd.command = cpu_to_le16(cb_el);
+       nic->blank_rfd.command = cpu_to_le16(cb_el & cb_s);
        nic->blank_rfd.rbd = 0xFFFFFFFF;
        nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
 
@@ -1318,7 +1314,7 @@ static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb,
        }
 
        /* ack any interupts, something could have been set */
-       writeb(~0, &nic->csr->scb.stat_ack);
+       iowrite8(~0, &nic->csr->scb.stat_ack);
 
        /* if the command failed, or is not OK, notify and return */
        if (!counter || !(cb->status & cpu_to_le16(cb_ok))) {
@@ -1580,7 +1576,7 @@ static void e100_watchdog(unsigned long data)
         * accidentally, due to hardware that shares a register between the
         * interrupt mask bit and the SW Interrupt generation bit */
        spin_lock_irq(&nic->cmd_lock);
-       writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
+       iowrite8(ioread8(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
        e100_write_flush(nic);
        spin_unlock_irq(&nic->cmd_lock);
 
@@ -1746,19 +1742,11 @@ static int e100_alloc_cbs(struct nic *nic)
        return 0;
 }
 
-static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
+static inline void e100_start_receiver(struct nic *nic)
 {
-       if(!nic->rxs) return;
-       if(RU_SUSPENDED != nic->ru_running) return;
-
-       /* handle init time starts */
-       if(!rx) rx = nic->rxs;
-
-       /* (Re)start RU if suspended or idle and RFA is non-NULL */
-       if(rx->skb) {
-               e100_exec_cmd(nic, ruc_start, rx->dma_addr);
-               nic->ru_running = RU_RUNNING;
-       }
+       /* Start if RFA is non-NULL */
+       if(nic->rx_to_clean->skb)
+               e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
 }
 
 #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
@@ -1787,7 +1775,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
                put_unaligned(cpu_to_le32(rx->dma_addr),
                        (u32 *)&prev_rfd->link);
                wmb();
-               prev_rfd->command &= ~cpu_to_le16(cb_el);
+               prev_rfd->command &= ~cpu_to_le16(cb_el & cb_s);
                pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
                        sizeof(struct rfd), PCI_DMA_TODEVICE);
        }
@@ -1825,10 +1813,6 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
        pci_unmap_single(nic->pdev, rx->dma_addr,
                RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
 
-       /* this allows for a fast restart without re-enabling interrupts */
-       if(le16_to_cpu(rfd->command) & cb_el)
-               nic->ru_running = RU_SUSPENDED;
-
        /* Pull off the RFD and put the actual data (minus eth hdr) */
        skb_reserve(skb, sizeof(struct rfd));
        skb_put(skb, actual_size);
@@ -1859,45 +1843,18 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
        unsigned int work_to_do)
 {
        struct rx *rx;
-       int restart_required = 0;
-       struct rx *rx_to_start = NULL;
-
-       /* are we already rnr? then pay attention!!! this ensures that
-        * the state machine progression never allows a start with a
-        * partially cleaned list, avoiding a race between hardware
-        * and rx_to_clean when in NAPI mode */
-       if(RU_SUSPENDED == nic->ru_running)
-               restart_required = 1;
 
        /* Indicate newly arrived packets */
        for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
-               int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
-               if(-EAGAIN == err) {
-                       /* hit quota so have more work to do, restart once
-                        * cleanup is complete */
-                       restart_required = 0;
-                       break;
-               } else if(-ENODATA == err)
+               if(e100_rx_indicate(nic, rx, work_done, work_to_do))
                        break; /* No more to clean */
        }
 
-       /* save our starting point as the place we'll restart the receiver */
-       if(restart_required)
-               rx_to_start = nic->rx_to_clean;
-
        /* Alloc new skbs to refill list */
        for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
                if(unlikely(e100_rx_alloc_skb(nic, rx)))
                        break; /* Better luck next time (see watchdog) */
        }
-
-       if(restart_required) {
-               // ack the rnr?
-               writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
-               e100_start_receiver(nic, rx_to_start);
-               if(work_done)
-                       (*work_done)++;
-       }
 }
 
 static void e100_rx_clean_list(struct nic *nic)
@@ -1905,8 +1862,6 @@ static void e100_rx_clean_list(struct nic *nic)
        struct rx *rx;
        unsigned int i, count = nic->params.rfds.count;
 
-       nic->ru_running = RU_UNINITIALIZED;
-
        if(nic->rxs) {
                for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
                        if(rx->skb) {
@@ -1928,7 +1883,6 @@ static int e100_rx_alloc_list(struct nic *nic)
        unsigned int i, count = nic->params.rfds.count;
 
        nic->rx_to_use = nic->rx_to_clean = NULL;
-       nic->ru_running = RU_UNINITIALIZED;
 
        if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC)))
                return -ENOMEM;
@@ -1943,7 +1897,6 @@ static int e100_rx_alloc_list(struct nic *nic)
        }
 
        nic->rx_to_use = nic->rx_to_clean = nic->rxs;
-       nic->ru_running = RU_SUSPENDED;
 
        return 0;
 }
@@ -1952,7 +1905,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
 {
        struct net_device *netdev = dev_id;
        struct nic *nic = netdev_priv(netdev);
-       u8 stat_ack = readb(&nic->csr->scb.stat_ack);
+       u8 stat_ack = ioread8(&nic->csr->scb.stat_ack);
 
        DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
 
@@ -1961,11 +1914,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
                return IRQ_NONE;
 
        /* Ack interrupt(s) */
-       writeb(stat_ack, &nic->csr->scb.stat_ack);
-
-       /* We hit Receive No Resource (RNR); restart RU after cleaning */
-       if(stat_ack & stat_ack_rnr)
-               nic->ru_running = RU_SUSPENDED;
+       iowrite8(stat_ack, &nic->csr->scb.stat_ack);
 
        if(likely(netif_rx_schedule_prep(netdev))) {
                e100_disable_irq(nic);
@@ -2058,7 +2007,7 @@ static int e100_up(struct nic *nic)
        if((err = e100_hw_init(nic)))
                goto err_clean_cbs;
        e100_set_multicast_list(nic->netdev);
-       e100_start_receiver(nic, NULL);
+       e100_start_receiver(nic);
        mod_timer(&nic->watchdog, jiffies);
        if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
                nic->netdev->name, nic->netdev)))
@@ -2107,7 +2056,7 @@ static void e100_tx_timeout_task(struct work_struct *work)
        struct net_device *netdev = nic->netdev;
 
        DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
-               readb(&nic->csr->scb.status));
+               ioread8(&nic->csr->scb.status));
        e100_down(netdev_priv(netdev));
        e100_up(netdev_priv(netdev));
 }
@@ -2139,7 +2088,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
                mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
                        BMCR_LOOPBACK);
 
-       e100_start_receiver(nic, NULL);
+       e100_start_receiver(nic);
 
        if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
                err = -ENOMEM;
@@ -2230,9 +2179,9 @@ static void e100_get_regs(struct net_device *netdev,
        int i;
 
        regs->version = (1 << 24) | nic->rev_id;
-       buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 |
-               readb(&nic->csr->scb.cmd_lo) << 16 |
-               readw(&nic->csr->scb.status);
+       buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 |
+               ioread8(&nic->csr->scb.cmd_lo) << 16 |
+               ioread16(&nic->csr->scb.status);
        for(i = E100_PHY_REGS; i >= 0; i--)
                buff[1 + E100_PHY_REGS - i] =
                        mdio_read(netdev, nic->mii.phy_id, i);
@@ -2604,7 +2553,10 @@ static int __devinit e100_probe(struct pci_dev *pdev,
        SET_MODULE_OWNER(netdev);
        SET_NETDEV_DEV(netdev, &pdev->dev);
 
-       nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr));
+       if (use_io)
+               DPRINTK(PROBE, INFO, "using i/o access mode\n");
+
+       nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct csr));
        if(!nic->csr) {
                DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n");
                err = -ENOMEM;
@@ -2651,11 +2603,16 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 
        memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
        memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
-       if(!is_valid_ether_addr(netdev->perm_addr)) {
-               DPRINTK(PROBE, ERR, "Invalid MAC address from "
-                       "EEPROM, aborting.\n");
-               err = -EAGAIN;
-               goto err_out_free;
+       if (!is_valid_ether_addr(netdev->perm_addr)) {
+               if (!eeprom_bad_csum_allow) {
+                       DPRINTK(PROBE, ERR, "Invalid MAC address from "
+                               "EEPROM, aborting.\n");
+                       err = -EAGAIN;
+                       goto err_out_free;
+               } else {
+                       DPRINTK(PROBE, ERR, "Invalid MAC address from EEPROM, "
+                               "you MUST configure one.\n");
+               }
        }
 
        /* Wol magic packet can be enabled from eeprom */
@@ -2676,7 +2633,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 
        DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
                "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
-               (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
+               (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq,
                netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
                netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
 
@@ -2685,7 +2642,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 err_out_free:
        e100_free(nic);
 err_out_iounmap:
-       iounmap(nic->csr);
+       pci_iounmap(pdev, nic->csr);
 err_out_free_res:
        pci_release_regions(pdev);
 err_out_disable_pdev:
index dd4b728ac4b58712ceb88658c1fa82807fccda39..a9ea67e75c1b322f1bfd03b0543ce982535ee7d0 100644 (file)
@@ -155,9 +155,6 @@ struct e1000_adapter;
 /* Number of packet split data buffers (not including the header buffer) */
 #define PS_PAGE_BUFFERS MAX_PS_BUFFERS-1
 
-/* only works for sizes that are powers of 2 */
-#define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
-
 /* wrapper around a pointer to a socket buffer,
  * so a DMA handle can be stored along with the buffer */
 struct e1000_buffer {
index 6777887295f538822d006aa582986cac6eeb94a7..bb08375b5f13f73629320bc874653c0fa7cfba01 100644 (file)
@@ -654,14 +654,11 @@ e1000_set_ringparam(struct net_device *netdev,
        e1000_mac_type mac_type = adapter->hw.mac_type;
        struct e1000_tx_ring *txdr, *tx_old;
        struct e1000_rx_ring *rxdr, *rx_old;
-       int i, err, tx_ring_size, rx_ring_size;
+       int i, err;
 
        if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
                return -EINVAL;
 
-       tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
-       rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
-
        while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
                msleep(1);
 
@@ -672,11 +669,11 @@ e1000_set_ringparam(struct net_device *netdev,
        rx_old = adapter->rx_ring;
 
        err = -ENOMEM;
-       txdr = kzalloc(tx_ring_size, GFP_KERNEL);
+       txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring), GFP_KERNEL);
        if (!txdr)
                goto err_alloc_tx;
 
-       rxdr = kzalloc(rx_ring_size, GFP_KERNEL);
+       rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring), GFP_KERNEL);
        if (!rxdr)
                goto err_alloc_rx;
 
@@ -686,12 +683,12 @@ e1000_set_ringparam(struct net_device *netdev,
        rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD);
        rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ?
                E1000_MAX_RXD : E1000_MAX_82544_RXD));
-       E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+       rxdr->count = ALIGN(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
 
        txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD);
        txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ?
                E1000_MAX_TXD : E1000_MAX_82544_TXD));
-       E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+       txdr->count = ALIGN(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
 
        for (i = 0; i < adapter->num_tx_queues; i++)
                txdr[i].count = txdr->count;
@@ -742,7 +739,7 @@ err_setup:
        uint32_t pat, value;                                                   \
        uint32_t test[] =                                                      \
                {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};              \
-       for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) {              \
+       for (pat = 0; pat < ARRAY_SIZE(test); pat++) {              \
                E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W));             \
                value = E1000_READ_REG(&adapter->hw, R);                       \
                if (value != (test[pat] & W & M)) {                             \
@@ -1053,23 +1050,24 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter)
        struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
        struct pci_dev *pdev = adapter->pdev;
        uint32_t rctl;
-       int size, i, ret_val;
+       int i, ret_val;
 
        /* Setup Tx descriptor ring and Tx buffers */
 
        if (!txdr->count)
                txdr->count = E1000_DEFAULT_TXD;
 
-       size = txdr->count * sizeof(struct e1000_buffer);
-       if (!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+       if (!(txdr->buffer_info = kcalloc(txdr->count,
+                                         sizeof(struct e1000_buffer),
+                                         GFP_KERNEL))) {
                ret_val = 1;
                goto err_nomem;
        }
-       memset(txdr->buffer_info, 0, size);
 
        txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
-       E1000_ROUNDUP(txdr->size, 4096);
-       if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) {
+       txdr->size = ALIGN(txdr->size, 4096);
+       if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size,
+                                               &txdr->dma))) {
                ret_val = 2;
                goto err_nomem;
        }
@@ -1116,12 +1114,12 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter)
        if (!rxdr->count)
                rxdr->count = E1000_DEFAULT_RXD;
 
-       size = rxdr->count * sizeof(struct e1000_buffer);
-       if (!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+       if (!(rxdr->buffer_info = kcalloc(rxdr->count,
+                                         sizeof(struct e1000_buffer),
+                                         GFP_KERNEL))) {
                ret_val = 4;
                goto err_nomem;
        }
-       memset(rxdr->buffer_info, 0, size);
 
        rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
        if (!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) {
index 9267f16b1b324be2a1d3abf97a3331eed20d2565..3a03a74c0609b89172941ccb9e6a9586005bbf31 100644 (file)
@@ -748,9 +748,9 @@ e1000_reset(struct e1000_adapter *adapter)
                               VLAN_TAG_SIZE;
                min_tx_space = min_rx_space;
                min_tx_space *= 2;
-               E1000_ROUNDUP(min_tx_space, 1024);
+               min_tx_space = ALIGN(min_tx_space, 1024);
                min_tx_space >>= 10;
-               E1000_ROUNDUP(min_rx_space, 1024);
+               min_rx_space = ALIGN(min_rx_space, 1024);
                min_rx_space >>= 10;
 
                /* If current Tx allocation is less than the min Tx FIFO size,
@@ -1354,31 +1354,27 @@ e1000_sw_init(struct e1000_adapter *adapter)
 static int __devinit
 e1000_alloc_queues(struct e1000_adapter *adapter)
 {
-       int size;
-
-       size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
-       adapter->tx_ring = kmalloc(size, GFP_KERNEL);
+       adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+                                  sizeof(struct e1000_tx_ring), GFP_KERNEL);
        if (!adapter->tx_ring)
                return -ENOMEM;
-       memset(adapter->tx_ring, 0, size);
 
-       size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
-       adapter->rx_ring = kmalloc(size, GFP_KERNEL);
+       adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+                                  sizeof(struct e1000_rx_ring), GFP_KERNEL);
        if (!adapter->rx_ring) {
                kfree(adapter->tx_ring);
                return -ENOMEM;
        }
-       memset(adapter->rx_ring, 0, size);
 
 #ifdef CONFIG_E1000_NAPI
-       size = sizeof(struct net_device) * adapter->num_rx_queues;
-       adapter->polling_netdev = kmalloc(size, GFP_KERNEL);
+       adapter->polling_netdev = kcalloc(adapter->num_rx_queues,
+                                         sizeof(struct net_device),
+                                         GFP_KERNEL);
        if (!adapter->polling_netdev) {
                kfree(adapter->tx_ring);
                kfree(adapter->rx_ring);
                return -ENOMEM;
        }
-       memset(adapter->polling_netdev, 0, size);
 #endif
 
        return E1000_SUCCESS;
@@ -1560,7 +1556,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter,
        /* round up to nearest 4K */
 
        txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
-       E1000_ROUNDUP(txdr->size, 4096);
+       txdr->size = ALIGN(txdr->size, 4096);
 
        txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
        if (!txdr->desc) {
@@ -1774,18 +1770,18 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
        }
        memset(rxdr->buffer_info, 0, size);
 
-       size = sizeof(struct e1000_ps_page) * rxdr->count;
-       rxdr->ps_page = kmalloc(size, GFP_KERNEL);
+       rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct e1000_ps_page),
+                               GFP_KERNEL);
        if (!rxdr->ps_page) {
                vfree(rxdr->buffer_info);
                DPRINTK(PROBE, ERR,
                "Unable to allocate memory for the receive descriptor ring\n");
                return -ENOMEM;
        }
-       memset(rxdr->ps_page, 0, size);
 
-       size = sizeof(struct e1000_ps_page_dma) * rxdr->count;
-       rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL);
+       rxdr->ps_page_dma = kcalloc(rxdr->count,
+                                   sizeof(struct e1000_ps_page_dma),
+                                   GFP_KERNEL);
        if (!rxdr->ps_page_dma) {
                vfree(rxdr->buffer_info);
                kfree(rxdr->ps_page);
@@ -1793,7 +1789,6 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
                "Unable to allocate memory for the receive descriptor ring\n");
                return -ENOMEM;
        }
-       memset(rxdr->ps_page_dma, 0, size);
 
        if (adapter->hw.mac_type <= e1000_82547_rev_2)
                desc_len = sizeof(struct e1000_rx_desc);
@@ -1803,7 +1798,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
        /* Round up to nearest 4K */
 
        rxdr->size = rxdr->count * desc_len;
-       E1000_ROUNDUP(rxdr->size, 4096);
+       rxdr->size = ALIGN(rxdr->size, 4096);
 
        rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
 
@@ -2667,7 +2662,7 @@ e1000_watchdog(unsigned long data)
 
                        netif_carrier_on(netdev);
                        netif_wake_queue(netdev);
-                       mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+                       mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ));
                        adapter->smartspeed = 0;
                } else {
                        /* make sure the receive unit is started */
@@ -2684,7 +2679,7 @@ e1000_watchdog(unsigned long data)
                        DPRINTK(LINK, INFO, "NIC Link is Down\n");
                        netif_carrier_off(netdev);
                        netif_stop_queue(netdev);
-                       mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+                       mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ));
 
                        /* 80003ES2LAN workaround--
                         * For packet buffer work-around on link down event;
@@ -2736,7 +2731,7 @@ e1000_watchdog(unsigned long data)
                e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
 
        /* Reset the timer */
-       mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+       mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ));
 }
 
 enum latency_range {
@@ -3175,7 +3170,7 @@ e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb)
        uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head;
        uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR;
 
-       E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR);
+       skb_fifo_len = ALIGN(skb_fifo_len, E1000_FIFO_HDR);
 
        if (adapter->link_duplex != HALF_DUPLEX)
                goto no_fifo_stall_required;
index f8862e203ac9f9f4d76ba4ef026040cbf308d15b..f485874a63f56f6d5b0eaee18e3813cf3aa75c7a 100644 (file)
@@ -305,7 +305,7 @@ e1000_check_options(struct e1000_adapter *adapter)
                if (num_TxDescriptors > bd) {
                        tx_ring->count = TxDescriptors[bd];
                        e1000_validate_option(&tx_ring->count, &opt, adapter);
-                       E1000_ROUNDUP(tx_ring->count,
+                       tx_ring->count = ALIGN(tx_ring->count,
                                                REQ_TX_DESCRIPTOR_MULTIPLE);
                } else {
                        tx_ring->count = opt.def;
@@ -331,7 +331,7 @@ e1000_check_options(struct e1000_adapter *adapter)
                if (num_RxDescriptors > bd) {
                        rx_ring->count = RxDescriptors[bd];
                        e1000_validate_option(&rx_ring->count, &opt, adapter);
-                       E1000_ROUNDUP(rx_ring->count,
+                       rx_ring->count = ALIGN(rx_ring->count,
                                                REQ_RX_DESCRIPTOR_MULTIPLE);
                } else {
                        rx_ring->count = opt.def;
index 8aaf5ec0c36089ed07b32c65024bf97d0b75d82c..7934ea37f9442e55a16e37a02deb360a2cc12253 100644 (file)
 #include <linux/mca-legacy.h>
 #include <linux/spinlock.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -556,7 +557,7 @@ static void unstick_cu(struct net_device *dev)
 
        if (lp->started)
        {
-               if ((jiffies - dev->trans_start)>50)
+               if (time_after(jiffies, dev->trans_start + 50))
                {
                        if (lp->tx_link==lp->last_tx_restart)
                        {
@@ -612,7 +613,7 @@ static void unstick_cu(struct net_device *dev)
        }
        else
        {
-               if ((jiffies-lp->init_time)>10)
+               if (time_after(jiffies, lp->init_time + 10))
                {
                        unsigned short status = scb_status(dev);
                        printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
@@ -776,7 +777,7 @@ static unsigned short eexp_start_irq(struct net_device *dev,
 static void eexp_cmd_clear(struct net_device *dev)
 {
        unsigned long int oldtime = jiffies;
-       while (scb_rdcmd(dev) && ((jiffies-oldtime)<10));
+       while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
        if (scb_rdcmd(dev)) {
                printk("%s: command didn't clear\n", dev->name);
        }
@@ -1649,7 +1650,7 @@ eexp_set_multicast(struct net_device *dev)
 #endif
                 oj = jiffies;
                 while ((SCB_CUstat(scb_status(dev)) == 2) &&
-                       ((jiffies-oj) < 2000));
+                       (time_before(jiffies, oj + 2000)));
                if (SCB_CUstat(scb_status(dev)) == 2)
                        printk("%s: warning, CU didn't stop\n", dev->name);
                 lp->started &= ~(STARTED_CU);
index 42295d61ecd847791f6a8c04513940c471732790..602872dbe15fa4be022b2effd872a0deb447c6b3 100644 (file)
@@ -39,7 +39,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "ehea"
-#define DRV_VERSION    "EHEA_0046"
+#define DRV_VERSION    "EHEA_0058"
 
 #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
        | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
 #define EHEA_RQ2_PKT_SIZE       1522
 #define EHEA_L_PKT_SIZE         256    /* low latency */
 
-#define EHEA_POLL_MAX_RWQE      1000
-
 /* Send completion signaling */
-#define EHEA_SIG_IV_LONG           1
 
 /* Protection Domain Identifier */
 #define EHEA_PD_ID        0xaabcdeff
 #define EHEA_CACHE_LINE          128
 
 /* Memory Regions */
-#define EHEA_MR_MAX_TX_PAGES   20
-#define EHEA_MR_TX_DATA_PN      3
 #define EHEA_MR_ACC_CTRL       0x00800000
-#define EHEA_RWQES_PER_MR_RQ2  10
-#define EHEA_RWQES_PER_MR_RQ3  10
 
 #define EHEA_WATCH_DOG_TIMEOUT 10*HZ
 
@@ -311,6 +304,7 @@ struct ehea_cq {
  * Memory Region
  */
 struct ehea_mr {
+       struct ehea_adapter *adapter;
        u64 handle;
        u64 vaddr;
        u32 lkey;
@@ -319,17 +313,12 @@ struct ehea_mr {
 /*
  * Port state information
  */
-struct port_state {
-       int poll_max_processed;
+struct port_stats {
        int poll_receive_errors;
-       int ehea_poll;
        int queue_stopped;
-       int min_swqe_avail;
-       u64 sqc_stop_sum;
-       int pkt_send;
-       int pkt_xmit;
-       int send_tasklet;
-       int nwqe;
+       int err_tcp_cksum;
+       int err_ip_cksum;
+       int err_frame_crc;
 };
 
 #define EHEA_IRQ_NAME_SIZE 20
@@ -348,6 +337,7 @@ struct ehea_q_skb_arr {
  * Port resources
  */
 struct ehea_port_res {
+       struct port_stats p_stats;
        struct ehea_mr send_mr;         /* send memory region */
        struct ehea_mr recv_mr;         /* receive memory region */
        spinlock_t xmit_lock;
@@ -357,9 +347,8 @@ struct ehea_port_res {
        struct ehea_qp *qp;
        struct ehea_cq *send_cq;
        struct ehea_cq *recv_cq;
-       struct ehea_eq *send_eq;
-       struct ehea_eq *recv_eq;
-       spinlock_t send_lock;
+       struct ehea_eq *eq;
+       struct net_device *d_netdev;
        struct ehea_q_skb_arr rq1_skba;
        struct ehea_q_skb_arr rq2_skba;
        struct ehea_q_skb_arr rq3_skba;
@@ -369,21 +358,18 @@ struct ehea_port_res {
        int swqe_refill_th;
        atomic_t swqe_avail;
        int swqe_ll_count;
-       int swqe_count;
        u32 swqe_id_counter;
        u64 tx_packets;
-       struct tasklet_struct send_comp_task;
-       spinlock_t recv_lock;
-       struct port_state p_state;
        u64 rx_packets;
        u32 poll_counter;
 };
 
 
+#define EHEA_MAX_PORTS 16
 struct ehea_adapter {
        u64 handle;
-       u8 num_ports;
-       struct ehea_port *port[16];
+       struct ibmebus_dev *ebus_dev;
+       struct ehea_port *port[EHEA_MAX_PORTS];
        struct ehea_eq *neq;       /* notification event queue */
        struct workqueue_struct *ehea_wq;
        struct tasklet_struct neq_tasklet;
@@ -406,7 +392,7 @@ struct ehea_port {
        struct net_device *netdev;
        struct net_device_stats stats;
        struct ehea_port_res port_res[EHEA_MAX_PORT_RES];
-       struct device_node *of_dev_node; /* Open Firmware Device Node */
+       struct of_device  ofdev; /* Open Firmware Device */
        struct ehea_mc_list *mc_list;    /* Multicast MAC addresses */
        struct vlan_group *vgrp;
        struct ehea_eq *qp_eq;
@@ -415,7 +401,9 @@ struct ehea_port {
        char int_aff_name[EHEA_IRQ_NAME_SIZE];
        int allmulti;                    /* Indicates IFF_ALLMULTI state */
        int promisc;                     /* Indicates IFF_PROMISC state */
+       int num_tx_qps;
        int num_add_tx_qps;
+       int num_mcs;
        int resets;
        u64 mac_addr;
        u32 logical_port_id;
index 9f57c2e78cedce2359a85a761ea363e7addab83f..decec8cfe96b8c2789705971409f2344f8b5558d 100644 (file)
@@ -144,8 +144,8 @@ static int ehea_nway_reset(struct net_device *dev)
 static void ehea_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strlcpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
-       strlcpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static u32 ehea_get_msglevel(struct net_device *dev)
@@ -166,33 +166,23 @@ static u32 ehea_get_rx_csum(struct net_device *dev)
 }
 
 static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
-       {"poll_max_processed"},
-       {"queue_stopped"},
-       {"min_swqe_avail"},
-       {"poll_receive_err"},
-       {"pkt_send"},
-       {"pkt_xmit"},
-       {"send_tasklet"},
-       {"ehea_poll"},
-       {"nwqe"},
-       {"swqe_available_0"},
        {"sig_comp_iv"},
        {"swqe_refill_th"},
        {"port resets"},
-       {"rxo"},
-       {"rx64"},
-       {"rx65"},
-       {"rx128"},
-       {"rx256"},
-       {"rx512"},
-       {"rx1024"},
-       {"txo"},
-       {"tx64"},
-       {"tx65"},
-       {"tx128"},
-       {"tx256"},
-       {"tx512"},
-       {"tx1024"},
+       {"Receive errors"},
+       {"TCP cksum errors"},
+       {"IP cksum errors"},
+       {"Frame cksum errors"},
+       {"num SQ stopped"},
+       {"SQ stopped"},
+       {"PR0 free_swqes"},
+       {"PR1 free_swqes"},
+       {"PR2 free_swqes"},
+       {"PR3 free_swqes"},
+       {"PR4 free_swqes"},
+       {"PR5 free_swqes"},
+       {"PR6 free_swqes"},
+       {"PR7 free_swqes"},
 };
 
 static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -211,63 +201,44 @@ static int ehea_get_stats_count(struct net_device *dev)
 static void ehea_get_ethtool_stats(struct net_device *dev,
                                     struct ethtool_stats *stats, u64 *data)
 {
-       u64 hret;
-       int i;
+       int i, k, tmp;
        struct ehea_port *port = netdev_priv(dev);
-       struct ehea_adapter *adapter = port->adapter;
-       struct ehea_port_res *pr = &port->port_res[0];
-       struct port_state *p_state = &pr->p_state;
-       struct hcp_ehea_port_cb6 *cb6;
 
        for (i = 0; i < ehea_get_stats_count(dev); i++)
                data[i] = 0;
-
        i = 0;
 
-       data[i++] = p_state->poll_max_processed;
-       data[i++] = p_state->queue_stopped;
-       data[i++] = p_state->min_swqe_avail;
-       data[i++] = p_state->poll_receive_errors;
-       data[i++] = p_state->pkt_send;
-       data[i++] = p_state->pkt_xmit;
-       data[i++] = p_state->send_tasklet;
-       data[i++] = p_state->ehea_poll;
-       data[i++] = p_state->nwqe;
-       data[i++] = atomic_read(&port->port_res[0].swqe_avail);
        data[i++] = port->sig_comp_iv;
        data[i++] = port->port_res[0].swqe_refill_th;
        data[i++] = port->resets;
 
-       cb6 = kzalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!cb6) {
-               ehea_error("no mem for cb6");
-               return;
-       }
+       for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+               tmp += port->port_res[k].p_stats.poll_receive_errors;
+       data[i++] = tmp;
+
+       for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+               tmp += port->port_res[k].p_stats.err_tcp_cksum;
+       data[i++] = tmp;
+
+       for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+               tmp += port->port_res[k].p_stats.err_ip_cksum;
+       data[i++] = tmp;
+
+       for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+               tmp += port->port_res[k].p_stats.err_frame_crc;
+       data[i++] = tmp;
+
+       for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+               tmp += port->port_res[k].p_stats.queue_stopped;
+       data[i++] = tmp;
+
+       for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+               tmp |= port->port_res[k].queue_stopped;
+       data[i++] = tmp;
+
+       for (k = 0; k < 8; k++)
+               data[i++] = atomic_read(&port->port_res[k].swqe_avail);
 
-       hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
-                                     H_PORT_CB6, H_PORT_CB6_ALL, cb6);
-       if (netif_msg_hw(port))
-               ehea_dump(cb6, sizeof(*cb6), "ehea_get_ethtool_stats");
-
-       if (hret == H_SUCCESS) {
-               data[i++] = cb6->rxo;
-               data[i++] = cb6->rx64;
-               data[i++] = cb6->rx65;
-               data[i++] = cb6->rx128;
-               data[i++] = cb6->rx256;
-               data[i++] = cb6->rx512;
-               data[i++] = cb6->rx1024;
-               data[i++] = cb6->txo;
-               data[i++] = cb6->tx64;
-               data[i++] = cb6->tx65;
-               data[i++] = cb6->tx128;
-               data[i++] = cb6->tx256;
-               data[i++] = cb6->tx512;
-               data[i++] = cb6->tx1024;
-       } else
-               ehea_error("query_ehea_port failed");
-
-       kfree(cb6);
 }
 
 const struct ethtool_ops ehea_ethtool_ops = {
index 58364a0ff378128c72710ae7238029c3348703d5..c7a5614e66c01b6d928521cb609296d97c923662 100644 (file)
@@ -51,13 +51,18 @@ static int rq1_entries = EHEA_DEF_ENTRIES_RQ1;
 static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
 static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
 static int sq_entries = EHEA_DEF_ENTRIES_SQ;
+static int use_mcs = 0;
+static int num_tx_qps = EHEA_NUM_TX_QP;
 
 module_param(msg_level, int, 0);
 module_param(rq1_entries, int, 0);
 module_param(rq2_entries, int, 0);
 module_param(rq3_entries, int, 0);
 module_param(sq_entries, int, 0);
+module_param(use_mcs, int, 0);
+module_param(num_tx_qps, int, 0);
 
+MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS");
 MODULE_PARM_DESC(msg_level, "msg_level");
 MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
                 "[2^x - 1], x = [6..14]. Default = "
@@ -71,6 +76,29 @@ MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
 MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue  "
                 "[2^x - 1], x = [6..14]. Default = "
                 __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
+MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 ");
+
+static int port_name_cnt = 0;
+
+static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
+                                        const struct of_device_id *id);
+
+static int __devexit ehea_remove(struct ibmebus_dev *dev);
+
+static struct of_device_id ehea_device_table[] = {
+       {
+               .name = "lhea",
+               .compatible = "IBM,lhea",
+       },
+       {},
+};
+
+static struct ibmebus_driver ehea_driver = {
+       .name = "ehea",
+       .id_table = ehea_device_table,
+       .probe = ehea_probe_adapter,
+       .remove = ehea_remove,
+};
 
 void ehea_dump(void *adr, int len, char *msg) {
        int x;
@@ -197,7 +225,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
                struct sk_buff *skb = netdev_alloc_skb(dev, packet_size);
                if (!skb) {
                        ehea_error("%s: no mem for skb/%d wqes filled",
-                                  dev->name, i);
+                                  pr->port->netdev->name, i);
                        q_skba->os_skbs = fill_wqes - i;
                        ret = -ENOMEM;
                        break;
@@ -321,6 +349,13 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
 {
        struct sk_buff *skb;
 
+       if (cqe->status & EHEA_CQE_STAT_ERR_TCP)
+               pr->p_stats.err_tcp_cksum++;
+       if (cqe->status & EHEA_CQE_STAT_ERR_IP)
+               pr->p_stats.err_ip_cksum++;
+       if (cqe->status & EHEA_CQE_STAT_ERR_CRC)
+               pr->p_stats.err_frame_crc++;
+
        if (netif_msg_rx_err(pr->port)) {
                ehea_error("CQE Error for QP %d", pr->qp->init_attr.qp_nr);
                ehea_dump(cqe, sizeof(*cqe), "CQE");
@@ -345,10 +380,11 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
        return 0;
 }
 
-static int ehea_poll(struct net_device *dev, int *budget)
+static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
+                                       struct ehea_port_res *pr,
+                                       int *budget)
 {
-       struct ehea_port *port = netdev_priv(dev);
-       struct ehea_port_res *pr = &port->port_res[0];
+       struct ehea_port *port = pr->port;
        struct ehea_qp *qp = pr->qp;
        struct ehea_cqe *cqe;
        struct sk_buff *skb;
@@ -359,14 +395,12 @@ static int ehea_poll(struct net_device *dev, int *budget)
        int skb_arr_rq2_len = pr->rq2_skba.len;
        int skb_arr_rq3_len = pr->rq3_skba.len;
        int processed, processed_rq1, processed_rq2, processed_rq3;
-       int wqe_index, last_wqe_index, rq, intreq, my_quota, port_reset;
+       int wqe_index, last_wqe_index, rq, my_quota, port_reset;
 
        processed = processed_rq1 = processed_rq2 = processed_rq3 = 0;
        last_wqe_index = 0;
        my_quota = min(*budget, dev->quota);
-       my_quota = min(my_quota, EHEA_POLL_MAX_RWQE);
 
-       /* rq0 is low latency RQ */
        cqe = ehea_poll_rq1(qp, &wqe_index);
        while ((my_quota > 0) && cqe) {
                ehea_inc_rq1(qp);
@@ -386,7 +420,8 @@ static int ehea_poll(struct net_device *dev, int *budget)
                                if (unlikely(!skb)) {
                                        if (netif_msg_rx_err(port))
                                                ehea_error("LL rq1: skb=NULL");
-                                       skb = netdev_alloc_skb(dev,
+
+                                       skb = netdev_alloc_skb(port->netdev,
                                                               EHEA_L_PKT_SIZE);
                                        if (!skb)
                                                break;
@@ -402,7 +437,7 @@ static int ehea_poll(struct net_device *dev, int *budget)
                                                ehea_error("rq2: skb=NULL");
                                        break;
                                }
-                               ehea_fill_skb(dev, skb, cqe);
+                               ehea_fill_skb(port->netdev, skb, cqe);
                                processed_rq2++;
                        } else {  /* RQ3 */
                                skb = get_skb_by_index(skb_arr_rq3,
@@ -412,7 +447,7 @@ static int ehea_poll(struct net_device *dev, int *budget)
                                                ehea_error("rq3: skb=NULL");
                                        break;
                                }
-                               ehea_fill_skb(dev, skb, cqe);
+                               ehea_fill_skb(port->netdev, skb, cqe);
                                processed_rq3++;
                        }
 
@@ -421,9 +456,8 @@ static int ehea_poll(struct net_device *dev, int *budget)
                                                         cqe->vlan_tag);
                        else
                                netif_receive_skb(skb);
-
-               } else { /* Error occured */
-                       pr->p_state.poll_receive_errors++;
+               } else {
+                       pr->p_stats.poll_receive_errors++;
                        port_reset = ehea_treat_poll_error(pr, rq, cqe,
                                                           &processed_rq2,
                                                           &processed_rq3);
@@ -433,72 +467,32 @@ static int ehea_poll(struct net_device *dev, int *budget)
                cqe = ehea_poll_rq1(qp, &wqe_index);
        }
 
-       dev->quota -= processed;
-       *budget -= processed;
-
-       pr->p_state.ehea_poll += 1;
        pr->rx_packets += processed;
+       *budget -= processed;
 
        ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
        ehea_refill_rq2(pr, processed_rq2);
        ehea_refill_rq3(pr, processed_rq3);
 
-       intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF);
-
-       if (!cqe || intreq) {
-               netif_rx_complete(dev);
-               ehea_reset_cq_ep(pr->recv_cq);
-               ehea_reset_cq_n1(pr->recv_cq);
-               cqe = hw_qeit_get_valid(&qp->hw_rqueue1);
-               if (!cqe || intreq)
-                       return 0;
-               if (!netif_rx_reschedule(dev, my_quota))
-                       return 0;
-       }
-       return 1;
+       cqe = ehea_poll_rq1(qp, &wqe_index);
+       return cqe;
 }
 
-void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr)
+static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
 {
        struct sk_buff *skb;
-       int index, max_index_mask, i;
-
-       index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
-       max_index_mask = pr->sq_skba.len - 1;
-       for (i = 0; i < EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); i++) {
-               skb = pr->sq_skba.arr[index];
-               if (likely(skb)) {
-                       dev_kfree_skb(skb);
-                       pr->sq_skba.arr[index] = NULL;
-               } else {
-                       ehea_error("skb=NULL, wr_id=%lX, loop=%d, index=%d",
-                                  cqe->wr_id, i, index);
-               }
-               index--;
-               index &= max_index_mask;
-       }
-}
-
-#define MAX_SENDCOMP_QUOTA 400
-void ehea_send_irq_tasklet(unsigned long data)
-{
-       struct ehea_port_res *pr = (struct ehea_port_res*)data;
        struct ehea_cq *send_cq = pr->send_cq;
        struct ehea_cqe *cqe;
-       int quota = MAX_SENDCOMP_QUOTA;
+       int quota = my_quota;
        int cqe_counter = 0;
        int swqe_av = 0;
+       int index;
        unsigned long flags;
 
-       do {
-               cqe = ehea_poll_cq(send_cq);
-               if (!cqe) {
-                       ehea_reset_cq_ep(send_cq);
-                       ehea_reset_cq_n1(send_cq);
-                       cqe = ehea_poll_cq(send_cq);
-                       if (!cqe)
-                               break;
-               }
+       cqe = ehea_poll_cq(send_cq);
+       while(cqe && (quota > 0)) {
+               ehea_inc_cq(send_cq);
+
                cqe_counter++;
                rmb();
                if (cqe->status & EHEA_CQE_STAT_ERR_MASK) {
@@ -514,17 +508,25 @@ void ehea_send_irq_tasklet(unsigned long data)
                        ehea_dump(cqe, sizeof(*cqe), "CQE");
 
                if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id)
-                          == EHEA_SWQE2_TYPE))
-                       free_sent_skbs(cqe, pr);
+                          == EHEA_SWQE2_TYPE)) {
+
+                       index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
+                       skb = pr->sq_skba.arr[index];
+                       dev_kfree_skb(skb);
+                       pr->sq_skba.arr[index] = NULL;
+               }
 
                swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id);
                quota--;
-       } while (quota > 0);
+
+               cqe = ehea_poll_cq(send_cq);
+       };
 
        ehea_update_feca(send_cq, cqe_counter);
        atomic_add(swqe_av, &pr->swqe_avail);
 
        spin_lock_irqsave(&pr->netif_queue, flags);
+
        if (pr->queue_stopped && (atomic_read(&pr->swqe_avail)
                                  >= pr->swqe_refill_th)) {
                netif_wake_queue(pr->port->netdev);
@@ -532,22 +534,55 @@ void ehea_send_irq_tasklet(unsigned long data)
        }
        spin_unlock_irqrestore(&pr->netif_queue, flags);
 
-       if (unlikely(cqe))
-               tasklet_hi_schedule(&pr->send_comp_task);
+       return cqe;
 }
 
-static irqreturn_t ehea_send_irq_handler(int irq, void *param)
+#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16
+
+static int ehea_poll(struct net_device *dev, int *budget)
 {
-       struct ehea_port_res *pr = param;
-       tasklet_hi_schedule(&pr->send_comp_task);
-       return IRQ_HANDLED;
+       struct ehea_port_res *pr = dev->priv;
+       struct ehea_cqe *cqe;
+       struct ehea_cqe *cqe_skb = NULL;
+       int force_irq, wqe_index;
+
+       cqe = ehea_poll_rq1(pr->qp, &wqe_index);
+       cqe_skb = ehea_poll_cq(pr->send_cq);
+
+       force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ);
+
+       if ((!cqe && !cqe_skb) || force_irq) {
+               pr->poll_counter = 0;
+               netif_rx_complete(dev);
+               ehea_reset_cq_ep(pr->recv_cq);
+               ehea_reset_cq_ep(pr->send_cq);
+               ehea_reset_cq_n1(pr->recv_cq);
+               ehea_reset_cq_n1(pr->send_cq);
+               cqe = ehea_poll_rq1(pr->qp, &wqe_index);
+               cqe_skb = ehea_poll_cq(pr->send_cq);
+
+               if (!cqe && !cqe_skb)
+                       return 0;
+
+               if (!netif_rx_reschedule(dev, dev->quota))
+                       return 0;
+       }
+
+       cqe = ehea_proc_rwqes(dev, pr, budget);
+       cqe_skb = ehea_proc_cqes(pr, 300);
+
+       if (cqe || cqe_skb)
+               pr->poll_counter++;
+
+       return 1;
 }
 
 static irqreturn_t ehea_recv_irq_handler(int irq, void *param)
 {
        struct ehea_port_res *pr = param;
-       struct ehea_port *port = pr->port;
-       netif_rx_schedule(port->netdev);
+
+       netif_rx_schedule(pr->d_netdev);
+
        return IRQ_HANDLED;
 }
 
@@ -580,7 +615,7 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
 {
        int i;
 
-       for (i = 0; i < adapter->num_ports; i++)
+       for (i = 0; i < EHEA_MAX_PORTS; i++)
                if (adapter->port[i])
                        if (adapter->port[i]->logical_port_id == logical_port)
                                return adapter->port[i];
@@ -650,19 +685,25 @@ int ehea_sense_port_attr(struct ehea_port *port)
        }
 
        port->autoneg = 1;
+       port->num_mcs = cb0->num_default_qps;
 
        /* Number of default QPs */
-       port->num_def_qps = cb0->num_default_qps;
+       if (use_mcs)
+               port->num_def_qps = cb0->num_default_qps;
+       else
+               port->num_def_qps = 1;
 
        if (!port->num_def_qps) {
                ret = -EINVAL;
                goto out_free;
        }
 
-       if (port->num_def_qps >= EHEA_NUM_TX_QP)
+       port->num_tx_qps = num_tx_qps;
+
+       if (port->num_def_qps >= port->num_tx_qps)
                port->num_add_tx_qps = 0;
        else
-               port->num_add_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps;
+               port->num_add_tx_qps = port->num_tx_qps - port->num_def_qps;
 
        ret = 0;
 out_free:
@@ -882,23 +923,6 @@ static int ehea_reg_interrupts(struct net_device *dev)
        struct ehea_port_res *pr;
        int i, ret;
 
-       for (i = 0; i < port->num_def_qps; i++) {
-               pr = &port->port_res[i];
-               snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1
-                        , "%s-recv%d", dev->name, i);
-               ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1,
-                                         ehea_recv_irq_handler,
-                                         IRQF_DISABLED, pr->int_recv_name, pr);
-               if (ret) {
-                       ehea_error("failed registering irq for ehea_recv_int:"
-                                  "port_res_nr:%d, ist=%X", i,
-                                  pr->recv_eq->attr.ist1);
-                       goto out_free_seq;
-               }
-               if (netif_msg_ifup(port))
-                       ehea_info("irq_handle 0x%X for funct ehea_recv_int %d "
-                                 "registered", pr->recv_eq->attr.ist1, i);
-       }
 
        snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff",
                 dev->name);
@@ -916,41 +940,41 @@ static int ehea_reg_interrupts(struct net_device *dev)
                ehea_info("irq_handle 0x%X for function qp_aff_irq_handler "
                          "registered", port->qp_eq->attr.ist1);
 
+
        for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
                pr = &port->port_res[i];
                snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
-                        "%s-send%d", dev->name, i);
-               ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1,
-                                         ehea_send_irq_handler,
+                        "%s-queue%d", dev->name, i);
+               ret = ibmebus_request_irq(NULL, pr->eq->attr.ist1,
+                                         ehea_recv_irq_handler,
                                          IRQF_DISABLED, pr->int_send_name,
                                          pr);
                if (ret) {
-                       ehea_error("failed registering irq for ehea_send "
+                       ehea_error("failed registering irq for ehea_queue "
                                   "port_res_nr:%d, ist=%X", i,
-                                  pr->send_eq->attr.ist1);
+                                  pr->eq->attr.ist1);
                        goto out_free_req;
                }
                if (netif_msg_ifup(port))
-                       ehea_info("irq_handle 0x%X for function ehea_send_int "
-                                 "%d registered", pr->send_eq->attr.ist1, i);
+                       ehea_info("irq_handle 0x%X for function ehea_queue_int "
+                                 "%d registered", pr->eq->attr.ist1, i);
        }
 out:
        return ret;
 
+
 out_free_req:
        while (--i >= 0) {
-               u32 ist = port->port_res[i].send_eq->attr.ist1;
+               u32 ist = port->port_res[i].eq->attr.ist1;
                ibmebus_free_irq(NULL, ist, &port->port_res[i]);
        }
+
 out_free_qpeq:
        ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
        i = port->num_def_qps;
-out_free_seq:
-       while (--i >= 0) {
-               u32 ist = port->port_res[i].recv_eq->attr.ist1;
-               ibmebus_free_irq(NULL, ist, &port->port_res[i]);
-       }
+
        goto out;
+
 }
 
 static void ehea_free_interrupts(struct net_device *dev)
@@ -960,21 +984,13 @@ static void ehea_free_interrupts(struct net_device *dev)
        int i;
 
        /* send */
+
        for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
                pr = &port->port_res[i];
-               ibmebus_free_irq(NULL, pr->send_eq->attr.ist1, pr);
+               ibmebus_free_irq(NULL, pr->eq->attr.ist1, pr);
                if (netif_msg_intr(port))
                        ehea_info("free send irq for res %d with handle 0x%X",
-                                 i, pr->send_eq->attr.ist1);
-       }
-
-       /* receive */
-       for (i = 0; i < port->num_def_qps; i++) {
-               pr = &port->port_res[i];
-               ibmebus_free_irq(NULL, pr->recv_eq->attr.ist1, pr);
-               if (netif_msg_intr(port))
-                       ehea_info("free recv irq for res %d with handle 0x%X",
-                                 i, pr->recv_eq->attr.ist1);
+                                 i, pr->eq->attr.ist1);
        }
 
        /* associated events */
@@ -1003,8 +1019,13 @@ static int ehea_configure_port(struct ehea_port *port)
                                      PXLY_RC_VLAN_FILTER)
                     | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1);
 
-       for (i = 0; i < port->num_def_qps; i++)
-               cb0->default_qpn_arr[i] = port->port_res[0].qp->init_attr.qp_nr;
+       for (i = 0; i < port->num_mcs; i++)
+               if (use_mcs)
+                       cb0->default_qpn_arr[i] =
+                               port->port_res[i].qp->init_attr.qp_nr;
+               else
+                       cb0->default_qpn_arr[i] =
+                               port->port_res[0].qp->init_attr.qp_nr;
 
        if (netif_msg_ifup(port))
                ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port");
@@ -1027,52 +1048,35 @@ out:
        return ret;
 }
 
-static int ehea_gen_smrs(struct ehea_port_res *pr)
+int ehea_gen_smrs(struct ehea_port_res *pr)
 {
-       u64 hret;
+       int ret;
        struct ehea_adapter *adapter = pr->port->adapter;
 
-       hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle,
-                                  adapter->mr.vaddr, EHEA_MR_ACC_CTRL,
-                                  adapter->pd, &pr->send_mr);
-       if (hret != H_SUCCESS)
+       ret = ehea_gen_smr(adapter, &adapter->mr, &pr->send_mr);
+       if (ret)
                goto out;
 
-       hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle,
-                                  adapter->mr.vaddr, EHEA_MR_ACC_CTRL,
-                                  adapter->pd, &pr->recv_mr);
-       if (hret != H_SUCCESS)
-               goto out_freeres;
+       ret = ehea_gen_smr(adapter, &adapter->mr, &pr->recv_mr);
+       if (ret)
+               goto out_free;
 
        return 0;
 
-out_freeres:
-       hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle);
-       if (hret != H_SUCCESS)
-               ehea_error("failed freeing SMR");
+out_free:
+       ehea_rem_mr(&pr->send_mr);
 out:
+       ehea_error("Generating SMRS failed\n");
        return -EIO;
 }
 
-static int ehea_rem_smrs(struct ehea_port_res *pr)
+int ehea_rem_smrs(struct ehea_port_res *pr)
 {
-       struct ehea_adapter *adapter = pr->port->adapter;
-       int ret = 0;
-       u64 hret;
-
-       hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle);
-       if (hret != H_SUCCESS) {
-               ret = -EIO;
-               ehea_error("failed freeing send SMR for pr=%p", pr);
-       }
-
-       hret = ehea_h_free_resource(adapter->handle, pr->recv_mr.handle);
-       if (hret != H_SUCCESS) {
-               ret = -EIO;
-               ehea_error("failed freeing recv SMR for pr=%p", pr);
-       }
-
-       return ret;
+       if ((ehea_rem_mr(&pr->send_mr))
+           || (ehea_rem_mr(&pr->recv_mr)))
+               return -EIO;
+       else
+               return 0;
 }
 
 static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
@@ -1103,25 +1107,17 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
        memset(pr, 0, sizeof(struct ehea_port_res));
 
        pr->port = port;
-       spin_lock_init(&pr->send_lock);
-       spin_lock_init(&pr->recv_lock);
        spin_lock_init(&pr->xmit_lock);
        spin_lock_init(&pr->netif_queue);
 
-       pr->recv_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
-       if (!pr->recv_eq) {
-               ehea_error("create_eq failed (recv_eq)");
-               goto out_free;
-       }
-
-       pr->send_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
-       if (!pr->send_eq) {
-               ehea_error("create_eq failed (send_eq)");
+       pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
+       if (!pr->eq) {
+               ehea_error("create_eq failed (eq)");
                goto out_free;
        }
 
        pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq,
-                                    pr->recv_eq->fw_handle,
+                                    pr->eq->fw_handle,
                                     port->logical_port_id);
        if (!pr->recv_cq) {
                ehea_error("create_cq failed (cq_recv)");
@@ -1129,7 +1125,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
        }
 
        pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq,
-                                    pr->send_eq->fw_handle,
+                                    pr->eq->fw_handle,
                                     port->logical_port_id);
        if (!pr->send_cq) {
                ehea_error("create_cq failed (cq_send)");
@@ -1194,11 +1190,20 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
                ret = -EIO;
                goto out_free;
        }
-       tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet,
-                    (unsigned long)pr);
+
        atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1);
 
        kfree(init_attr);
+
+       pr->d_netdev = alloc_netdev(0, "", ether_setup);
+       if (!pr->d_netdev)
+               goto out_free;
+       pr->d_netdev->priv = pr;
+       pr->d_netdev->weight = 64;
+       pr->d_netdev->poll = ehea_poll;
+       set_bit(__LINK_STATE_START, &pr->d_netdev->state);
+       strcpy(pr->d_netdev->name, port->netdev->name);
+
        ret = 0;
        goto out;
 
@@ -1211,8 +1216,7 @@ out_free:
        ehea_destroy_qp(pr->qp);
        ehea_destroy_cq(pr->send_cq);
        ehea_destroy_cq(pr->recv_cq);
-       ehea_destroy_eq(pr->send_eq);
-       ehea_destroy_eq(pr->recv_eq);
+       ehea_destroy_eq(pr->eq);
 out:
        return ret;
 }
@@ -1221,13 +1225,14 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
 {
        int ret, i;
 
+       free_netdev(pr->d_netdev);
+
        ret = ehea_destroy_qp(pr->qp);
 
        if (!ret) {
                ehea_destroy_cq(pr->send_cq);
                ehea_destroy_cq(pr->recv_cq);
-               ehea_destroy_eq(pr->send_eq);
-               ehea_destroy_eq(pr->recv_eq);
+               ehea_destroy_eq(pr->eq);
 
                for (i = 0; i < pr->rq1_skba.len; i++)
                        if (pr->rq1_skba.arr[i])
@@ -1792,6 +1797,22 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
        dev_kfree_skb(skb);
 }
 
+static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps)
+{
+       struct tcphdr *tcp;
+       u32 tmp;
+
+       if ((skb->protocol == htons(ETH_P_IP)) &&
+           (skb->nh.iph->protocol == IPPROTO_TCP)) {
+               tcp = (struct tcphdr*)(skb->nh.raw + (skb->nh.iph->ihl * 4));
+               tmp = (tcp->source + (tcp->dest << 16)) % 31;
+               tmp += skb->nh.iph->daddr % 31;
+               return tmp % num_qps;
+       }
+       else
+               return 0;
+}
+
 static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ehea_port *port = netdev_priv(dev);
@@ -1799,9 +1820,17 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned long flags;
        u32 lkey;
        int swqe_index;
-       struct ehea_port_res *pr = &port->port_res[0];
+       struct ehea_port_res *pr;
+
+       pr = &port->port_res[ehea_hash_skb(skb, port->num_tx_qps)];
 
-       spin_lock(&pr->xmit_lock);
+       if (!spin_trylock(&pr->xmit_lock))
+               return NETDEV_TX_BUSY;
+
+       if (pr->queue_stopped) {
+               spin_unlock(&pr->xmit_lock);
+               return NETDEV_TX_BUSY;
+       }
 
        swqe = ehea_get_swqe(pr->qp, &swqe_index);
        memset(swqe, 0, SWQE_HEADER_SIZE);
@@ -1824,6 +1853,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
                swqe->wr_id =
                        EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE)
                      | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter)
+                     | EHEA_BMASK_SET(EHEA_WR_ID_REFILL, 1)
                      | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index);
                pr->sq_skba.arr[pr->sq_skba.index] = skb;
 
@@ -1832,14 +1862,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
                lkey = pr->send_mr.lkey;
                ehea_xmit2(skb, dev, swqe, lkey);
-
-               if (pr->swqe_count >= (EHEA_SIG_IV_LONG - 1)) {
-                       swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL,
-                                                     EHEA_SIG_IV_LONG);
-                       swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
-                       pr->swqe_count = 0;
-               } else
-                       pr->swqe_count += 1;
+               swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
        }
        pr->swqe_id_counter += 1;
 
@@ -1859,6 +1882,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
                spin_lock_irqsave(&pr->netif_queue, flags);
                if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
+                       pr->p_stats.queue_stopped++;
                        netif_stop_queue(dev);
                        pr->queue_stopped = 1;
                }
@@ -2060,7 +2084,7 @@ static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
        }
 
        pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries;
-       pr_cfg.max_entries_scq = sq_entries;
+       pr_cfg.max_entries_scq = sq_entries * 2;
        pr_cfg.max_entries_sq = sq_entries;
        pr_cfg.max_entries_rq1 = rq1_entries;
        pr_cfg.max_entries_rq2 = rq2_entries;
@@ -2109,6 +2133,28 @@ static int ehea_clean_all_portres(struct ehea_port *port)
        return ret;
 }
 
+static void ehea_remove_adapter_mr (struct ehea_adapter *adapter)
+{
+       int i;
+
+       for (i=0; i < EHEA_MAX_PORTS; i++)
+               if (adapter->port[i])
+                       return;
+
+       ehea_rem_mr(&adapter->mr);
+}
+
+static int ehea_add_adapter_mr (struct ehea_adapter *adapter)
+{
+       int i;
+
+       for (i=0; i < EHEA_MAX_PORTS; i++)
+               if (adapter->port[i])
+                       return 0;
+
+       return ehea_reg_kernel_mr(adapter, &adapter->mr);
+}
+
 static int ehea_up(struct net_device *dev)
 {
        int ret, i;
@@ -2208,8 +2254,10 @@ static int ehea_down(struct net_device *dev)
        ehea_drop_multicast_list(dev);
        ehea_free_interrupts(dev);
 
-       for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
-               tasklet_kill(&port->port_res[i].send_comp_task);
+       for (i = 0; i < port->num_def_qps; i++)
+               while (test_bit(__LINK_STATE_RX_SCHED,
+                               &port->port_res[i].d_netdev->state))
+                       msleep(1);
 
        ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
        ret = ehea_clean_all_portres(port);
@@ -2276,8 +2324,6 @@ static void ehea_tx_watchdog(struct net_device *dev)
 int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
 {
        struct hcp_query_ehea *cb;
-       struct device_node *lhea_dn = NULL;
-       struct device_node *eth_dn = NULL;
        u64 hret;
        int ret;
 
@@ -2294,18 +2340,6 @@ int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
                goto out_herr;
        }
 
-       /* Determine the number of available logical ports
-        * by counting the child nodes of the lhea OFDT entry
-        */
-       adapter->num_ports = 0;
-       lhea_dn = of_find_node_by_name(lhea_dn, "lhea");
-       do {
-               eth_dn = of_get_next_child(lhea_dn, eth_dn);
-               if (eth_dn)
-                       adapter->num_ports++;
-       } while ( eth_dn );
-       of_node_put(lhea_dn);
-
        adapter->max_mc_mac = cb->max_mc_mac - 1;
        ret = 0;
 
@@ -2315,79 +2349,188 @@ out:
        return ret;
 }
 
-static int ehea_setup_single_port(struct ehea_port *port,
-                                 struct device_node *dn)
+int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo)
 {
-       int ret;
-       u64 hret;
-       struct net_device *dev = port->netdev;
-       struct ehea_adapter *adapter = port->adapter;
        struct hcp_ehea_port_cb4 *cb4;
-       u32 *dn_log_port_id;
-       int jumbo = 0;
-
-       sema_init(&port->port_lock, 1);
-       port->state = EHEA_PORT_DOWN;
-       port->sig_comp_iv = sq_entries / 10;
-
-       if (!dn) {
-               ehea_error("bad device node: dn=%p", dn);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       port->of_dev_node = dn;
-
-       /* Determine logical port id */
-       dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL);
-
-       if (!dn_log_port_id) {
-               ehea_error("bad device node: dn_log_port_id=%p",
-                          dn_log_port_id);
-               ret = -EINVAL;
-               goto out;
-       }
-       port->logical_port_id = *dn_log_port_id;
-
-       port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL);
-       if (!port->mc_list) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       INIT_LIST_HEAD(&port->mc_list->list);
+       u64 hret;
+       int ret = 0;
 
-       ret = ehea_sense_port_attr(port);
-       if (ret)
-               goto out;
+       *jumbo = 0;
 
-       /* Enable Jumbo frames */
+       /* (Try to) enable *jumbo frames */
        cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (!cb4) {
                ehea_error("no mem for cb4");
+               ret = -ENOMEM;
+               goto out;
        } else {
-               hret = ehea_h_query_ehea_port(adapter->handle,
+               hret = ehea_h_query_ehea_port(port->adapter->handle,
                                              port->logical_port_id,
                                              H_PORT_CB4,
                                              H_PORT_CB4_JUMBO, cb4);
-
                if (hret == H_SUCCESS) {
                        if (cb4->jumbo_frame)
-                               jumbo = 1;
+                               *jumbo = 1;
                        else {
                                cb4->jumbo_frame = 1;
-                               hret = ehea_h_modify_ehea_port(adapter->handle,
+                               hret = ehea_h_modify_ehea_port(port->adapter->
+                                                              handle,
                                                               port->
-                                                               logical_port_id,
+                                                              logical_port_id,
                                                               H_PORT_CB4,
                                                               H_PORT_CB4_JUMBO,
                                                               cb4);
                                if (hret == H_SUCCESS)
-                                       jumbo = 1;
+                                       *jumbo = 1;
                        }
-               }
+               } else
+                       ret = -EINVAL;
+
                kfree(cb4);
        }
+out:
+       return ret;
+}
+
+static ssize_t ehea_show_port_id(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
+       return sprintf(buf, "0x%X", port->logical_port_id);
+}
+
+static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id,
+                  NULL);
+
+static void __devinit logical_port_release(struct device *dev)
+{
+       struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
+       of_node_put(port->ofdev.node);
+}
+
+static int ehea_driver_sysfs_add(struct device *dev,
+                                 struct device_driver *driver)
+{
+       int ret;
+
+       ret = sysfs_create_link(&driver->kobj, &dev->kobj,
+                               kobject_name(&dev->kobj));
+       if (ret == 0) {
+               ret = sysfs_create_link(&dev->kobj, &driver->kobj,
+                                       "driver");
+               if (ret)
+                       sysfs_remove_link(&driver->kobj,
+                                         kobject_name(&dev->kobj));
+       }
+       return ret;
+}
+
+static void ehea_driver_sysfs_remove(struct device *dev,
+                                     struct device_driver *driver)
+{
+       struct device_driver *drv = driver;
+
+       if (drv) {
+               sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
+               sysfs_remove_link(&dev->kobj, "driver");
+       }
+}
+
+static struct device *ehea_register_port(struct ehea_port *port,
+                                        struct device_node *dn)
+{
+       int ret;
+
+       port->ofdev.node = of_node_get(dn);
+       port->ofdev.dev.parent = &port->adapter->ebus_dev->ofdev.dev;
+       port->ofdev.dev.bus = &ibmebus_bus_type;
+
+       sprintf(port->ofdev.dev.bus_id, "port%d", port_name_cnt++);
+       port->ofdev.dev.release = logical_port_release;
+
+       ret = of_device_register(&port->ofdev);
+       if (ret) {
+               ehea_error("failed to register device. ret=%d", ret);
+               goto out;
+       }
+
+       ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id);
+        if (ret) {
+               ehea_error("failed to register attributes, ret=%d", ret);
+               goto out_unreg_of_dev;
+       }
+
+       ret = ehea_driver_sysfs_add(&port->ofdev.dev, &ehea_driver.driver);
+       if (ret) {
+               ehea_error("failed to register sysfs driver link");
+               goto out_rem_dev_file;
+       }
+
+       return &port->ofdev.dev;
+
+out_rem_dev_file:
+       device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
+out_unreg_of_dev:
+       of_device_unregister(&port->ofdev);
+out:
+       return NULL;
+}
+
+static void ehea_unregister_port(struct ehea_port *port)
+{
+       ehea_driver_sysfs_remove(&port->ofdev.dev, &ehea_driver.driver);
+       device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
+       of_device_unregister(&port->ofdev);
+}
+
+struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
+                                        u32 logical_port_id,
+                                        struct device_node *dn)
+{
+       int ret;
+       struct net_device *dev;
+       struct ehea_port *port;
+       struct device *port_dev;
+       int jumbo;
+
+       /* allocate memory for the port structures */
+       dev = alloc_etherdev(sizeof(struct ehea_port));
+
+       if (!dev) {
+               ehea_error("no mem for net_device");
+               ret = -ENOMEM;
+               goto out_err;
+       }
+
+       port = netdev_priv(dev);
+
+       sema_init(&port->port_lock, 1);
+       port->state = EHEA_PORT_DOWN;
+       port->sig_comp_iv = sq_entries / 10;
+
+       port->adapter = adapter;
+       port->netdev = dev;
+       port->logical_port_id = logical_port_id;
+
+       port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT);
+
+       port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL);
+       if (!port->mc_list) {
+               ret = -ENOMEM;
+               goto out_free_ethdev;
+       }
+
+       INIT_LIST_HEAD(&port->mc_list->list);
+
+       ret = ehea_sense_port_attr(port);
+       if (ret)
+               goto out_free_mc_list;
+
+       port_dev = ehea_register_port(port, dn);
+       if (!port_dev)
+               goto out_free_mc_list;
+
+       SET_NETDEV_DEV(dev, port_dev);
 
        /* initialize net_device structure */
        SET_MODULE_OWNER(dev);
@@ -2420,84 +2563,225 @@ static int ehea_setup_single_port(struct ehea_port *port,
        ret = register_netdev(dev);
        if (ret) {
                ehea_error("register_netdev failed. ret=%d", ret);
-               goto out_free;
+               goto out_unreg_port;
        }
 
+       ret = ehea_get_jumboframe_status(port, &jumbo);
+       if (ret)
+               ehea_error("failed determining jumbo frame status for %s",
+                          port->netdev->name);
+
        ehea_info("%s: Jumbo frames are %sabled", dev->name,
                  jumbo == 1 ? "en" : "dis");
 
-       port->netdev = dev;
-       ret = 0;
-       goto out;
+       return port;
 
-out_free:
+out_unreg_port:
+       ehea_unregister_port(port);
+
+out_free_mc_list:
        kfree(port->mc_list);
-out:
-       return ret;
+
+out_free_ethdev:
+       free_netdev(dev);
+
+out_err:
+       ehea_error("setting up logical port with id=%d failed, ret=%d",
+                  logical_port_id, ret);
+       return NULL;
+}
+
+static void ehea_shutdown_single_port(struct ehea_port *port)
+{
+       unregister_netdev(port->netdev);
+       ehea_unregister_port(port);
+       kfree(port->mc_list);
+       free_netdev(port->netdev);
 }
 
 static int ehea_setup_ports(struct ehea_adapter *adapter)
 {
-       int ret;
-       int port_setup_ok = 0;
+       struct device_node *lhea_dn;
+       struct device_node *eth_dn = NULL;
+
+       u32 *dn_log_port_id;
+       int i = 0;
+
+       lhea_dn = adapter->ebus_dev->ofdev.node;
+       while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
+
+               dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no",
+                                                   NULL);
+               if (!dn_log_port_id) {
+                       ehea_error("bad device node: eth_dn name=%s",
+                                  eth_dn->full_name);
+                       continue;
+               }
+
+               if (ehea_add_adapter_mr(adapter)) {
+                       ehea_error("creating MR failed");
+                       of_node_put(eth_dn);
+                       return -EIO;
+               }
+
+               adapter->port[i] = ehea_setup_single_port(adapter,
+                                                         *dn_log_port_id,
+                                                         eth_dn);
+               if (adapter->port[i])
+                       ehea_info("%s -> logical port id #%d",
+                                 adapter->port[i]->netdev->name,
+                                 *dn_log_port_id);
+               else
+                       ehea_remove_adapter_mr(adapter);
+
+               i++;
+       };
+
+       return 0;
+}
+
+static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter,
+                                          u32 logical_port_id)
+{
+       struct device_node *lhea_dn;
+       struct device_node *eth_dn = NULL;
+       u32 *dn_log_port_id;
+
+       lhea_dn = adapter->ebus_dev->ofdev.node;
+       while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
+
+               dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no",
+                                                   NULL);
+               if (dn_log_port_id)
+                       if (*dn_log_port_id == logical_port_id)
+                               return eth_dn;
+       };
+
+       return NULL;
+}
+
+static ssize_t ehea_probe_port(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct ehea_adapter *adapter = dev->driver_data;
        struct ehea_port *port;
-       struct device_node *dn = NULL;
-       struct net_device *dev;
+       struct device_node *eth_dn = NULL;
        int i;
 
-       /* get port properties for all ports */
-       for (i = 0; i < adapter->num_ports; i++) {
+       u32 logical_port_id;
 
-               if (adapter->port[i])
-                       continue;       /* port already up and running */
+       sscanf(buf, "%X", &logical_port_id);
 
-               /* allocate memory for the port structures */
-               dev = alloc_etherdev(sizeof(struct ehea_port));
+       port = ehea_get_port(adapter, logical_port_id);
 
-               if (!dev) {
-                       ehea_error("no mem for net_device");
-                       break;
-               }
+       if (port) {
+               ehea_info("adding port with logical port id=%d failed. port "
+                         "already configured as %s.", logical_port_id,
+                         port->netdev->name);
+               return -EINVAL;
+       }
 
-               port = netdev_priv(dev);
-               port->adapter = adapter;
-               port->netdev = dev;
-               adapter->port[i] = port;
-               port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT);
+       eth_dn = ehea_get_eth_dn(adapter, logical_port_id);
 
-               dn = of_find_node_by_name(dn, "ethernet");
-               ret = ehea_setup_single_port(port, dn);
-               if (ret) {
-                       /* Free mem for this port struct. The others will be
-                          processed on rollback */
-                       free_netdev(dev);
-                       adapter->port[i] = NULL;
-                       ehea_error("eHEA port %d setup failed, ret=%d", i, ret);
-               }
+       if (!eth_dn) {
+               ehea_info("no logical port with id %d found", logical_port_id);
+               return -EINVAL;
        }
 
-       of_node_put(dn);
+       if (ehea_add_adapter_mr(adapter)) {
+               ehea_error("creating MR failed");
+               return -EIO;
+       }
 
-       /* Check for succesfully set up ports */
-       for (i = 0; i < adapter->num_ports; i++)
-               if (adapter->port[i])
-                       port_setup_ok++;
+       port = ehea_setup_single_port(adapter, logical_port_id, eth_dn);
 
-       if (port_setup_ok)
-               ret = 0;        /* At least some ports are setup correctly */
-       else
-               ret = -EINVAL;
+       of_node_put(eth_dn);
+
+       if (port) {
+               for (i=0; i < EHEA_MAX_PORTS; i++)
+                       if (!adapter->port[i]) {
+                               adapter->port[i] = port;
+                               break;
+                       }
+
+               ehea_info("added %s (logical port id=%d)", port->netdev->name,
+                         logical_port_id);
+       } else {
+               ehea_remove_adapter_mr(adapter);
+               return -EIO;
+       }
+
+       return (ssize_t) count;
+}
+
+static ssize_t ehea_remove_port(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct ehea_adapter *adapter = dev->driver_data;
+       struct ehea_port *port;
+       int i;
+       u32 logical_port_id;
+
+       sscanf(buf, "%X", &logical_port_id);
+
+       port = ehea_get_port(adapter, logical_port_id);
+
+       if (port) {
+               ehea_info("removed %s (logical port id=%d)", port->netdev->name,
+                         logical_port_id);
+
+               ehea_shutdown_single_port(port);
+
+               for (i=0; i < EHEA_MAX_PORTS; i++)
+                       if (adapter->port[i] == port) {
+                               adapter->port[i] = NULL;
+                               break;
+                       }
+       } else {
+               ehea_error("removing port with logical port id=%d failed. port "
+                          "not configured.", logical_port_id);
+               return -EINVAL;
+       }
+
+       ehea_remove_adapter_mr(adapter);
+
+       return (ssize_t) count;
+}
+
+static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port);
+static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port);
 
+int ehea_create_device_sysfs(struct ibmebus_dev *dev)
+{
+       int ret = device_create_file(&dev->ofdev.dev, &dev_attr_probe_port);
+       if (ret)
+               goto out;
+
+       ret = device_create_file(&dev->ofdev.dev, &dev_attr_remove_port);
+out:
        return ret;
 }
 
-static int __devinit ehea_probe(struct ibmebus_dev *dev,
-                               const struct of_device_id *id)
+void ehea_remove_device_sysfs(struct ibmebus_dev *dev)
+{
+       device_remove_file(&dev->ofdev.dev, &dev_attr_probe_port);
+       device_remove_file(&dev->ofdev.dev, &dev_attr_remove_port);
+}
+
+static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
+                                       const struct of_device_id *id)
 {
        struct ehea_adapter *adapter;
        u64 *adapter_handle;
        int ret;
 
+       if (!dev || !dev->ofdev.node) {
+               ehea_error("Invalid ibmebus device probed");
+               return -EINVAL;
+       }
+
        adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
        if (!adapter) {
                ret = -ENOMEM;
@@ -2505,6 +2789,8 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev,
                goto out;
        }
 
+       adapter->ebus_dev = dev;
+
        adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle",
                                            NULL);
        if (adapter_handle)
@@ -2521,26 +2807,21 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev,
 
        dev->ofdev.dev.driver_data = adapter;
 
-       ret = ehea_reg_mr_adapter(adapter);
-       if (ret) {
-               dev_err(&dev->ofdev.dev, "reg_mr_adapter failed\n");
-               goto out_free_ad;
-       }
 
        /* initialize adapter and ports */
        /* get adapter properties */
        ret = ehea_sense_adapter_attr(adapter);
        if (ret) {
                dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret);
-               goto out_free_res;
+               goto out_free_ad;
        }
-       dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports);
 
        adapter->neq = ehea_create_eq(adapter,
                                      EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1);
        if (!adapter->neq) {
+               ret = -EIO;
                dev_err(&dev->ofdev.dev, "NEQ creation failed");
-               goto out_free_res;
+               goto out_free_ad;
        }
 
        tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet,
@@ -2555,18 +2836,27 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev,
        }
 
        adapter->ehea_wq = create_workqueue("ehea_wq");
-       if (!adapter->ehea_wq)
+       if (!adapter->ehea_wq) {
+               ret = -EIO;
                goto out_free_irq;
+       }
+
+       ret = ehea_create_device_sysfs(dev);
+       if (ret)
+               goto out_kill_wq;
 
        ret = ehea_setup_ports(adapter);
        if (ret) {
                dev_err(&dev->ofdev.dev, "setup_ports failed");
-               goto out_kill_wq;
+               goto out_rem_dev_sysfs;
        }
 
        ret = 0;
        goto out;
 
+out_rem_dev_sysfs:
+       ehea_remove_device_sysfs(dev);
+
 out_kill_wq:
        destroy_workqueue(adapter->ehea_wq);
 
@@ -2576,45 +2866,32 @@ out_free_irq:
 out_kill_eq:
        ehea_destroy_eq(adapter->neq);
 
-out_free_res:
-       ehea_h_free_resource(adapter->handle, adapter->mr.handle);
-
 out_free_ad:
        kfree(adapter);
 out:
        return ret;
 }
 
-static void ehea_shutdown_single_port(struct ehea_port *port)
-{
-       unregister_netdev(port->netdev);
-       kfree(port->mc_list);
-       free_netdev(port->netdev);
-}
-
 static int __devexit ehea_remove(struct ibmebus_dev *dev)
 {
        struct ehea_adapter *adapter = dev->ofdev.dev.driver_data;
-       u64 hret;
        int i;
 
-       for (i = 0; i < adapter->num_ports; i++)
+       for (i = 0; i < EHEA_MAX_PORTS; i++)
                if (adapter->port[i]) {
                        ehea_shutdown_single_port(adapter->port[i]);
                        adapter->port[i] = NULL;
                }
+
+       ehea_remove_device_sysfs(dev);
+
        destroy_workqueue(adapter->ehea_wq);
 
        ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
        tasklet_kill(&adapter->neq_tasklet);
 
        ehea_destroy_eq(adapter->neq);
-
-       hret = ehea_h_free_resource(adapter->handle, adapter->mr.handle);
-       if (hret) {
-               dev_err(&dev->ofdev.dev, "free_resource_mr failed");
-               return -EIO;
-       }
+       ehea_remove_adapter_mr(adapter);
        kfree(adapter);
        return 0;
 }
@@ -2647,21 +2924,6 @@ static int check_module_parm(void)
        return ret;
 }
 
-static struct of_device_id ehea_device_table[] = {
-       {
-               .name = "lhea",
-               .compatible = "IBM,lhea",
-       },
-       {},
-};
-
-static struct ibmebus_driver ehea_driver = {
-       .name = "ehea",
-       .id_table = ehea_device_table,
-       .probe = ehea_probe,
-       .remove = ehea_remove,
-};
-
 int __init ehea_module_init(void)
 {
        int ret;
index bc3c005472642af53f72627c666911cf380c60f0..95c4a7f9cc88aacbaf64cbbbec35f089bcc2adbd 100644 (file)
@@ -478,12 +478,14 @@ u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle)
                                 0, 0, 0, 0, 0, 0);             /* R7-R12 */
 }
 
-u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle)
+u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
+                        u64 force_bit)
 {
        return ehea_plpar_hcall_norets(H_FREE_RESOURCE,
                                       adapter_handle,     /* R4 */
                                       res_handle,         /* R5 */
-                                      0, 0, 0, 0, 0);     /* R6-R10 */
+                                      force_bit,
+                                      0, 0, 0, 0);        /* R7-R10 */
 }
 
 u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
index 90acddb068a1ab819938631675c4db83ab01bda3..d17a45a7e71704c6e6c7430af3e384fe3fe321de 100644 (file)
@@ -414,7 +414,11 @@ u64 ehea_h_register_rpage(const u64 adapter_handle,
 
 u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle);
 
-u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle);
+#define FORCE_FREE 1
+#define NORMAL_FREE 0
+
+u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
+                        u64 force_bit);
 
 u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
                             const u64 length, const u32 access_ctrl,
index 96ff3b6799969d50c2cd9f13e6899c1f3f1e8993..f24a8862977ddda82589dc17c75fb4232f204dec 100644 (file)
@@ -197,7 +197,7 @@ out_kill_hwq:
        hw_queue_dtor(&cq->hw_queue);
 
 out_freeres:
-       ehea_h_free_resource(adapter->handle, cq->fw_handle);
+       ehea_h_free_resource(adapter->handle, cq->fw_handle, FORCE_FREE);
 
 out_freemem:
        kfree(cq);
@@ -206,25 +206,38 @@ out_nomem:
        return NULL;
 }
 
-int ehea_destroy_cq(struct ehea_cq *cq)
+u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
 {
-       u64 adapter_handle, hret;
+       u64 hret;
+       u64 adapter_handle = cq->adapter->handle;
+
+        /* deregister all previous registered pages */
+       hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force);
+       if (hret != H_SUCCESS)
+               return hret;
+
+       hw_queue_dtor(&cq->hw_queue);
+       kfree(cq);
+
+       return hret;
+}
 
+int ehea_destroy_cq(struct ehea_cq *cq)
+{
+       u64 hret;
        if (!cq)
                return 0;
 
-       adapter_handle = cq->adapter->handle;
+       if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) {
+               ehea_error_data(cq->adapter, cq->fw_handle);
+               hret = ehea_destroy_cq_res(cq, FORCE_FREE);
+       }
 
-       /* deregister all previous registered pages */
-       hret = ehea_h_free_resource(adapter_handle, cq->fw_handle);
        if (hret != H_SUCCESS) {
                ehea_error("destroy CQ failed");
                return -EIO;
        }
 
-       hw_queue_dtor(&cq->hw_queue);
-       kfree(cq);
-
        return 0;
 }
 
@@ -297,7 +310,7 @@ out_kill_hwq:
        hw_queue_dtor(&eq->hw_queue);
 
 out_freeres:
-       ehea_h_free_resource(adapter->handle, eq->fw_handle);
+       ehea_h_free_resource(adapter->handle, eq->fw_handle, FORCE_FREE);
 
 out_freemem:
        kfree(eq);
@@ -316,27 +329,41 @@ struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
        return eqe;
 }
 
-int ehea_destroy_eq(struct ehea_eq *eq)
+u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
 {
        u64 hret;
        unsigned long flags;
 
-       if (!eq)
-               return 0;
-
        spin_lock_irqsave(&eq->spinlock, flags);
 
-       hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle);
+       hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle, force);
        spin_unlock_irqrestore(&eq->spinlock, flags);
 
-       if (hret != H_SUCCESS) {
-               ehea_error("destroy_eq failed");
-               return -EIO;
-       }
+       if (hret != H_SUCCESS)
+               return hret;
 
        hw_queue_dtor(&eq->hw_queue);
        kfree(eq);
 
+       return hret;
+}
+
+int ehea_destroy_eq(struct ehea_eq *eq)
+{
+       u64 hret;
+       if (!eq)
+               return 0;
+
+       if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) {
+               ehea_error_data(eq->adapter, eq->fw_handle);
+               hret = ehea_destroy_eq_res(eq, FORCE_FREE);
+       }
+
+       if (hret != H_SUCCESS) {
+               ehea_error("destroy EQ failed");
+               return -EIO;
+        }
+
        return 0;
 }
 
@@ -471,41 +498,56 @@ out_kill_hwsq:
 
 out_freeres:
        ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle);
-       ehea_h_free_resource(adapter->handle, qp->fw_handle);
+       ehea_h_free_resource(adapter->handle, qp->fw_handle, FORCE_FREE);
 
 out_freemem:
        kfree(qp);
        return NULL;
 }
 
-int ehea_destroy_qp(struct ehea_qp *qp)
+u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
 {
-       u64 hret;
-       struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
+        u64 hret;
+        struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
 
-       if (!qp)
-               return 0;
 
-       ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
-       hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle);
-       if (hret != H_SUCCESS) {
-               ehea_error("destroy_qp failed");
-               return -EIO;
-       }
+        ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
+        hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force);
+        if (hret != H_SUCCESS)
+                return hret;
 
-       hw_queue_dtor(&qp->hw_squeue);
-       hw_queue_dtor(&qp->hw_rqueue1);
+        hw_queue_dtor(&qp->hw_squeue);
+        hw_queue_dtor(&qp->hw_rqueue1);
 
-       if (qp_attr->rq_count > 1)
-               hw_queue_dtor(&qp->hw_rqueue2);
-       if (qp_attr->rq_count > 2)
-               hw_queue_dtor(&qp->hw_rqueue3);
-       kfree(qp);
+        if (qp_attr->rq_count > 1)
+                hw_queue_dtor(&qp->hw_rqueue2);
+        if (qp_attr->rq_count > 2)
+                hw_queue_dtor(&qp->hw_rqueue3);
+        kfree(qp);
 
-       return 0;
+        return hret;
 }
 
-int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
+int ehea_destroy_qp(struct ehea_qp *qp)
+{
+        u64 hret;
+        if (!qp)
+                return 0;
+
+        if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
+                ehea_error_data(qp->adapter, qp->fw_handle);
+                hret = ehea_destroy_qp_res(qp, FORCE_FREE);
+        }
+
+        if (hret != H_SUCCESS) {
+                ehea_error("destroy QP failed");
+                return -EIO;
+        }
+
+        return 0;
+}
+
+int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
 {
        int i, k, ret;
        u64 hret, pt_abs, start, end, nr_pages;
@@ -526,14 +568,14 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
 
        hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start,
                                        acc_ctrl, adapter->pd,
-                                       &adapter->mr.handle, &adapter->mr.lkey);
+                                       &mr->handle, &mr->lkey);
        if (hret != H_SUCCESS) {
                ehea_error("alloc_resource_mr failed");
                ret = -EIO;
                goto out;
        }
 
-       adapter->mr.vaddr = KERNELBASE;
+       mr->vaddr = KERNELBASE;
        k = 0;
 
        while (nr_pages > 0) {
@@ -545,7 +587,7 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
                                                             EHEA_PAGESIZE)));
 
                        hret = ehea_h_register_rpage_mr(adapter->handle,
-                                                       adapter->mr.handle, 0,
+                                                       mr->handle, 0,
                                                        0, (u64)pt_abs,
                                                        num_pages);
                        nr_pages -= num_pages;
@@ -554,34 +596,68 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
                                                          (k * EHEA_PAGESIZE)));
 
                        hret = ehea_h_register_rpage_mr(adapter->handle,
-                                                       adapter->mr.handle, 0,
+                                                       mr->handle, 0,
                                                        0, abs_adr,1);
                        nr_pages--;
                }
 
                if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) {
                        ehea_h_free_resource(adapter->handle,
-                                               adapter->mr.handle);
-                       ehea_error("register_rpage_mr failed: hret = %lX",
-                                  hret);
+                                            mr->handle, FORCE_FREE);
+                       ehea_error("register_rpage_mr failed");
                        ret = -EIO;
                        goto out;
                }
        }
 
        if (hret != H_SUCCESS) {
-               ehea_h_free_resource(adapter->handle, adapter->mr.handle);
-               ehea_error("register_rpage failed for last page: hret = %lX",
-                          hret);
+               ehea_h_free_resource(adapter->handle, mr->handle,
+                                    FORCE_FREE);
+               ehea_error("register_rpage failed for last page");
                ret = -EIO;
                goto out;
        }
+
+       mr->adapter = adapter;
        ret = 0;
 out:
        kfree(pt);
        return ret;
 }
 
+int ehea_rem_mr(struct ehea_mr *mr)
+{
+       u64 hret;
+
+       if (!mr || !mr->adapter)
+               return -EINVAL;
+
+       hret = ehea_h_free_resource(mr->adapter->handle, mr->handle,
+                                   FORCE_FREE);
+       if (hret != H_SUCCESS) {
+               ehea_error("destroy MR failed");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
+                struct ehea_mr *shared_mr)
+{
+       u64 hret;
+
+       hret = ehea_h_register_smr(adapter->handle, old_mr->handle,
+                                  old_mr->vaddr, EHEA_MR_ACC_CTRL,
+                                  adapter->pd, shared_mr);
+       if (hret != H_SUCCESS)
+               return -EIO;
+
+       shared_mr->adapter = adapter;
+
+       return 0;
+}
+
 void print_error_data(u64 *data)
 {
        int length;
@@ -597,6 +673,14 @@ void print_error_data(u64 *data)
                ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, "
                           "port=%lX", resource, data[6], data[12], data[22]);
 
+       if (type == 0x4) /* Completion Queue */
+               ehea_error("CQ (resource=%lX) state: AER=0x%lX", resource,
+                          data[6]);
+
+       if (type == 0x3) /* Event Queue */
+               ehea_error("EQ (resource=%lX) state: AER=0x%lX", resource,
+                          data[6]);
+
        ehea_dump(data, length, "error data");
 }
 
index 1ff60983504d07385bed88e72dc3c7c65a3dd018..c0eb3e03a1021ddd4273bd473b9715fab603403c 100644 (file)
@@ -142,6 +142,8 @@ struct ehea_rwqe {
 #define EHEA_CQE_STAT_ERR_MASK     0x721F
 #define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F
 #define EHEA_CQE_STAT_ERR_TCP      0x4000
+#define EHEA_CQE_STAT_ERR_IP       0x2000
+#define EHEA_CQE_STAT_ERR_CRC      0x1000
 
 struct ehea_cqe {
        u64 wr_id;              /* work request ID from WQE */
@@ -320,6 +322,11 @@ static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index)
        return hw_qeit_get_valid(queue);
 }
 
+static inline void ehea_inc_cq(struct ehea_cq *cq)
+{
+       hw_qeit_inc(&cq->hw_queue);
+}
+
 static inline void ehea_inc_rq1(struct ehea_qp *qp)
 {
        hw_qeit_inc(&qp->hw_rqueue1);
@@ -327,7 +334,7 @@ static inline void ehea_inc_rq1(struct ehea_qp *qp)
 
 static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq)
 {
-       return hw_qeit_get_inc_valid(&my_cq->hw_queue);
+       return hw_qeit_get_valid(&my_cq->hw_queue);
 }
 
 #define EHEA_CQ_REGISTER_ORIG 0
@@ -356,7 +363,12 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter, u32 pd,
 
 int ehea_destroy_qp(struct ehea_qp *qp);
 
-int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
+int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr);
+
+int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
+                struct ehea_mr *shared_mr);
+
+int ehea_rem_mr(struct ehea_mr *mr);
 
 void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
 
index 30baf6ecfc63c6eabe38eaa2dfd40a4b68677148..17ac6975d70db9d0d1fdbe35487c03a2a1d1fa38 100644 (file)
@@ -415,11 +415,18 @@ static int ser12_open(struct net_device *dev)
 
        if (!dev || !bc)
                return -ENXIO;
-       if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT ||
-           dev->irq < 2 || dev->irq > 15)
+       if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT ||
+           dev->irq < 2 || dev->irq > NR_IRQS) {
+               printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) "
+                               "or irq (2 <= irq <= %d)\n",
+                               0xffff-SER12_EXTENT, NR_IRQS);
                return -ENXIO;
-       if (bc->baud < 300 || bc->baud > 4800)
+       }
+       if (bc->baud < 300 || bc->baud > 4800) {
+               printk(KERN_INFO "baycom_ser_fdx: invalid baudrate "
+                               "(300...4800)\n");
                return -EINVAL;
+       }
        if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) {
                printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy \n", 
                       dev->base_addr);
index 0573fcfcb2c4be181eff6f4b594647f90e02487c..3bec0f733f01e6a882bc60be9ee51cce807e965d 100644 (file)
@@ -93,7 +93,7 @@ static void ibmveth_proc_unregister_driver(void);
 static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter);
 static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter);
 static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance);
-static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
+static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
 static struct kobj_type ktype_veth_pool;
 
 #ifdef CONFIG_PROC_FS
@@ -389,7 +389,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
        }
 }
 
-static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
+static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
 {
        ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
 
@@ -953,14 +953,16 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
        ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n",
                                        dev->unit_address);
 
-       mac_addr_p = (unsigned char *) vio_get_attribute(dev, VETH_MAC_ADDR, 0);
+       mac_addr_p = (unsigned char *) vio_get_attribute(dev,
+                                               VETH_MAC_ADDR, NULL);
        if(!mac_addr_p) {
                printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR "
                                "attribute\n", __FILE__, __LINE__);
                return 0;
        }
 
-       mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0);
+       mcastFilterSize_p = (unsigned int *) vio_get_attribute(dev,
+                                               VETH_MCAST_FILTER_SIZE, NULL);
        if(!mcastFilterSize_p) {
                printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find "
                                "VETH_MCAST_FILTER_SIZE attribute\n",
index cf30a1059ce02f1808b4cd8251366df938958b35..c8e90861f8694ca5e64c961d195678c22a8f2ee6 100644 (file)
@@ -111,9 +111,6 @@ struct ixgb_adapter;
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
 #define IXGB_RX_BUFFER_WRITE   8       /* Must be power of 2 */
 
-/* only works for sizes that are powers of 2 */
-#define IXGB_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
-
 /* wrapper around a pointer to a socket buffer,
  * so a DMA handle can be stored along with the buffer */
 struct ixgb_buffer {
index d6628bd9590a0773a423e8f9389e42a83d57f44f..afde84868bea71376da126670765a68143074558 100644 (file)
@@ -577,11 +577,11 @@ ixgb_set_ringparam(struct net_device *netdev,
 
        rxdr->count = max(ring->rx_pending,(uint32_t)MIN_RXD);
        rxdr->count = min(rxdr->count,(uint32_t)MAX_RXD);
-       IXGB_ROUNDUP(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); 
+       rxdr->count = ALIGN(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
 
        txdr->count = max(ring->tx_pending,(uint32_t)MIN_TXD);
        txdr->count = min(txdr->count,(uint32_t)MAX_TXD);
-       IXGB_ROUNDUP(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); 
+       txdr->count = ALIGN(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
 
        if(netif_running(adapter->netdev)) {
                /* Try to get new resources before deleting old */
index dfde80e54aefc6d3545e819f150e3b226630f84f..6d2b059371f10bcf46fe20d6b343a4d4ee193ec3 100644 (file)
@@ -685,7 +685,7 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter)
        /* round up to nearest 4K */
 
        txdr->size = txdr->count * sizeof(struct ixgb_tx_desc);
-       IXGB_ROUNDUP(txdr->size, 4096);
+       txdr->size = ALIGN(txdr->size, 4096);
 
        txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
        if(!txdr->desc) {
@@ -774,7 +774,7 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter)
        /* Round up to nearest 4K */
 
        rxdr->size = rxdr->count * sizeof(struct ixgb_rx_desc);
-       IXGB_ROUNDUP(rxdr->size, 4096);
+       rxdr->size = ALIGN(rxdr->size, 4096);
 
        rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
 
index b27442a121f2fba05b388d0691c118c4170a0b78..5d5ddabf4360ccfdf6f15fb9c4600aa7c395933e 100644 (file)
@@ -245,8 +245,6 @@ ixgb_validate_option(int *value, struct ixgb_option *opt)
        return -1;
 }
 
-#define LIST_LEN(l) (sizeof(l) / sizeof(l[0]))
-
 /**
  * ixgb_check_options - Range Checking for Command Line Parameters
  * @adapter: board private structure
@@ -284,7 +282,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
                } else {
                        tx_ring->count = opt.def;
                }
-               IXGB_ROUNDUP(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
+               tx_ring->count = ALIGN(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
        }
        { /* Receive Descriptor Count */
                struct ixgb_option opt = {
@@ -303,7 +301,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
                } else {
                        rx_ring->count = opt.def;
                }
-               IXGB_ROUNDUP(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
+               rx_ring->count = ALIGN(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
        }
        { /* Receive Checksum Offload Enable */
                struct ixgb_option opt = {
@@ -335,7 +333,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
                        .name = "Flow Control",
                        .err  = "reading default settings from EEPROM",
                        .def  = ixgb_fc_tx_pause,
-                       .arg  = { .l = { .nr = LIST_LEN(fc_list),
+                       .arg  = { .l = { .nr = ARRAY_SIZE(fc_list),
                                         .p = fc_list }}
                };
 
index 2912a34f597bd9316a710eec336ef6c6680af23f..92056051f2691cd3fe94fa82603cc2a9849511f9 100644 (file)
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 
+/**
+ * mii_ethtool_gset - get settings that are specified in @ecmd
+ * @mii: MII interface
+ * @ecmd: requested ethtool_cmd
+ *
+ * Returns 0 for success, negative on error.
+ */
 int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
 {
        struct net_device *dev = mii->dev;
@@ -114,6 +121,13 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
        return 0;
 }
 
+/**
+ * mii_ethtool_sset - set settings that are specified in @ecmd
+ * @mii: MII interface
+ * @ecmd: requested ethtool_cmd
+ *
+ * Returns 0 for success, negative on error.
+ */
 int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
 {
        struct net_device *dev = mii->dev;
@@ -207,6 +221,10 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
        return 0;
 }
 
+/**
+ * mii_check_gmii_support - check if the MII supports Gb interfaces
+ * @mii: the MII interface
+ */
 int mii_check_gmii_support(struct mii_if_info *mii)
 {
        int reg;
@@ -221,6 +239,12 @@ int mii_check_gmii_support(struct mii_if_info *mii)
        return 0;
 }
 
+/**
+ * mii_link_ok - is link status up/ok
+ * @mii: the MII interface
+ *
+ * Returns 1 if the MII reports link status up/ok, 0 otherwise.
+ */
 int mii_link_ok (struct mii_if_info *mii)
 {
        /* first, a dummy read, needed to latch some MII phys */
@@ -230,6 +254,12 @@ int mii_link_ok (struct mii_if_info *mii)
        return 0;
 }
 
+/**
+ * mii_nway_restart - restart NWay (autonegotiation) for this interface
+ * @mii: the MII interface
+ *
+ * Returns 0 on success, negative on error.
+ */
 int mii_nway_restart (struct mii_if_info *mii)
 {
        int bmcr;
@@ -247,6 +277,14 @@ int mii_nway_restart (struct mii_if_info *mii)
        return r;
 }
 
+/**
+ * mii_check_link - check MII link status
+ * @mii: MII interface
+ *
+ * If the link status changed (previous != current), call
+ * netif_carrier_on() if current link status is Up or call
+ * netif_carrier_off() if current link status is Down.
+ */
 void mii_check_link (struct mii_if_info *mii)
 {
        int cur_link = mii_link_ok(mii);
@@ -258,6 +296,15 @@ void mii_check_link (struct mii_if_info *mii)
                netif_carrier_off(mii->dev);
 }
 
+/**
+ * mii_check_media - check the MII interface for a duplex change
+ * @mii: the MII interface
+ * @ok_to_print: OK to print link up/down messages
+ * @init_media: OK to save duplex mode in @mii
+ *
+ * Returns 1 if the duplex mode changed, 0 if not.
+ * If the media type is forced, always returns 0.
+ */
 unsigned int mii_check_media (struct mii_if_info *mii,
                              unsigned int ok_to_print,
                              unsigned int init_media)
@@ -326,6 +373,16 @@ unsigned int mii_check_media (struct mii_if_info *mii,
        return 0; /* duplex did not change */
 }
 
+/**
+ * generic_mii_ioctl - main MII ioctl interface
+ * @mii_if: the MII interface
+ * @mii_data: MII ioctl data structure
+ * @cmd: MII ioctl command
+ * @duplex_chg_out: pointer to @duplex_changed status if there was no
+ *     ioctl error
+ *
+ * Returns 0 on success, negative on error.
+ */
 int generic_mii_ioctl(struct mii_if_info *mii_if,
                      struct mii_ioctl_data *mii_data, int cmd,
                      unsigned int *duplex_chg_out)
index 403f63afd20125ea7df272e51e4eaafd7a6c8382..638a279ec5051823a96819a95163dbd4383af7d6 100644 (file)
@@ -26,8 +26,6 @@ struct mipsnet_priv {
        struct net_device_stats stats;
 };
 
-static struct platform_device *mips_plat_dev;
-
 static char mipsnet_string[] = "mipsnet";
 
 /*
@@ -297,64 +295,17 @@ static struct device_driver mipsnet_driver = {
        .remove = __devexit_p(mipsnet_device_remove),
 };
 
-static void mipsnet_platform_release(struct device *device)
-{
-       struct platform_device *pldev;
-
-       /* free device */
-       pldev = to_platform_device(device);
-       kfree(pldev);
-}
-
 static int __init mipsnet_init_module(void)
 {
-       struct platform_device *pldev;
        int err;
 
        printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. "
               "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION);
 
-       if (driver_register(&mipsnet_driver)) {
+       err = driver_register(&mipsnet_driver);
+       if (err)
                printk(KERN_ERR "Driver registration failed\n");
-               err = -ENODEV;
-               goto out;
-       }
-
-        if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) {
-               err = -ENOMEM;
-               goto out_unregister_driver;
-       }
-
-       memset (pldev, 0, sizeof (*pldev));
-       pldev->name             = mipsnet_string;
-       pldev->id               = 0;
-       pldev->dev.release      = mipsnet_platform_release;
 
-       if (platform_device_register(pldev)) {
-               err = -ENODEV;
-               goto out_free_pldev;
-       }
-
-        if (!pldev->dev.driver) {
-               /*
-                * The driver was not bound to this device, there was
-                 * no hardware at this address. Unregister it, as the
-                * release fuction will take care of freeing the
-                * allocated structure
-                */
-               platform_device_unregister (pldev);
-       }
-
-       mips_plat_dev           = pldev;
-
-       return 0;
-
-out_free_pldev:
-       kfree(pldev);
-
-out_unregister_driver:
-       driver_unregister(&mipsnet_driver);
-out:
        return err;
 }
 
index ab15ecd4b3d64411c7b2a8e5f322aa1a50985d68..1799eee88db7f81e3206f6372eb8119ba4ea883b 100644 (file)
@@ -51,8 +51,8 @@
 #include "mv643xx_eth.h"
 
 /* Static function declarations */
-static void eth_port_uc_addr_get(struct net_device *dev,
-                                               unsigned char *MacAddr);
+static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr);
+static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr);
 static void eth_port_set_multicast_list(struct net_device *);
 static void mv643xx_eth_port_enable_tx(unsigned int port_num,
                                                unsigned int queues);
@@ -1381,7 +1381,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
        port_num = mp->port_num = pd->port_number;
 
        /* set default config values */
-       eth_port_uc_addr_get(dev, dev->dev_addr);
+       eth_port_uc_addr_get(port_num, dev->dev_addr);
        mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
        mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE;
 
@@ -1839,26 +1839,9 @@ static void eth_port_start(struct net_device *dev)
 }
 
 /*
- * eth_port_uc_addr_set - This function Set the port Unicast address.
- *
- * DESCRIPTION:
- *             This function Set the port Ethernet MAC address.
- *
- * INPUT:
- *     unsigned int    eth_port_num    Port number.
- *     char *          p_addr          Address to be set
- *
- * OUTPUT:
- *     Set MAC address low and high registers. also calls
- *     eth_port_set_filter_table_entry() to set the unicast
- *     table with the proper information.
- *
- * RETURN:
- *     N/A.
- *
+ * eth_port_uc_addr_set - Write a MAC address into the port's hw registers
  */
-static void eth_port_uc_addr_set(unsigned int eth_port_num,
-                                                       unsigned char *p_addr)
+static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr)
 {
        unsigned int mac_h;
        unsigned int mac_l;
@@ -1868,40 +1851,24 @@ static void eth_port_uc_addr_set(unsigned int eth_port_num,
        mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) |
                                                        (p_addr[3] << 0);
 
-       mv_write(MV643XX_ETH_MAC_ADDR_LOW(eth_port_num), mac_l);
-       mv_write(MV643XX_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h);
+       mv_write(MV643XX_ETH_MAC_ADDR_LOW(port_num), mac_l);
+       mv_write(MV643XX_ETH_MAC_ADDR_HIGH(port_num), mac_h);
 
-       /* Accept frames of this address */
-       table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(eth_port_num);
+       /* Accept frames with this address */
+       table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(port_num);
        eth_port_set_filter_table_entry(table, p_addr[5] & 0x0f);
 }
 
 /*
- * eth_port_uc_addr_get - This function retrieves the port Unicast address
- * (MAC address) from the ethernet hw registers.
- *
- * DESCRIPTION:
- *             This function retrieves the port Ethernet MAC address.
- *
- * INPUT:
- *     unsigned int    eth_port_num    Port number.
- *     char            *MacAddr        pointer where the MAC address is stored
- *
- * OUTPUT:
- *     Copy the MAC address to the location pointed to by MacAddr
- *
- * RETURN:
- *     N/A.
- *
+ * eth_port_uc_addr_get - Read the MAC address from the port's hw registers
  */
-static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *p_addr)
+static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr)
 {
-       struct mv643xx_private *mp = netdev_priv(dev);
        unsigned int mac_h;
        unsigned int mac_l;
 
-       mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(mp->port_num));
-       mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(mp->port_num));
+       mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(port_num));
+       mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(port_num));
 
        p_addr[0] = (mac_h >> 24) & 0xff;
        p_addr[1] = (mac_h >> 16) & 0xff;
index 7d4e90cf49e8704f797c7f142570693a370a4826..82f8c0cbfb640fafd0e90b8a429e0283ed6622f3 100644 (file)
@@ -346,10 +346,6 @@ static void eth_port_init(struct mv643xx_private *mp);
 static void eth_port_reset(unsigned int eth_port_num);
 static void eth_port_start(struct net_device *dev);
 
-/* Port MAC address routines */
-static void eth_port_uc_addr_set(unsigned int eth_port_num,
-                                unsigned char *p_addr);
-
 /* PHY and MIB routines */
 static void ethernet_phy_reset(unsigned int eth_port_num);
 
index dd8ce35332fefd297bbea28a8f19d003f4cfd118..ad6688eab265f741c5e3b8b385b40c35fdc7fd17 100644 (file)
@@ -64,9 +64,9 @@
 #include "netxen_nic_hw.h"
 
 #define _NETXEN_NIC_LINUX_MAJOR 3
-#define _NETXEN_NIC_LINUX_MINOR 3
-#define _NETXEN_NIC_LINUX_SUBVERSION 3
-#define NETXEN_NIC_LINUX_VERSIONID  "3.3.3"
+#define _NETXEN_NIC_LINUX_MINOR 4
+#define _NETXEN_NIC_LINUX_SUBVERSION 2
+#define NETXEN_NIC_LINUX_VERSIONID  "3.4.2"
 
 #define NUM_FLASH_SECTORS (64)
 #define FLASH_SECTOR_SIZE (64 * 1024)
@@ -131,8 +131,8 @@ extern struct workqueue_struct *netxen_workq;
 #define FIRST_PAGE_GROUP_START 0
 #define FIRST_PAGE_GROUP_END   0x100000
 
-#define SECOND_PAGE_GROUP_START        0x4000000
-#define SECOND_PAGE_GROUP_END  0x66BC000
+#define SECOND_PAGE_GROUP_START        0x6000000
+#define SECOND_PAGE_GROUP_END  0x68BC000
 
 #define THIRD_PAGE_GROUP_START 0x70E4000
 #define THIRD_PAGE_GROUP_END   0x8000000
@@ -205,6 +205,8 @@ enum {
 
 #define MAX_CMD_DESCRIPTORS            1024
 #define MAX_RCV_DESCRIPTORS            16384
+#define MAX_CMD_DESCRIPTORS_HOST       (MAX_CMD_DESCRIPTORS / 4)
+#define MAX_RCV_DESCRIPTORS_1G         (MAX_RCV_DESCRIPTORS / 4)
 #define MAX_JUMBO_RCV_DESCRIPTORS      1024
 #define MAX_LRO_RCV_DESCRIPTORS                64
 #define MAX_RCVSTATUS_DESCRIPTORS      MAX_RCV_DESCRIPTORS
@@ -230,7 +232,9 @@ enum {
        (((index) + (count)) & ((length) - 1))
 
 #define MPORT_SINGLE_FUNCTION_MODE 0x1111
+#define MPORT_MULTI_FUNCTION_MODE 0x2222
 
+#include "netxen_nic_phan_reg.h"
 extern unsigned long long netxen_dma_mask;
 extern unsigned long last_schedule_time;
 
@@ -300,6 +304,8 @@ struct netxen_ring_ctx {
 
 #define netxen_set_cmd_desc_port(cmd_desc, var)        \
        ((cmd_desc)->port_ctxid |= ((var) & 0x0F))
+#define netxen_set_cmd_desc_ctxid(cmd_desc, var)       \
+       ((cmd_desc)->port_ctxid |= ((var) & 0xF0))
 
 #define netxen_set_cmd_desc_flags(cmd_desc, val)       \
        ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x7f), \
@@ -442,7 +448,7 @@ struct status_desc {
        /* Bit pattern: 0-6 lro_count indicates frag sequence,
           7 last_frag indicates last frag */
        u8 lro;
-} __attribute__ ((aligned(8)));
+} __attribute__ ((aligned(16)));
 
 enum {
        NETXEN_RCV_PEG_0 = 0,
@@ -703,10 +709,8 @@ extern char netxen_nic_driver_name[];
 #else
 #define DPRINTK(klevel, fmt, args...)  do { \
        printk(KERN_##klevel PFX "%s: %s: " fmt, __FUNCTION__,\
-               (adapter != NULL && \
-               adapter->port[0] != NULL && \
-               adapter->port[0]->netdev != NULL) ? \
-               adapter->port[0]->netdev->name : NULL, \
+               (adapter != NULL && adapter->netdev != NULL) ? \
+               adapter->netdev->name : NULL, \
                ## args); } while(0)
 #endif
 
@@ -722,6 +726,18 @@ struct netxen_skb_frag {
        u32 length;
 };
 
+#define _netxen_set_bits(config_word, start, bits, val)        {\
+       unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));\
+       unsigned long long __tvalue = (val);    \
+       (config_word) &= ~__tmask;      \
+       (config_word) |= (((__tvalue) << (start)) & __tmask); \
+}
+       
+#define _netxen_clear_bits(config_word, start, bits) {\
+       unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));  \
+       (config_word) &= ~__tmask; \
+}              
+
 /*    Following defines are for the state of the buffers    */
 #define        NETXEN_BUFFER_FREE      0
 #define        NETXEN_BUFFER_BUSY      1
@@ -766,6 +782,8 @@ struct netxen_hardware_context {
        void __iomem *pci_base0;
        void __iomem *pci_base1;
        void __iomem *pci_base2;
+       unsigned long first_page_group_end;
+       unsigned long first_page_group_start;
        void __iomem *db_base;
        unsigned long db_len;
 
@@ -780,6 +798,7 @@ struct netxen_hardware_context {
        struct pci_dev *cmd_desc_pdev;
        dma_addr_t cmd_desc_phys_addr;
        struct netxen_adapter *adapter;
+       int pci_func;
 };
 
 #define RCV_RING_LRO   RCV_DESC_LRO
@@ -788,17 +807,27 @@ struct netxen_hardware_context {
 #define ETHERNET_FCS_SIZE              4
 
 struct netxen_adapter_stats {
-       u64 ints;
-       u64 hostints;
-       u64 otherints;
-       u64 process_rcv;
-       u64 process_xmit;
-       u64 noxmitdone;
-       u64 xmitcsummed;
-       u64 post_called;
-       u64 posted;
-       u64 lastposted;
-       u64 goodskbposts;
+       u64  rcvdbadskb;
+       u64  xmitcalled;
+       u64  xmitedframes;
+       u64  xmitfinished;
+       u64  badskblen;
+       u64  nocmddescriptor;
+       u64  polled;
+       u64  uphappy;
+       u64  updropped;
+       u64  uplcong;
+       u64  uphcong;
+       u64  upmcong;
+       u64  updunno;
+       u64  skbfreed;
+       u64  txdropped;
+       u64  txnullskb;
+       u64  csummed;
+       u64  no_rcv;
+       u64  rxbytes;
+       u64  txbytes;
+       u64  ints;
 };
 
 /*
@@ -846,13 +875,20 @@ struct netxen_dummy_dma {
 
 struct netxen_adapter {
        struct netxen_hardware_context ahw;
-       int port_count;         /* Number of configured ports  */
-       int active_ports;       /* Number of open ports */
-       struct netxen_port *port[NETXEN_MAX_PORTS];     /* ptr to each port  */
+       
+       struct netxen_adapter *master;
+       struct net_device *netdev;
+       struct pci_dev *pdev;
+       struct net_device_stats net_stats;
+       unsigned char mac_addr[ETH_ALEN];
+       int mtu;
+       int portnum;
+
        spinlock_t tx_lock;
        spinlock_t lock;
        struct work_struct watchdog_task;
        struct timer_list watchdog_timer;
+       struct work_struct  tx_timeout_task;
 
        u32 curr_window;
 
@@ -875,6 +911,15 @@ struct netxen_adapter {
        u32 temp;
 
        struct netxen_adapter_stats stats;
+       
+       u16 portno;
+       u16 link_speed;
+       u16 link_duplex;
+       u16 state;
+       u16 link_autoneg;
+       int rcsum;
+       int status;
+       spinlock_t stats_lock;
 
        struct netxen_cmd_buffer *cmd_buf_arr;  /* Command buffers for xmit */
 
@@ -891,65 +936,23 @@ struct netxen_adapter {
        struct netxen_ring_ctx *ctx_desc;
        struct pci_dev *ctx_desc_pdev;
        dma_addr_t ctx_desc_phys_addr;
-       int (*enable_phy_interrupts) (struct netxen_adapter *, int);
-       int (*disable_phy_interrupts) (struct netxen_adapter *, int);
+       int (*enable_phy_interrupts) (struct netxen_adapter *);
+       int (*disable_phy_interrupts) (struct netxen_adapter *);
        void (*handle_phy_intr) (struct netxen_adapter *);
-       int (*macaddr_set) (struct netxen_port *, netxen_ethernet_macaddr_t);
-       int (*set_mtu) (struct netxen_port *, int);
-       int (*set_promisc) (struct netxen_adapter *, int,
-                           netxen_niu_prom_mode_t);
-       int (*unset_promisc) (struct netxen_adapter *, int,
-                             netxen_niu_prom_mode_t);
-       int (*phy_read) (struct netxen_adapter *, long phy, long reg, u32 *);
-       int (*phy_write) (struct netxen_adapter *, long phy, long reg, u32 val);
+       int (*macaddr_set) (struct netxen_adapter *, netxen_ethernet_macaddr_t);
+       int (*set_mtu) (struct netxen_adapter *, int);
+       int (*set_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t);
+       int (*unset_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t);
+       int (*phy_read) (struct netxen_adapter *, long reg, u32 *);
+       int (*phy_write) (struct netxen_adapter *, long reg, u32 val);
        int (*init_port) (struct netxen_adapter *, int);
        void (*init_niu) (struct netxen_adapter *);
-       int (*stop_port) (struct netxen_adapter *, int);
+       int (*stop_port) (struct netxen_adapter *);
 };                             /* netxen_adapter structure */
 
 /* Max number of xmit producer threads that can run simultaneously */
 #define        MAX_XMIT_PRODUCERS              16
 
-struct netxen_port_stats {
-       u64 rcvdbadskb;
-       u64 xmitcalled;
-       u64 xmitedframes;
-       u64 xmitfinished;
-       u64 badskblen;
-       u64 nocmddescriptor;
-       u64 polled;
-       u64 uphappy;
-       u64 updropped;
-       u64 uplcong;
-       u64 uphcong;
-       u64 upmcong;
-       u64 updunno;
-       u64 skbfreed;
-       u64 txdropped;
-       u64 txnullskb;
-       u64 csummed;
-       u64 no_rcv;
-       u64 rxbytes;
-       u64 txbytes;
-};
-
-struct netxen_port {
-       struct netxen_adapter *adapter;
-
-       u16 portnum;            /* GBE port number */
-       u16 link_speed;
-       u16 link_duplex;
-       u16 link_autoneg;
-
-       int flags;
-
-       struct net_device *netdev;
-       struct pci_dev *pdev;
-       struct net_device_stats net_stats;
-       struct netxen_port_stats stats;
-       struct work_struct tx_timeout_task;
-};
-
 #define PCI_OFFSET_FIRST_RANGE(adapter, off)    \
        ((adapter)->ahw.pci_base0 + (off))
 #define PCI_OFFSET_SECOND_RANGE(adapter, off)   \
@@ -987,32 +990,26 @@ static inline void __iomem *pci_base(struct netxen_adapter *adapter,
        return NULL;
 }
 
-int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter,
-                                         int port);
-int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
-                                        int port);
-int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter,
-                                          int port);
-int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter,
-                                         int port);
-int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter,
-                                        int port);
-int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter,
-                                       int port);
+int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter);
 void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter);
 void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter);
 void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port,
                                 long enable);
 void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port,
                                  long enable);
-int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, long reg,
+int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
                            __u32 * readval);
-int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long phy,
+int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
                             long reg, __u32 val);
 
 /* Functions available from netxen_nic_hw.c */
-int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu);
-int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu);
+int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu);
+int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu);
 void netxen_nic_init_niu_gb(struct netxen_adapter *adapter);
 void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw);
 void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val);
@@ -1027,6 +1024,7 @@ int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data,
                           int len);
 void netxen_crb_writelit_adapter(struct netxen_adapter *adapter,
                                 unsigned long off, int data);
+int netxen_nic_erase_pxe(struct netxen_adapter *adapter);
 
 /* Functions from netxen_nic_init.c */
 void netxen_free_adapter_offload(struct netxen_adapter *adapter);
@@ -1051,11 +1049,8 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr);
 
 /* Functions from netxen_nic_isr.c */
 void netxen_nic_isr_other(struct netxen_adapter *adapter);
-void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 port,
-                                u32 link);
-void netxen_handle_port_int(struct netxen_adapter *adapter, u32 port,
-                           u32 enable);
-void netxen_nic_stop_all_ports(struct netxen_adapter *adapter);
+void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link);
+void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable);
 void netxen_initialize_adapter_sw(struct netxen_adapter *adapter);
 void netxen_initialize_adapter_hw(struct netxen_adapter *adapter);
 void *netxen_alloc(struct pci_dev *pdev, size_t sz, dma_addr_t * ptr,
@@ -1110,6 +1105,7 @@ static inline void netxen_nic_enable_int(struct netxen_adapter *adapter)
 
        if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
                mask = 0xbff;
+               writel(0X0, NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
                writel(mask, PCI_OFFSET_SECOND_RANGE(adapter,
                                                     ISR_INT_TARGET_MASK));
        }
@@ -1174,4 +1170,5 @@ extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr,
 
 extern struct ethtool_ops netxen_nic_ethtool_ops;
 
+extern int physical_port[];    /* physical port # from virtual port.*/
 #endif                         /* __NETXEN_NIC_H_ */
index ee1b5a24cbe7bbe7457528bdda7a0a5b4cb7feb3..16fabb377488977646ff83906424196c44003bd7 100644 (file)
@@ -40,8 +40,8 @@
 #include <linux/ethtool.h>
 #include <linux/version.h>
 
-#include "netxen_nic_hw.h"
 #include "netxen_nic.h"
+#include "netxen_nic_hw.h"
 #include "netxen_nic_phan_reg.h"
 
 struct netxen_nic_stats {
@@ -50,8 +50,8 @@ struct netxen_nic_stats {
        int stat_offset;
 };
 
-#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_port *)0)->m), \
-                       offsetof(struct netxen_port, m)
+#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_adapter *)0)->m), \
+                       offsetof(struct netxen_adapter, m)
 
 #define NETXEN_NIC_PORT_WINDOW 0x10000
 #define NETXEN_NIC_INVALID_DATA 0xDEADBEEF
@@ -100,8 +100,7 @@ static int netxen_nic_get_eeprom_len(struct net_device *dev)
 static void
 netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(dev);
        u32 fw_major = 0;
        u32 fw_minor = 0;
        u32 fw_build = 0;
@@ -115,7 +114,7 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
        fw_build = readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_SUB));
        sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
 
-       strncpy(drvinfo->bus_info, pci_name(port->pdev), 32);
+       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
        drvinfo->n_stats = NETXEN_NIC_STATS_LEN;
        drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN;
        drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
@@ -125,8 +124,7 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
 static int
 netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(dev);
        struct netxen_board_info *boardinfo = &adapter->ahw.boardcfg;
 
        /* read which mode */
@@ -146,8 +144,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                ecmd->port = PORT_TP;
 
                if (netif_running(dev)) {
-                       ecmd->speed = port->link_speed;
-                       ecmd->duplex = port->link_duplex;
+                       ecmd->speed = adapter->link_speed;
+                       ecmd->duplex = adapter->link_duplex;
                } else
                        return -EIO;    /* link absent */
        } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
@@ -165,7 +163,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
        } else
                return -EIO;
 
-       ecmd->phy_address = port->portnum;
+       ecmd->phy_address = adapter->portnum;
        ecmd->transceiver = XCVR_EXTERNAL;
 
        switch ((netxen_brdtype_t) boardinfo->board_type) {
@@ -179,7 +177,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                ecmd->port = PORT_TP;
                ecmd->autoneg = (boardinfo->board_type ==
                                 NETXEN_BRDTYPE_P2_SB31_10G_CX4) ?
-                   (AUTONEG_DISABLE) : (port->link_autoneg);
+                   (AUTONEG_DISABLE) : (adapter->link_autoneg);
                break;
        case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
        case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
@@ -206,23 +204,22 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 static int
 netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(dev);
        __u32 status;
 
        /* read which mode */
        if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
                /* autonegotiation */
                if (adapter->phy_write
-                   && adapter->phy_write(adapter, port->portnum,
+                   && adapter->phy_write(adapter,
                                          NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
                                          ecmd->autoneg) != 0)
                        return -EIO;
                else
-                       port->link_autoneg = ecmd->autoneg;
+                       adapter->link_autoneg = ecmd->autoneg;
 
                if (adapter->phy_read
-                   && adapter->phy_read(adapter, port->portnum,
+                   && adapter->phy_read(adapter,
                                         NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
                                         &status) != 0)
                        return -EIO;
@@ -245,13 +242,13 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                if (ecmd->duplex == DUPLEX_FULL)
                        netxen_set_phy_duplex(status);
                if (adapter->phy_write
-                   && adapter->phy_write(adapter, port->portnum,
+                   && adapter->phy_write(adapter,
                                          NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
                                          *((int *)&status)) != 0)
                        return -EIO;
                else {
-                       port->link_speed = ecmd->speed;
-                       port->link_duplex = ecmd->duplex;
+                       adapter->link_speed = ecmd->speed;
+                       adapter->link_duplex = ecmd->duplex;
                }
        } else
                return -EOPNOTSUPP;
@@ -360,15 +357,14 @@ static struct netxen_niu_regs niu_registers[] = {
 static void
 netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(dev);
        __u32 mode, *regs_buff = p;
        void __iomem *addr;
        int i, window;
 
        memset(p, 0, NETXEN_NIC_REGS_LEN);
        regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) |
-           (port->pdev)->device;
+           (adapter->pdev)->device;
        /* which mode */
        NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_MODE, &regs_buff[0]);
        mode = regs_buff[0];
@@ -383,7 +379,8 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
                for (i = 3; niu_registers[mode].reg[i - 3] != -1; i++) {
                        /* GB: port specific registers */
                        if (mode == 0 && i >= 19)
-                               window = port->portnum * NETXEN_NIC_PORT_WINDOW;
+                               window = physical_port[adapter->portnum] *
+                                       NETXEN_NIC_PORT_WINDOW;
 
                        NETXEN_NIC_LOCKED_READ_REG(niu_registers[mode].
                                                   reg[i - 3] + window,
@@ -395,15 +392,14 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
 
 static u32 netxen_nic_test_link(struct net_device *dev)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(dev);
        __u32 status;
        int val;
 
        /* read which mode */
        if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
                if (adapter->phy_read
-                   && adapter->phy_read(adapter, port->portnum,
+                   && adapter->phy_read(adapter,
                                         NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
                                         &status) != 0)
                        return -EIO;
@@ -422,15 +418,15 @@ static int
 netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                      u8 * bytes)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(dev);
        int offset;
        int ret;
 
        if (eeprom->len == 0)
                return -EINVAL;
 
-       eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16);
+       eeprom->magic = (adapter->pdev)->vendor | 
+                       ((adapter->pdev)->device << 16);
        offset = eeprom->offset;
 
        ret = netxen_rom_fast_read_words(adapter, offset, bytes, 
@@ -445,8 +441,7 @@ static int
 netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                        u8 * bytes)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(dev);
        int offset = eeprom->offset;
        static int flash_start;
        static int ready_to_flash;
@@ -516,8 +511,7 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 static void
 netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(dev);
        int i;
 
        ring->rx_pending = 0;
@@ -541,19 +535,45 @@ static void
 netxen_nic_get_pauseparam(struct net_device *dev,
                          struct ethtool_pauseparam *pause)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(dev);
        __u32 val;
+       int port = physical_port[adapter->portnum];
 
        if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+               if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+                       return;
                /* get flow control settings */
-               netxen_nic_read_w0(adapter,
-                                  NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
-                                  &val);
+               netxen_nic_read_w0(adapter,NETXEN_NIU_GB_MAC_CONFIG_0(port),
+                               &val);
                pause->rx_pause = netxen_gb_get_rx_flowctl(val);
-               pause->tx_pause = netxen_gb_get_tx_flowctl(val);
-               /* get autoneg settings */
-               pause->autoneg = port->link_autoneg;
+               netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val);
+               switch (port) {
+                       case 0:
+                               pause->tx_pause = !(netxen_gb_get_gb0_mask(val));
+                               break;
+                       case 1:
+                               pause->tx_pause = !(netxen_gb_get_gb1_mask(val));
+                               break;
+                       case 2:
+                               pause->tx_pause = !(netxen_gb_get_gb2_mask(val));
+                               break;
+                       case 3:
+                       default:
+                               pause->tx_pause = !(netxen_gb_get_gb3_mask(val));
+                               break;
+               }
+       } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+               if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
+                       return;
+               pause->rx_pause = 1;
+               netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val);
+               if (port == 0)
+                       pause->tx_pause = !(netxen_xg_get_xg0_mask(val));
+               else
+                       pause->tx_pause = !(netxen_xg_get_xg1_mask(val));
+       } else {
+               printk(KERN_ERR"%s: Unknown board type: %x\n", 
+                               netxen_nic_driver_name, adapter->ahw.board_type);
        }
 }
 
@@ -561,42 +581,76 @@ static int
 netxen_nic_set_pauseparam(struct net_device *dev,
                          struct ethtool_pauseparam *pause)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(dev);
        __u32 val;
-       unsigned int autoneg;
-
+       int port = physical_port[adapter->portnum];
        /* read mode */
        if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+               if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+                       return -EIO;
                /* set flow control */
                netxen_nic_read_w0(adapter,
-                                  NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
-                                  (u32 *) & val);
-               if (pause->tx_pause)
-                       netxen_gb_tx_flowctl(val);
-               else
-                       netxen_gb_unset_tx_flowctl(val);
+                                       NETXEN_NIU_GB_MAC_CONFIG_0(port), &val);
+               
                if (pause->rx_pause)
                        netxen_gb_rx_flowctl(val);
                else
                        netxen_gb_unset_rx_flowctl(val);
 
-               netxen_nic_write_w0(adapter,
-                                   NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
-                                   *&val);
+               netxen_nic_write_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+                               val);
                /* set autoneg */
-               autoneg = pause->autoneg;
-               if (adapter->phy_write
-                   && adapter->phy_write(adapter, port->portnum,
-                                         NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
-                                         autoneg) != 0)
+               netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val);
+               switch (port) {
+                       case 0:
+                               if (pause->tx_pause)
+                                       netxen_gb_unset_gb0_mask(val);
+                               else
+                                       netxen_gb_set_gb0_mask(val);
+                               break;
+                       case 1:
+                               if (pause->tx_pause)
+                                       netxen_gb_unset_gb1_mask(val);
+                               else
+                                       netxen_gb_set_gb1_mask(val);
+                               break;
+                       case 2:
+                               if (pause->tx_pause)
+                                       netxen_gb_unset_gb2_mask(val);
+                               else
+                                       netxen_gb_set_gb2_mask(val);
+                               break;
+                       case 3:
+                       default:
+                               if (pause->tx_pause)
+                                       netxen_gb_unset_gb3_mask(val);
+                               else
+                                       netxen_gb_set_gb3_mask(val);
+                               break;
+               }
+               netxen_nic_write_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, val);
+       } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+               if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
                        return -EIO;
-               else {
-                       port->link_autoneg = pause->autoneg;
-                       return 0;
+               netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val);
+               if (port == 0) {
+                       if (pause->tx_pause)
+                               netxen_xg_unset_xg0_mask(val);
+                       else
+                               netxen_xg_set_xg0_mask(val);
+               } else {
+                       if (pause->tx_pause)
+                               netxen_xg_unset_xg1_mask(val);
+                       else
+                               netxen_xg_set_xg1_mask(val);
                }
-       } else
-               return -EOPNOTSUPP;
+               netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val);                     
+       } else {
+               printk(KERN_ERR "%s: Unknown board type: %x\n",
+                               netxen_nic_driver_name, 
+                               adapter->ahw.board_type);
+       }
+       return 0;
 }
 
 static int netxen_nic_reg_test(struct net_device *dev)
@@ -627,23 +681,12 @@ static void
 netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
                     u64 * data)
 {
-       if (eth_test->flags == ETH_TEST_FL_OFFLINE) {   /* offline tests */
-               /* link test */
-               if ((data[1] = (u64) netxen_nic_test_link(dev)))
-                       eth_test->flags |= ETH_TEST_FL_FAILED;
-
-               /* register tests */
-               if ((data[0] = netxen_nic_reg_test(dev)))
-                       eth_test->flags |= ETH_TEST_FL_FAILED;
-       } else {                /* online tests */
-               /* register tests */
-               if((data[0] = netxen_nic_reg_test(dev)))
-                       eth_test->flags |= ETH_TEST_FL_FAILED;
-
-               /* link test */
-               if ((data[1] = (u64) netxen_nic_test_link(dev)))
-                       eth_test->flags |= ETH_TEST_FL_FAILED;
-       }
+       memset(data, 0, sizeof(uint64_t) * NETXEN_NIC_TEST_LEN);
+       if ((data[0] = netxen_nic_reg_test(dev)))
+               eth_test->flags |= ETH_TEST_FL_FAILED;
+       /* link test */
+       if ((data[1] = (u64) netxen_nic_test_link(dev)))
+               eth_test->flags |= ETH_TEST_FL_FAILED;
 }
 
 static void
@@ -675,12 +718,13 @@ static void
 netxen_nic_get_ethtool_stats(struct net_device *dev,
                             struct ethtool_stats *stats, u64 * data)
 {
-       struct netxen_port *port = netdev_priv(dev);
+       struct netxen_adapter *adapter = netdev_priv(dev);
        int index;
 
        for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) {
                char *p =
-                   (char *)port + netxen_nic_gstrings_stats[index].stat_offset;
+                   (char *)adapter +
+                   netxen_nic_gstrings_stats[index].stat_offset;
                data[index] =
                    (netxen_nic_gstrings_stats[index].sizeof_stat ==
                     sizeof(u64)) ? *(u64 *) p : *(u32 *) p;
index fe8b675f9e72c69deefc464af835b91f1ae6cfaf..608e37b349b4d8d1431d4f093cb40e7b66e5e098 100644 (file)
@@ -467,6 +467,8 @@ enum {
 #define NETXEN_PCI_OCM1                (0x05100000UL)
 #define NETXEN_PCI_OCM1_MAX    (0x051fffffUL)
 #define NETXEN_PCI_CRBSPACE    (0x06000000UL)
+#define NETXEN_PCI_128MB_SIZE  (0x08000000UL)
+#define NETXEN_PCI_32MB_SIZE   (0x02000000UL)
 
 #define NETXEN_CRB_CAM NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_CAM)
 
@@ -484,6 +486,7 @@ enum {
        /* 10 seconds before we give up */
 #define        NETXEN_NIU_PHY_WAITMAX          50
 #define        NETXEN_NIU_MAX_GBE_PORTS        4
+#define        NETXEN_NIU_MAX_XG_PORTS         2
 
 #define        NETXEN_NIU_MODE                 (NETXEN_CRB_NIU + 0x00000)
 
@@ -527,6 +530,7 @@ enum {
 #define        NETXEN_NIU_XG_PAUSE_CTL         (NETXEN_CRB_NIU + 0x00098)
 #define        NETXEN_NIU_XG_PAUSE_LEVEL       (NETXEN_CRB_NIU + 0x000dc)
 #define        NETXEN_NIU_XG_SEL               (NETXEN_CRB_NIU + 0x00128)
+#define NETXEN_NIU_GB_PAUSE_CTL                (NETXEN_CRB_NIU + 0x0030c)
 
 #define NETXEN_NIU_FULL_LEVEL_XG       (NETXEN_CRB_NIU + 0x00450)
 
@@ -649,11 +653,19 @@ enum {
 #define PCIX_MS_WINDOW         (0x10204)
 #define PCIX_SN_WINDOW         (0x10208)
 #define PCIX_CRB_WINDOW                (0x10210)
+#define PCIX_CRB_WINDOW_F0     (0x10210)
+#define PCIX_CRB_WINDOW_F1     (0x10230)
+#define PCIX_CRB_WINDOW_F2     (0x10250)
+#define PCIX_CRB_WINDOW_F3     (0x10270)
 
 #define PCIX_TARGET_STATUS     (0x10118)
 #define PCIX_TARGET_MASK       (0x10128)
 
 #define PCIX_MSI_F0            (0x13000)
+#define PCIX_MSI_F1            (0x13004)
+#define PCIX_MSI_F2            (0x13008)
+#define PCIX_MSI_F3            (0x1300c)
+#define PCIX_MSI_F(i)          (0x13000+((i)*4))
 
 #define PCIX_PS_MEM_SPACE      (0x90000)
 
index 0fba8f190762c7785513e3d85fbae98ff51ccf8a..baff17a24d633ba8a5eec76c9ad7dab9b8a73aaa 100644 (file)
 
 #include "netxen_nic.h"
 #include "netxen_nic_hw.h"
+#define DEFINE_GLOBAL_RECV_CRB
 #include "netxen_nic_phan_reg.h"
 
+
 #include <net/ip.h>
 
+struct netxen_recv_crb recv_crb_registers[] = {
+       /*
+        * Instance 0.
+        */
+       {
+        /* rcv_desc_crb: */
+        {
+         {
+          /* crb_rcv_producer_offset: */
+          NETXEN_NIC_REG(0x100),
+          /* crb_rcv_consumer_offset: */
+          NETXEN_NIC_REG(0x104),
+          /* crb_gloablrcv_ring: */
+          NETXEN_NIC_REG(0x108),
+          /* crb_rcv_ring_size */
+          NETXEN_NIC_REG(0x10c),
+
+          },
+         /* Jumbo frames */
+         {
+          /* crb_rcv_producer_offset: */
+          NETXEN_NIC_REG(0x110),
+          /* crb_rcv_consumer_offset: */
+          NETXEN_NIC_REG(0x114),
+          /* crb_gloablrcv_ring: */
+          NETXEN_NIC_REG(0x118),
+          /* crb_rcv_ring_size */
+          NETXEN_NIC_REG(0x11c),
+          },
+         /* LRO */
+         {
+          /* crb_rcv_producer_offset: */
+          NETXEN_NIC_REG(0x120),
+          /* crb_rcv_consumer_offset: */
+          NETXEN_NIC_REG(0x124),
+          /* crb_gloablrcv_ring: */
+          NETXEN_NIC_REG(0x128),
+          /* crb_rcv_ring_size */
+          NETXEN_NIC_REG(0x12c),
+          }
+         },
+        /* crb_rcvstatus_ring: */
+        NETXEN_NIC_REG(0x130),
+        /* crb_rcv_status_producer: */
+        NETXEN_NIC_REG(0x134),
+        /* crb_rcv_status_consumer: */
+        NETXEN_NIC_REG(0x138),
+        /* crb_rcvpeg_state: */
+        NETXEN_NIC_REG(0x13c),
+        /* crb_status_ring_size */
+        NETXEN_NIC_REG(0x140),
+
+        },
+       /*
+        * Instance 1,
+        */
+       {
+        /* rcv_desc_crb: */
+        {
+         {
+          /* crb_rcv_producer_offset: */
+          NETXEN_NIC_REG(0x144),
+          /* crb_rcv_consumer_offset: */
+          NETXEN_NIC_REG(0x148),
+          /* crb_globalrcv_ring: */
+          NETXEN_NIC_REG(0x14c),
+          /* crb_rcv_ring_size */
+          NETXEN_NIC_REG(0x150),
+
+          },
+         /* Jumbo frames */
+         {
+          /* crb_rcv_producer_offset: */
+          NETXEN_NIC_REG(0x154),
+          /* crb_rcv_consumer_offset: */
+          NETXEN_NIC_REG(0x158),
+          /* crb_globalrcv_ring: */
+          NETXEN_NIC_REG(0x15c),
+          /* crb_rcv_ring_size */
+          NETXEN_NIC_REG(0x160),
+          },
+         /* LRO */
+         {
+          /* crb_rcv_producer_offset: */
+          NETXEN_NIC_REG(0x164),
+          /* crb_rcv_consumer_offset: */
+          NETXEN_NIC_REG(0x168),
+          /* crb_globalrcv_ring: */
+          NETXEN_NIC_REG(0x16c),
+          /* crb_rcv_ring_size */
+          NETXEN_NIC_REG(0x170),
+          }
+
+         },
+        /* crb_rcvstatus_ring: */
+        NETXEN_NIC_REG(0x174),
+        /* crb_rcv_status_producer: */
+        NETXEN_NIC_REG(0x178),
+        /* crb_rcv_status_consumer: */
+        NETXEN_NIC_REG(0x17c),
+        /* crb_rcvpeg_state: */
+        NETXEN_NIC_REG(0x180),
+        /* crb_status_ring_size */
+        NETXEN_NIC_REG(0x184),
+        },
+       /*
+        * Instance 2,
+        */
+       {
+         {
+           {
+           /* crb_rcv_producer_offset: */
+           NETXEN_NIC_REG(0x1d8),
+           /* crb_rcv_consumer_offset: */
+           NETXEN_NIC_REG(0x1dc),
+           /* crb_gloablrcv_ring: */
+           NETXEN_NIC_REG(0x1f0),
+           /* crb_rcv_ring_size */
+           NETXEN_NIC_REG(0x1f4),
+           },
+           /* Jumbo frames */
+           {
+           /* crb_rcv_producer_offset: */                  
+           NETXEN_NIC_REG(0x1f8),
+           /* crb_rcv_consumer_offset: */
+           NETXEN_NIC_REG(0x1fc),
+           /* crb_gloablrcv_ring: */
+           NETXEN_NIC_REG(0x200),
+           /* crb_rcv_ring_size */
+           NETXEN_NIC_REG(0x204),
+           },
+           /* LRO */
+           {
+           /* crb_rcv_producer_offset: */
+           NETXEN_NIC_REG(0x208),
+           /* crb_rcv_consumer_offset: */
+           NETXEN_NIC_REG(0x20c),
+           /* crb_gloablrcv_ring: */
+           NETXEN_NIC_REG(0x210),
+           /* crb_rcv_ring_size */
+           NETXEN_NIC_REG(0x214),
+           }
+         },
+         /* crb_rcvstatus_ring: */
+         NETXEN_NIC_REG(0x218),
+         /* crb_rcv_status_producer: */
+         NETXEN_NIC_REG(0x21c),
+         /* crb_rcv_status_consumer: */
+         NETXEN_NIC_REG(0x220),
+         /* crb_rcvpeg_state: */
+         NETXEN_NIC_REG(0x224),
+         /* crb_status_ring_size */
+         NETXEN_NIC_REG(0x228),
+       },
+       /*
+        * Instance 3,
+        */
+       {
+         {
+           {
+           /* crb_rcv_producer_offset: */
+           NETXEN_NIC_REG(0x22c),
+           /* crb_rcv_consumer_offset: */
+           NETXEN_NIC_REG(0x230),
+           /* crb_gloablrcv_ring: */
+           NETXEN_NIC_REG(0x234),
+           /* crb_rcv_ring_size */
+           NETXEN_NIC_REG(0x238),
+           },
+           /* Jumbo frames */
+           {
+           /* crb_rcv_producer_offset: */ 
+           NETXEN_NIC_REG(0x23c),
+           /* crb_rcv_consumer_offset: */
+           NETXEN_NIC_REG(0x240),
+           /* crb_gloablrcv_ring: */
+           NETXEN_NIC_REG(0x244),
+           /* crb_rcv_ring_size */
+           NETXEN_NIC_REG(0x248),
+           },
+           /* LRO */
+           {
+           /* crb_rcv_producer_offset: */
+           NETXEN_NIC_REG(0x24c),
+           /* crb_rcv_consumer_offset: */
+           NETXEN_NIC_REG(0x250),
+           /* crb_gloablrcv_ring: */
+           NETXEN_NIC_REG(0x254),
+           /* crb_rcv_ring_size */
+           NETXEN_NIC_REG(0x258),
+           }
+         },
+         /* crb_rcvstatus_ring: */
+         NETXEN_NIC_REG(0x25c),
+         /* crb_rcv_status_producer: */
+         NETXEN_NIC_REG(0x260),
+         /* crb_rcv_status_consumer: */
+         NETXEN_NIC_REG(0x264),
+         /* crb_rcvpeg_state: */
+         NETXEN_NIC_REG(0x268),
+         /* crb_status_ring_size */
+         NETXEN_NIC_REG(0x26c),
+       },
+};
+
+u64 ctx_addr_sig_regs[][3] = {
+       {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)},
+       {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)},
+       {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)},
+       {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)}
+};
+
+
 /*  PCI Windowing for DDR regions.  */
 
 #define ADDR_IN_RANGE(addr, low, high) \
@@ -70,8 +285,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter);
 
 int netxen_nic_set_mac(struct net_device *netdev, void *p)
 {
-       struct netxen_port *port = netdev_priv(netdev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(netdev);
        struct sockaddr *addr = p;
 
        if (netif_running(netdev))
@@ -84,7 +298,7 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p)
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 
        if (adapter->macaddr_set)
-               adapter->macaddr_set(port, addr->sa_data);
+               adapter->macaddr_set(adapter, addr->sa_data);
 
        return 0;
 }
@@ -94,56 +308,19 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p)
  */
 void netxen_nic_set_multi(struct net_device *netdev)
 {
-       struct netxen_port *port = netdev_priv(netdev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(netdev);
        struct dev_mc_list *mc_ptr;
-       __u32 netxen_mac_addr_cntl_data = 0;
 
        mc_ptr = netdev->mc_list;
        if (netdev->flags & IFF_PROMISC) {
                if (adapter->set_promisc)
                        adapter->set_promisc(adapter,
-                                            port->portnum,
                                             NETXEN_NIU_PROMISC_MODE);
        } else {
-               if (adapter->unset_promisc &&
-                   adapter->ahw.boardcfg.board_type
-                   != NETXEN_BRDTYPE_P2_SB31_10G_IMEZ)
+               if (adapter->unset_promisc)
                        adapter->unset_promisc(adapter,
-                                              port->portnum,
                                               NETXEN_NIU_NON_PROMISC_MODE);
        }
-       if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
-               netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x03);
-               netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00);
-               netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x00);
-               netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x00);
-               netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x00);
-               netxen_nic_mcr_set_enable_xtnd0(netxen_mac_addr_cntl_data);
-               netxen_nic_mcr_set_enable_xtnd1(netxen_mac_addr_cntl_data);
-               netxen_nic_mcr_set_enable_xtnd2(netxen_mac_addr_cntl_data);
-               netxen_nic_mcr_set_enable_xtnd3(netxen_mac_addr_cntl_data);
-       } else {
-               netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x00);
-               netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00);
-               netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x01);
-               netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x02);
-               netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x03);
-       }
-       writel(netxen_mac_addr_cntl_data,
-              NETXEN_CRB_NORMALIZE(adapter, NETXEN_MAC_ADDR_CNTL_REG));
-       if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
-               writel(netxen_mac_addr_cntl_data,
-                      NETXEN_CRB_NORMALIZE(adapter,
-                                           NETXEN_MULTICAST_ADDR_HI_0));
-       } else {
-               writel(netxen_mac_addr_cntl_data,
-                      NETXEN_CRB_NORMALIZE(adapter,
-                                           NETXEN_MULTICAST_ADDR_HI_1));
-       }
-       netxen_mac_addr_cntl_data = 0;
-       writel(netxen_mac_addr_cntl_data,
-              NETXEN_CRB_NORMALIZE(adapter, NETXEN_NIU_GB_DROP_WRONGADDR));
 }
 
 /*
@@ -152,8 +329,7 @@ void netxen_nic_set_multi(struct net_device *netdev)
  */
 int netxen_nic_change_mtu(struct net_device *netdev, int mtu)
 {
-       struct netxen_port *port = netdev_priv(netdev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(netdev);
        int eff_mtu = mtu + NETXEN_ENET_HEADER_SIZE + NETXEN_ETH_FCS_SIZE;
 
        if ((eff_mtu > NETXEN_MAX_MTU) || (eff_mtu < NETXEN_MIN_MTU)) {
@@ -163,7 +339,7 @@ int netxen_nic_change_mtu(struct net_device *netdev, int mtu)
        }
 
        if (adapter->set_mtu)
-               adapter->set_mtu(port, mtu);
+               adapter->set_mtu(adapter, mtu);
        netdev->mtu = mtu;
 
        return 0;
@@ -180,9 +356,9 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
        void *addr;
        int loops = 0, err = 0;
        int ctx, ring;
-       u32 card_cmdring = 0;
        struct netxen_recv_context *recv_ctx;
        struct netxen_rcv_desc_ctx *rcv_desc;
+       int func_id = adapter->portnum;
 
        DPRINTK(INFO, "crb_base: %lx %x", NETXEN_PCI_CRBSPACE,
                PCI_OFFSET_SECOND_RANGE(adapter, NETXEN_PCI_CRBSPACE));
@@ -191,11 +367,6 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
        DPRINTK(INFO, "cam RAM: %lx %x", NETXEN_CAM_RAM_BASE,
                pci_base_offset(adapter, NETXEN_CAM_RAM_BASE));
 
-       /* Window 1 call */
-       card_cmdring = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_CMDRING));
-
-       DPRINTK(INFO, "Command Peg sends 0x%x for cmdring base\n",
-               card_cmdring);
 
        for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
                DPRINTK(INFO, "Command Peg ready..waiting for rcv peg\n");
@@ -229,7 +400,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
                            (dma_addr_t *) & adapter->ctx_desc_phys_addr,
                            &adapter->ctx_desc_pdev);
 
-       printk("ctx_desc_phys_addr: 0x%llx\n",
+       printk(KERN_INFO "ctx_desc_phys_addr: 0x%llx\n",
               (unsigned long long) adapter->ctx_desc_phys_addr);
        if (addr == NULL) {
                DPRINTK(ERR, "bad return from pci_alloc_consistent\n");
@@ -238,6 +409,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
        }
        memset(addr, 0, sizeof(struct netxen_ring_ctx));
        adapter->ctx_desc = (struct netxen_ring_ctx *)addr;
+       adapter->ctx_desc->ctx_id = cpu_to_le32(adapter->portnum);
        adapter->ctx_desc->cmd_consumer_offset =
            cpu_to_le64(adapter->ctx_desc_phys_addr +
                        sizeof(struct netxen_ring_ctx));
@@ -249,7 +421,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
                            adapter->max_tx_desc_count,
                            (dma_addr_t *) & hw->cmd_desc_phys_addr,
                            &adapter->ahw.cmd_desc_pdev);
-       printk("cmd_desc_phys_addr: 0x%llx\n",
+       printk(KERN_INFO "cmd_desc_phys_addr: 0x%llx\n",
               (unsigned long long) hw->cmd_desc_phys_addr);
 
        if (addr == NULL) {
@@ -308,11 +480,11 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
        /* Window = 1 */
 
        writel(lower32(adapter->ctx_desc_phys_addr),
-              NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO));
+              NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO(func_id)));
        writel(upper32(adapter->ctx_desc_phys_addr),
-              NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI));
-       writel(NETXEN_CTX_SIGNATURE,
-              NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG));
+              NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI(func_id)));
+       writel(NETXEN_CTX_SIGNATURE | func_id,
+              NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG(func_id)));
        return err;
 }
 
@@ -339,10 +511,6 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter)
                                    adapter->ahw.cmd_desc_phys_addr);
                adapter->ahw.cmd_desc_head = NULL;
        }
-       /* Special handling: there are 2 ports on this board */
-       if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
-               adapter->ahw.max_ports = 2;
-       }
 
        for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
                recv_ctx = &adapter->recv_ctx[ctx];
@@ -385,7 +553,6 @@ void netxen_tso_check(struct netxen_adapter *adapter,
                        return;
                }
        }
-       adapter->stats.xmitcsummed++;
        desc->tcp_hdr_offset = skb_transport_offset(skb);
        desc->ip_hdr_offset = skb_network_offset(skb);
 }
@@ -475,7 +642,30 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
 
        if (adapter->curr_window == wndw)
                return;
-
+       switch(adapter->ahw.pci_func) {
+               case 0:
+                       offset = PCI_OFFSET_SECOND_RANGE(adapter,
+                                       NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
+                       break;
+               case 1:
+                       offset = PCI_OFFSET_SECOND_RANGE(adapter,
+                                       NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F1));
+                       break;
+               case 2:
+                       offset = PCI_OFFSET_SECOND_RANGE(adapter,
+                                       NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F2));
+                       break;
+               case 3:
+                       offset = PCI_OFFSET_SECOND_RANGE(adapter,
+                                       NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F3));
+                       break;
+               default:
+                       printk(KERN_INFO "Changing the window for PCI function"
+                                       "%d\n", adapter->ahw.pci_func);
+                       offset = PCI_OFFSET_SECOND_RANGE(adapter,
+                                       NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
+                       break;
+       }
        /*
         * Move the CRB window.
         * We need to write to the "direct access" region of PCI
@@ -484,9 +674,6 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
         * register address is received by PCI. The direct region bypasses
         * the CRB bus.
         */
-       offset =
-           PCI_OFFSET_SECOND_RANGE(adapter,
-                                   NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
 
        if (wndw & 0x1)
                wndw = NETXEN_WINDOW_ONE;
@@ -504,7 +691,10 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
                count++;
        }
 
-       adapter->curr_window = wndw;
+       if (wndw == NETXEN_WINDOW_ONE)
+               adapter->curr_window = 1;
+       else
+               adapter->curr_window = 0;
 }
 
 void netxen_load_firmware(struct netxen_adapter *adapter)
@@ -749,6 +939,17 @@ netxen_nic_pci_set_window(struct netxen_adapter *adapter,
        return addr;
 }
 
+int
+netxen_nic_erase_pxe(struct netxen_adapter *adapter)
+{
+       if (netxen_rom_fast_write(adapter, PXE_START, 0) == -1) {
+               printk(KERN_ERR "%s: erase pxe failed\n", 
+                       netxen_nic_driver_name);
+               return -1;
+       }
+       return 0;
+}
+
 int netxen_nic_get_board_info(struct netxen_adapter *adapter)
 {
        int rv = 0;
@@ -810,43 +1011,29 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
 
 /* NIU access sections */
 
-int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu)
+int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu)
 {
-       struct netxen_adapter *adapter = port->adapter;
        netxen_nic_write_w0(adapter,
-                           NETXEN_NIU_GB_MAX_FRAME_SIZE(port->portnum),
-                           new_mtu);
+                       NETXEN_NIU_GB_MAX_FRAME_SIZE(
+                               physical_port[adapter->portnum]), new_mtu);
        return 0;
 }
 
-int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu)
+int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu)
 {
-       struct netxen_adapter *adapter = port->adapter;
        new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE;
-       if (port->portnum == 0)
-           netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, new_mtu);
-       else if (port->portnum == 1)
-           netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, new_mtu);
+       if (physical_port[adapter->portnum] == 0)
+               netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, 
+                               new_mtu);
+       else 
+               netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE,
+                               new_mtu);
        return 0;
 }
 
 void netxen_nic_init_niu_gb(struct netxen_adapter *adapter)
 {
-       int portno;
-       for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++)
-               netxen_niu_gbe_init_port(adapter, portno);
-}
-
-void netxen_nic_stop_all_ports(struct netxen_adapter *adapter)
-{
-       int port_nr;
-       struct netxen_port *port;
-
-       for (port_nr = 0; port_nr < adapter->ahw.max_ports; port_nr++) {
-               port = adapter->port[port_nr];
-               if (adapter->stop_port)
-                       adapter->stop_port(adapter, port->portnum);
-       }
+       netxen_niu_gbe_init_port(adapter, physical_port[adapter->portnum]);
 }
 
 void
@@ -865,9 +1052,8 @@ netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off,
        }
 }
 
-void netxen_nic_set_link_parameters(struct netxen_port *port)
+void netxen_nic_set_link_parameters(struct netxen_adapter *adapter)
 {
-       struct netxen_adapter *adapter = port->adapter;
        __u32 status;
        __u32 autoneg;
        __u32 mode;
@@ -876,47 +1062,47 @@ void netxen_nic_set_link_parameters(struct netxen_port *port)
        if (netxen_get_niu_enable_ge(mode)) {   /* Gb 10/100/1000 Mbps mode */
                if (adapter->phy_read
                    && adapter->
-                   phy_read(adapter, port->portnum,
+                   phy_read(adapter,
                             NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
                             &status) == 0) {
                        if (netxen_get_phy_link(status)) {
                                switch (netxen_get_phy_speed(status)) {
                                case 0:
-                                       port->link_speed = SPEED_10;
+                                       adapter->link_speed = SPEED_10;
                                        break;
                                case 1:
-                                       port->link_speed = SPEED_100;
+                                       adapter->link_speed = SPEED_100;
                                        break;
                                case 2:
-                                       port->link_speed = SPEED_1000;
+                                       adapter->link_speed = SPEED_1000;
                                        break;
                                default:
-                                       port->link_speed = -1;
+                                       adapter->link_speed = -1;
                                        break;
                                }
                                switch (netxen_get_phy_duplex(status)) {
                                case 0:
-                                       port->link_duplex = DUPLEX_HALF;
+                                       adapter->link_duplex = DUPLEX_HALF;
                                        break;
                                case 1:
-                                       port->link_duplex = DUPLEX_FULL;
+                                       adapter->link_duplex = DUPLEX_FULL;
                                        break;
                                default:
-                                       port->link_duplex = -1;
+                                       adapter->link_duplex = -1;
                                        break;
                                }
                                if (adapter->phy_read
                                    && adapter->
-                                   phy_read(adapter, port->portnum,
+                                   phy_read(adapter,
                                             NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
                                             &autoneg) != 0)
-                                       port->link_autoneg = autoneg;
+                                       adapter->link_autoneg = autoneg;
                        } else
                                goto link_down;
                } else {
                      link_down:
-                       port->link_speed = -1;
-                       port->link_duplex = -1;
+                       adapter->link_speed = -1;
+                       adapter->link_duplex = -1;
                }
        }
 }
@@ -930,7 +1116,7 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
        char brd_name[NETXEN_MAX_SHORT_NAME];
        struct netxen_new_user_info user_info;
        int i, addr = USER_START;
-       u32 *ptr32;
+       __le32 *ptr32;
 
        struct netxen_board_info *board_info = &(adapter->ahw.boardcfg);
        if (board_info->magic != NETXEN_BDINFO_MAGIC) {
@@ -956,7 +1142,6 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
                                       netxen_nic_driver_name);
                                return;
                        }
-                       *ptr32 = le32_to_cpu(*ptr32);
                        ptr32++;
                        addr += sizeof(u32);
                }
index ab1112eb1b0d0e49f7eebbdd30017c8e0090c9de..245bf13c7ba2a5bbcc009be9fc34f35256a31344 100644 (file)
@@ -6,12 +6,12 @@
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- *                            
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *                                   
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@@ -87,7 +87,7 @@ struct netxen_adapter;
        *(u32 *)Y = readl((void __iomem*) addr);
 
 struct netxen_port;
-void netxen_nic_set_link_parameters(struct netxen_port *port);
+void netxen_nic_set_link_parameters(struct netxen_adapter *adapter);
 void netxen_nic_flash_print(struct netxen_adapter *adapter);
 int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off,
                           void *data, int len);
@@ -220,6 +220,69 @@ typedef enum {
                _netxen_crb_get_bit(config_word, 1)
 #define netxen_get_gb_mii_mgmt_notvalid(config_word)   \
                _netxen_crb_get_bit(config_word, 2)
+/*
+ * NIU XG Pause Ctl Register
+ *
+ *      Bit 0       : xg0_mask => 1:disable tx pause frames
+ *      Bit 1       : xg0_request => 1:request single pause frame
+ *      Bit 2       : xg0_on_off => 1:request is pause on, 0:off
+ *      Bit 3       : xg1_mask => 1:disable tx pause frames
+ *      Bit 4       : xg1_request => 1:request single pause frame
+ *      Bit 5       : xg1_on_off => 1:request is pause on, 0:off
+ */
+
+#define netxen_xg_set_xg0_mask(config_word)    \
+       ((config_word) |= 1 << 0)
+#define netxen_xg_set_xg1_mask(config_word)    \
+       ((config_word) |= 1 << 3)
+               
+#define netxen_xg_get_xg0_mask(config_word)    \
+       _netxen_crb_get_bit((config_word), 0)
+#define netxen_xg_get_xg1_mask(config_word)    \
+       _netxen_crb_get_bit((config_word), 3)
+
+#define netxen_xg_unset_xg0_mask(config_word)  \
+       ((config_word) &= ~(1 << 0))
+#define netxen_xg_unset_xg1_mask(config_word)  \
+       ((config_word) &= ~(1 << 3))
+
+/*
+ * NIU XG Pause Ctl Register
+ *
+ *      Bit 0       : xg0_mask => 1:disable tx pause frames
+ *      Bit 1       : xg0_request => 1:request single pause frame
+ *      Bit 2       : xg0_on_off => 1:request is pause on, 0:off
+ *      Bit 3       : xg1_mask => 1:disable tx pause frames
+ *      Bit 4       : xg1_request => 1:request single pause frame
+ *      Bit 5       : xg1_on_off => 1:request is pause on, 0:off
+ */
+#define netxen_gb_set_gb0_mask(config_word)    \
+       ((config_word) |= 1 << 0)
+#define netxen_gb_set_gb1_mask(config_word)    \
+       ((config_word) |= 1 << 2)
+#define netxen_gb_set_gb2_mask(config_word)    \
+       ((config_word) |= 1 << 4)
+#define netxen_gb_set_gb3_mask(config_word)    \
+       ((config_word) |= 1 << 6)
+
+#define netxen_gb_get_gb0_mask(config_word)    \
+       _netxen_crb_get_bit((config_word), 0)
+#define netxen_gb_get_gb1_mask(config_word)    \
+       _netxen_crb_get_bit((config_word), 2)
+#define netxen_gb_get_gb2_mask(config_word)    \
+       _netxen_crb_get_bit((config_word), 4)
+#define netxen_gb_get_gb3_mask(config_word)    \
+       _netxen_crb_get_bit((config_word), 6)
+       
+#define netxen_gb_unset_gb0_mask(config_word)  \
+       ((config_word) &= ~(1 << 0))
+#define netxen_gb_unset_gb1_mask(config_word)  \
+       ((config_word) &= ~(1 << 2))
+#define netxen_gb_unset_gb2_mask(config_word)  \
+       ((config_word) &= ~(1 << 4))
+#define netxen_gb_unset_gb3_mask(config_word)  \
+       ((config_word) &= ~(1 << 6))
+
 
 /*
  * PHY-Specific MII control/status registers.
@@ -452,21 +515,21 @@ typedef enum {
                ((config) |= (((val) & 0x0f) << 28))
 
 /* Set promiscuous mode for a GbE interface */
-int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
+int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, 
                                    netxen_niu_prom_mode_t mode);
 int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
-                                      int port, netxen_niu_prom_mode_t mode);
+                                      netxen_niu_prom_mode_t mode);
 
 /* get/set the MAC address for a given MAC */
-int netxen_niu_macaddr_get(struct netxen_adapter *adapter, int port,
+int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
                           netxen_ethernet_macaddr_t * addr);
-int netxen_niu_macaddr_set(struct netxen_port *port,
+int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
                           netxen_ethernet_macaddr_t addr);
 
 /* XG versons */
-int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int port,
+int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
                              netxen_ethernet_macaddr_t * addr);
-int netxen_niu_xg_macaddr_set(struct netxen_port *port,
+int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
                              netxen_ethernet_macaddr_t addr);
 
 /* Generic enable for GbE ports. Will detect the speed of the link. */
@@ -475,8 +538,8 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port);
 int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port);
 
 /* Disable a GbE interface */
-int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port);
+int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter);
 
-int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port);
+int netxen_niu_disable_xg_port(struct netxen_adapter *adapter);
 
 #endif                         /* __NETXEN_NIC_HW_H_ */
index 5cd40562da7ca9acb0a68e9c73c6e797055e53d5..cf0e96adfe4449a95a64eddf01be970c06e70574 100644 (file)
@@ -139,7 +139,7 @@ int netxen_init_firmware(struct netxen_adapter *adapter)
                return err;
        }
        /* Window 1 call */
-       writel(MPORT_SINGLE_FUNCTION_MODE,
+       writel(MPORT_MULTI_FUNCTION_MODE,
               NETXEN_CRB_NORMALIZE(adapter, CRB_MPORT_MODE));
        writel(PHAN_INITIALIZE_ACK,
               NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
@@ -226,7 +226,6 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter)
                adapter->unset_promisc = netxen_niu_set_promiscuous_mode;
                adapter->phy_read = netxen_niu_gbe_phy_read;
                adapter->phy_write = netxen_niu_gbe_phy_write;
-               adapter->init_port = netxen_niu_gbe_init_port;
                adapter->init_niu = netxen_nic_init_niu_gb;
                adapter->stop_port = netxen_niu_disable_gbe_port;
                break;
@@ -277,8 +276,8 @@ u32 netxen_decode_crb_addr(u32 addr)
                return (pci_base + offset);
 }
 
-static long rom_max_timeout = 10000;
-static long rom_lock_timeout = 1000000;
+static long rom_max_timeout = 100;
+static long rom_lock_timeout = 10000;
 static long rom_write_timeout = 700;
 
 static inline int rom_lock(struct netxen_adapter *adapter)
@@ -438,9 +437,9 @@ do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
 
        for (addridx = addr; addridx < (addr + size); addridx += 4) {
                ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
-               *(int *)bytes = cpu_to_le32(*(int *)bytes);
                if (ret != 0)
                        break;
+               *(int *)bytes = cpu_to_le32(*(int *)bytes);
                bytes += 4;
        }
 
@@ -499,7 +498,6 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter,
                int data;
 
                data = le32_to_cpu((*(u32*)bytes));
-
                ret = do_rom_fast_write(adapter, addridx, data);
                if (ret < 0)
                        return ret;
@@ -953,7 +951,8 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
 
        if (!pegtune_val) {
                val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
-               while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
+               while (val != PHAN_INITIALIZE_COMPLETE && 
+                       val != PHAN_INITIALIZE_ACK && loops < 200000) {
                        udelay(100);
                        schedule();
                        val =
@@ -990,9 +989,7 @@ int netxen_nic_rx_has_work(struct netxen_adapter *adapter)
 
 static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
 {
-       int port_num;
-       struct netxen_port *port;
-       struct net_device *netdev;
+       struct net_device *netdev = adapter->netdev;
        uint32_t temp, temp_state, temp_val;
        int rv = 0;
 
@@ -1006,14 +1003,9 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
                       "%s: Device temperature %d degrees C exceeds"
                       " maximum allowed. Hardware has been shut down.\n",
                       netxen_nic_driver_name, temp_val);
-               for (port_num = 0; port_num < adapter->ahw.max_ports;
-                    port_num++) {
-                       port = adapter->port[port_num];
-                       netdev = port->netdev;
 
-                       netif_carrier_off(netdev);
-                       netif_stop_queue(netdev);
-               }
+               netif_carrier_off(netdev);
+               netif_stop_queue(netdev);
                rv = 1;
        } else if (temp_state == NX_TEMP_WARN) {
                if (adapter->temp == NX_TEMP_NORMAL) {
@@ -1037,29 +1029,23 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
 
 void netxen_watchdog_task(struct work_struct *work)
 {
-       int port_num;
-       struct netxen_port *port;
        struct net_device *netdev;
        struct netxen_adapter *adapter =
                container_of(work, struct netxen_adapter, watchdog_task);
 
-       if (netxen_nic_check_temp(adapter))
+       if ((adapter->portnum  == 0) && netxen_nic_check_temp(adapter))
                return;
 
-       for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) {
-               port = adapter->port[port_num];
-               netdev = port->netdev;
-
-               if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) {
-                       printk(KERN_INFO "%s port %d, %s carrier is now ok\n",
-                              netxen_nic_driver_name, port_num, netdev->name);
-                       netif_carrier_on(netdev);
-               }
-
-               if (netif_queue_stopped(netdev))
-                       netif_wake_queue(netdev);
+       netdev = adapter->netdev;
+       if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) {
+               printk(KERN_INFO "%s port %d, %s carrier is now ok\n",
+                      netxen_nic_driver_name, adapter->portnum, netdev->name);
+               netif_carrier_on(netdev);
        }
 
+       if (netif_queue_stopped(netdev))
+               netif_wake_queue(netdev);
+
        if (adapter->handle_phy_intr)
                adapter->handle_phy_intr(adapter);
        mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
@@ -1074,9 +1060,8 @@ void
 netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
                   struct status_desc *desc)
 {
-       struct netxen_port *port = adapter->port[netxen_get_sts_port(desc)];
-       struct pci_dev *pdev = port->pdev;
-       struct net_device *netdev = port->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+       struct net_device *netdev = adapter->netdev;
        int index = netxen_get_sts_refhandle(desc);
        struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]);
        struct netxen_rx_buffer *buffer;
@@ -1126,7 +1111,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
        skb = (struct sk_buff *)buffer->skb;
 
        if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
-               port->stats.csummed++;
+               adapter->stats.csummed++;
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
        if (desc_ctx == RCV_DESC_LRO_CTXID) {
@@ -1146,27 +1131,27 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
         */
        switch (ret) {
        case NET_RX_SUCCESS:
-               port->stats.uphappy++;
+               adapter->stats.uphappy++;
                break;
 
        case NET_RX_CN_LOW:
-               port->stats.uplcong++;
+               adapter->stats.uplcong++;
                break;
 
        case NET_RX_CN_MOD:
-               port->stats.upmcong++;
+               adapter->stats.upmcong++;
                break;
 
        case NET_RX_CN_HIGH:
-               port->stats.uphcong++;
+               adapter->stats.uphcong++;
                break;
 
        case NET_RX_DROP:
-               port->stats.updropped++;
+               adapter->stats.updropped++;
                break;
 
        default:
-               port->stats.updunno++;
+               adapter->stats.updunno++;
                break;
        }
 
@@ -1178,14 +1163,13 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
        /*
         * We just consumed one buffer so post a buffer.
         */
-       adapter->stats.post_called++;
        buffer->skb = NULL;
        buffer->state = NETXEN_BUFFER_FREE;
        buffer->lro_current_frags = 0;
        buffer->lro_expected_frags = 0;
 
-       port->stats.no_rcv++;
-       port->stats.rxbytes += length;
+       adapter->stats.no_rcv++;
+       adapter->stats.rxbytes += length;
 }
 
 /* Process Receive status ring */
@@ -1226,7 +1210,6 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max)
 
        /* update the consumer index in phantom */
        if (count) {
-               adapter->stats.process_rcv++;
                recv_ctx->status_rx_consumer = consumer;
                recv_ctx->status_rx_producer = producer;
 
@@ -1249,13 +1232,10 @@ int netxen_process_cmd_ring(unsigned long data)
        int count1 = 0;
        int count2 = 0;
        struct netxen_cmd_buffer *buffer;
-       struct netxen_port *port;       /* port #1 */
-       struct netxen_port *nport;
        struct pci_dev *pdev;
        struct netxen_skb_frag *frag;
        u32 i;
        struct sk_buff *skb = NULL;
-       int p;
        int done;
 
        spin_lock(&adapter->tx_lock);
@@ -1276,7 +1256,6 @@ int netxen_process_cmd_ring(unsigned long data)
        }
 
        adapter->proc_cmd_buf_counter++;
-       adapter->stats.process_xmit++;
        /*
         * Not needed - does not seem to be used anywhere.
         * adapter->cmd_consumer = consumer;
@@ -1285,8 +1264,7 @@ int netxen_process_cmd_ring(unsigned long data)
 
        while ((last_consumer != consumer) && (count1 < MAX_STATUS_HANDLE)) {
                buffer = &adapter->cmd_buf_arr[last_consumer];
-               port = adapter->port[buffer->port];
-               pdev = port->pdev;
+               pdev = adapter->pdev;
                frag = &buffer->frag_array[0];
                skb = buffer->skb;
                if (skb && (cmpxchg(&buffer->skb, skb, 0) == skb)) {
@@ -1299,24 +1277,23 @@ int netxen_process_cmd_ring(unsigned long data)
                                               PCI_DMA_TODEVICE);
                        }
 
-                       port->stats.skbfreed++;
+                       adapter->stats.skbfreed++;
                        dev_kfree_skb_any(skb);
                        skb = NULL;
                } else if (adapter->proc_cmd_buf_counter == 1) {
-                       port->stats.txnullskb++;
+                       adapter->stats.txnullskb++;
                }
-               if (unlikely(netif_queue_stopped(port->netdev)
-                            && netif_carrier_ok(port->netdev))
-                   && ((jiffies - port->netdev->trans_start) >
-                       port->netdev->watchdog_timeo)) {
-                       SCHEDULE_WORK(&port->tx_timeout_task);
+               if (unlikely(netif_queue_stopped(adapter->netdev)
+                            && netif_carrier_ok(adapter->netdev))
+                   && ((jiffies - adapter->netdev->trans_start) >
+                       adapter->netdev->watchdog_timeo)) {
+                       SCHEDULE_WORK(&adapter->tx_timeout_task);
                }
 
                last_consumer = get_next_index(last_consumer,
                                               adapter->max_tx_desc_count);
                count1++;
        }
-       adapter->stats.noxmitdone += count1;
 
        count2 = 0;
        spin_lock(&adapter->tx_lock);
@@ -1336,13 +1313,10 @@ int netxen_process_cmd_ring(unsigned long data)
                }
        }
        if (count1 || count2) {
-               for (p = 0; p < adapter->ahw.max_ports; p++) {
-                       nport = adapter->port[p];
-                       if (netif_queue_stopped(nport->netdev)
-                           && (nport->flags & NETXEN_NETDEV_STATUS)) {
-                               netif_wake_queue(nport->netdev);
-                               nport->flags &= ~NETXEN_NETDEV_STATUS;
-                       }
+               if (netif_queue_stopped(adapter->netdev)
+                   && (adapter->flags & NETXEN_NETDEV_STATUS)) {
+                       netif_wake_queue(adapter->netdev);
+                       adapter->flags &= ~NETXEN_NETDEV_STATUS;
                }
        }
        /*
@@ -1388,7 +1362,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
        netxen_ctx_msg msg = 0;
        dma_addr_t dma;
 
-       adapter->stats.post_called++;
        rcv_desc = &recv_ctx->rcv_desc[ringid];
 
        producer = rcv_desc->producer;
@@ -1441,8 +1414,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
        if (count) {
                rcv_desc->begin_alloc = index;
                rcv_desc->rcv_pending += count;
-               adapter->stats.lastposted = count;
-               adapter->stats.posted += count;
                rcv_desc->producer = producer;
                if (rcv_desc->rcv_free >= 32) {
                        rcv_desc->rcv_free = 0;
@@ -1450,7 +1421,8 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
                        writel((producer - 1) &
                               (rcv_desc->max_rx_desc_count - 1),
                               NETXEN_CRB_NORMALIZE(adapter,
-                                                   recv_crb_registers[0].
+                                                   recv_crb_registers[
+                                                   adapter->portnum].
                                                    rcv_desc_crb[ringid].
                                                    crb_rcv_producer_offset));
                        /*
@@ -1463,7 +1435,7 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
                                             ((producer -
                                               1) & (rcv_desc->
                                                     max_rx_desc_count - 1)));
-                       netxen_set_msg_ctxid(msg, 0);
+                       netxen_set_msg_ctxid(msg, adapter->portnum);
                        netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid));
                        writel(msg,
                               DB_NORMALIZE(adapter,
@@ -1485,7 +1457,6 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
        int count = 0;
        int index = 0;
 
-       adapter->stats.post_called++;
        rcv_desc = &recv_ctx->rcv_desc[ringid];
 
        producer = rcv_desc->producer;
@@ -1532,8 +1503,6 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
        if (count) {
                rcv_desc->begin_alloc = index;
                rcv_desc->rcv_pending += count;
-               adapter->stats.lastposted = count;
-               adapter->stats.posted += count;
                rcv_desc->producer = producer;
                if (rcv_desc->rcv_free >= 32) {
                        rcv_desc->rcv_free = 0;
@@ -1541,7 +1510,8 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
                        writel((producer - 1) &
                               (rcv_desc->max_rx_desc_count - 1),
                               NETXEN_CRB_NORMALIZE(adapter,
-                                                   recv_crb_registers[0].
+                                                   recv_crb_registers[
+                                                   adapter->portnum].
                                                    rcv_desc_crb[ringid].
                                                    crb_rcv_producer_offset));
                        wmb();
@@ -1562,13 +1532,7 @@ int netxen_nic_tx_has_work(struct netxen_adapter *adapter)
 
 void netxen_nic_clear_stats(struct netxen_adapter *adapter)
 {
-       struct netxen_port *port;
-       int port_num;
-
        memset(&adapter->stats, 0, sizeof(adapter->stats));
-       for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) {
-               port = adapter->port[port_num];
-               memset(&port->stats, 0, sizeof(port->stats));
-       }
+       return;
 }
 
index be366e48007c9e96e3fd0554161896ddd1933c73..b213b062eb567fe777651c1c196ff5d716712a38 100644 (file)
@@ -6,12 +6,12 @@
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- *                            
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *                                   
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  */
 struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
 {
-       struct netxen_port *port = netdev_priv(netdev);
-       struct net_device_stats *stats = &port->net_stats;
+       struct netxen_adapter *adapter = netdev_priv(netdev);
+       struct net_device_stats *stats = &adapter->net_stats;
 
        memset(stats, 0, sizeof(*stats));
 
        /* total packets received   */
-       stats->rx_packets = port->stats.no_rcv;
+       stats->rx_packets = adapter->stats.no_rcv;
        /* total packets transmitted    */
-       stats->tx_packets = port->stats.xmitedframes + port->stats.xmitfinished;
+       stats->tx_packets = adapter->stats.xmitedframes + 
+               adapter->stats.xmitfinished;
        /* total bytes received     */
-       stats->rx_bytes = port->stats.rxbytes;
+       stats->rx_bytes = adapter->stats.rxbytes;
        /* total bytes transmitted  */
-       stats->tx_bytes = port->stats.txbytes;
+       stats->tx_bytes = adapter->stats.txbytes;
        /* bad packets received     */
-       stats->rx_errors = port->stats.rcvdbadskb;
+       stats->rx_errors = adapter->stats.rcvdbadskb;
        /* packet transmit problems */
-       stats->tx_errors = port->stats.nocmddescriptor;
+       stats->tx_errors = adapter->stats.nocmddescriptor;
        /* no space in linux buffers    */
-       stats->rx_dropped = port->stats.updropped;
+       stats->rx_dropped = adapter->stats.updropped;
        /* no space available in linux  */
-       stats->tx_dropped = port->stats.txdropped;
+       stats->tx_dropped = adapter->stats.txdropped;
 
        return stats;
 }
 
-void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno,
-                                u32 link)
+void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link)
 {
-       struct net_device *netdev = (adapter->port[portno])->netdev;
+       struct net_device *netdev = adapter->netdev;
 
        if (link)
                netif_carrier_on(netdev);
@@ -76,15 +76,13 @@ void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno,
                netif_carrier_off(netdev);
 }
 
-void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
-                           u32 enable)
+void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable)
 {
        __u32 int_src;
-       struct netxen_port *port;
 
        /*  This should clear the interrupt source */
        if (adapter->phy_read)
-               adapter->phy_read(adapter, portno,
+               adapter->phy_read(adapter, 
                                  NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
                                  &int_src);
        if (int_src == 0) {
@@ -92,9 +90,7 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
                return;
        }
        if (adapter->disable_phy_interrupts)
-               adapter->disable_phy_interrupts(adapter, portno);
-
-       port = adapter->port[portno];
+               adapter->disable_phy_interrupts(adapter);
 
        if (netxen_get_phy_int_jabber(int_src))
                DPRINTK(INFO, "Jabber interrupt \n");
@@ -115,64 +111,57 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
                DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n");
 
                if (adapter->phy_read
-                   && adapter->phy_read(adapter, portno,
+                   && adapter->phy_read(adapter, 
                                         NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
                                         &status) == 0) {
                        if (netxen_get_phy_int_link_status_changed(int_src)) {
                                if (netxen_get_phy_link(status)) {
-                                       netxen_niu_gbe_init_port(adapter,
-                                                                portno);
-                                       printk("%s: %s Link UP\n",
+                                       printk(KERN_INFO "%s: %s Link UP\n",
                                               netxen_nic_driver_name,
-                                              port->netdev->name);
+                                              adapter->netdev->name);
 
                                } else {
-                                       printk("%s: %s Link DOWN\n",
+                                       printk(KERN_INFO "%s: %s Link DOWN\n",
                                               netxen_nic_driver_name,
-                                              port->netdev->name);
+                                              adapter->netdev->name);
                                }
-                               netxen_indicate_link_status(adapter, portno,
+                               netxen_indicate_link_status(adapter, 
                                                            netxen_get_phy_link
                                                            (status));
                        }
                }
        }
        if (adapter->enable_phy_interrupts)
-               adapter->enable_phy_interrupts(adapter, portno);
+               adapter->enable_phy_interrupts(adapter);
 }
 
 void netxen_nic_isr_other(struct netxen_adapter *adapter)
 {
-       u32 portno;
+       int portno = adapter->portnum;
        u32 val, linkup, qg_linksup;
 
        /* verify the offset */
        val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
+       val = val >> physical_port[adapter->portnum];
        if (val == adapter->ahw.qg_linksup)
                return;
 
        qg_linksup = adapter->ahw.qg_linksup;
        adapter->ahw.qg_linksup = val;
        DPRINTK(INFO, "link update 0x%08x\n", val);
-       for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) {
-               linkup = val & 1;
-               if (linkup != (qg_linksup & 1)) {
-                       printk(KERN_INFO "%s: %s PORT %d link %s\n",
-                              adapter->port[portno]->netdev->name,
-                              netxen_nic_driver_name, portno,
-                              ((linkup == 0) ? "down" : "up"));
-                       netxen_indicate_link_status(adapter, portno, linkup);
-                       if (linkup)
-                               netxen_nic_set_link_parameters(adapter->
-                                                              port[portno]);
 
-               }
-               val = val >> 1;
-               qg_linksup = qg_linksup >> 1;
-       }
+       linkup = val & 1;
 
-       adapter->stats.otherints++;
+       if (linkup != (qg_linksup & 1)) {
+               printk(KERN_INFO "%s: %s PORT %d link %s\n",
+                      adapter->netdev->name,
+                      netxen_nic_driver_name, portno,
+                      ((linkup == 0) ? "down" : "up"));
+               netxen_indicate_link_status(adapter, linkup);
+               if (linkup)
+                       netxen_nic_set_link_parameters(adapter);
 
+       }
 }
 
 void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
@@ -182,26 +171,28 @@ void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
 
 void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter)
 {
-       struct net_device *netdev = adapter->port[0]->netdev;
-       u32 val;
+       struct net_device *netdev = adapter->netdev;
+       u32 val, val1;
 
        /* WINDOW = 1 */
        val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
+       val >>= (physical_port[adapter->portnum] * 8);
+       val1 = val & 0xff;
 
-       if (adapter->ahw.xg_linkup == 1 && val != XG_LINK_UP) {
+       if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) {
                printk(KERN_INFO "%s: %s NIC Link is down\n",
                       netxen_nic_driver_name, netdev->name);
                adapter->ahw.xg_linkup = 0;
                /* read twice to clear sticky bits */
                /* WINDOW = 0 */
-               netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
-               netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
+               netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
+               netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
 
                if ((val & 0xffb) != 0xffb) {
                        printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n",
-                              netxen_nic_driver_name, val);
+                              netxen_nic_driver_name, val1);
                }
-       } else if (adapter->ahw.xg_linkup == 0 && val == XG_LINK_UP) {
+       } else if (adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) {
                printk(KERN_INFO "%s: %s NIC Link is up\n",
                       netxen_nic_driver_name, netdev->name);
                adapter->ahw.xg_linkup = 1;
index ab25c225a07e011255068d470c53eb8fbe4fc612..4e32bb678ea94b8e7ded7ad9b0311718849c3ca3 100644 (file)
@@ -36,7 +36,6 @@
 #include "netxen_nic_hw.h"
 
 #include "netxen_nic.h"
-#define DEFINE_GLOBAL_RECV_CRB
 #include "netxen_nic_phan_reg.h"
 
 #include <linux/dma-mapping.h>
@@ -77,6 +76,8 @@ static void netxen_nic_poll_controller(struct net_device *netdev);
 #endif
 static irqreturn_t netxen_intr(int irq, void *data);
 
+int physical_port[] = {0, 1, 2, 3};
+
 /*  PCI Device ID Table  */
 static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
        {PCI_DEVICE(0x4040, 0x0001)},
@@ -94,6 +95,67 @@ MODULE_DEVICE_TABLE(pci, netxen_pci_tbl);
 struct workqueue_struct *netxen_workq;
 static void netxen_watchdog(unsigned long);
 
+static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
+                                                       uint32_t crb_producer)
+{
+       switch (adapter->portnum) {
+               case 0:
+                       writel(crb_producer, NETXEN_CRB_NORMALIZE
+                                       (adapter, CRB_CMD_PRODUCER_OFFSET));
+                       return;
+               case 1:
+                       writel(crb_producer, NETXEN_CRB_NORMALIZE
+                                       (adapter, CRB_CMD_PRODUCER_OFFSET_1));
+                       return;
+               case 2:
+                       writel(crb_producer, NETXEN_CRB_NORMALIZE
+                                       (adapter, CRB_CMD_PRODUCER_OFFSET_2));
+                       return;
+               case 3:
+                       writel(crb_producer, NETXEN_CRB_NORMALIZE
+                                       (adapter, CRB_CMD_PRODUCER_OFFSET_3));
+                       return;
+               default:
+                       printk(KERN_WARNING "We tried to update "
+                                       "CRB_CMD_PRODUCER_OFFSET for invalid "
+                                       "PCI function id %d\n",
+                                       adapter->portnum);
+                       return;
+       }
+}
+
+static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter,
+                                                       u32 crb_consumer)
+{
+       switch (adapter->portnum) {
+               case 0:
+                       writel(crb_consumer, NETXEN_CRB_NORMALIZE
+                               (adapter, CRB_CMD_CONSUMER_OFFSET));
+                       return;
+               case 1:
+                       writel(crb_consumer, NETXEN_CRB_NORMALIZE
+                               (adapter, CRB_CMD_CONSUMER_OFFSET_1));
+                       return;
+               case 2:
+                       writel(crb_consumer, NETXEN_CRB_NORMALIZE
+                               (adapter, CRB_CMD_CONSUMER_OFFSET_2));
+                       return;
+               case 3:
+                       writel(crb_consumer, NETXEN_CRB_NORMALIZE
+                               (adapter, CRB_CMD_CONSUMER_OFFSET_3));
+                       return;
+               default:
+                       printk(KERN_WARNING "We tried to update "
+                                       "CRB_CMD_PRODUCER_OFFSET for invalid "
+                                       "PCI function id %d\n",
+                                       adapter->portnum);
+                       return;
+       }
+}
+
+#define        ADAPTER_LIST_SIZE 12
+int netxen_cards_found;
+
 /*
  * netxen_nic_probe()
  *
@@ -111,26 +173,30 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct net_device *netdev = NULL;
        struct netxen_adapter *adapter = NULL;
-       struct netxen_port *port = NULL;
        void __iomem *mem_ptr0 = NULL;
        void __iomem *mem_ptr1 = NULL;
        void __iomem *mem_ptr2 = NULL;
+       unsigned long first_page_group_end;
+       unsigned long first_page_group_start;
+
 
        u8 __iomem *db_ptr = NULL;
        unsigned long mem_base, mem_len, db_base, db_len;
-       int pci_using_dac, i, err;
+       int pci_using_dac, i = 0, err;
        int ring;
        struct netxen_recv_context *recv_ctx = NULL;
        struct netxen_rcv_desc_ctx *rcv_desc = NULL;
        struct netxen_cmd_buffer *cmd_buf_arr = NULL;
        u64 mac_addr[FLASH_NUM_PORTS + 1];
        int valid_mac = 0;
+       u32 val;
+       int pci_func_id = PCI_FUNC(pdev->devfn);
 
        printk(KERN_INFO "%s \n", netxen_nic_driver_string);
-       /* In current scheme, we use only PCI function 0 */
-       if (PCI_FUNC(pdev->devfn) != 0) {
-               DPRINTK(ERR, "NetXen function %d will not be enabled.\n",
-                       PCI_FUNC(pdev->devfn));
+
+       if (pdev->class != 0x020000) {
+               printk(KERN_ERR"NetXen function %d, class %x will not"
+                               "be enabled.\n",pci_func_id, pdev->class);
                return -ENODEV;
        }
        if ((err = pci_enable_device(pdev)))
@@ -157,18 +223,52 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                pci_using_dac = 0;
        }
 
+
+       netdev = alloc_etherdev(sizeof(struct netxen_adapter));
+       if(!netdev) {
+               printk(KERN_ERR"%s: Failed to allocate memory for the "
+                               "device block.Check system memory resource"
+                               " usage.\n", netxen_nic_driver_name);
+               goto err_out_free_res;
+       }
+
+       SET_MODULE_OWNER(netdev);
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+
+       adapter = netdev->priv;
+       memset(adapter, 0 , sizeof(struct netxen_adapter));
+
+       adapter->ahw.pdev = pdev;
+       adapter->ahw.pci_func  = pci_func_id;
+       spin_lock_init(&adapter->tx_lock);
+       spin_lock_init(&adapter->lock);
+
        /* remap phys address */
        mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
        mem_len = pci_resource_len(pdev, 0);
 
        /* 128 Meg of memory */
-       mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE);
-       mem_ptr1 =
-           ioremap(mem_base + SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_SIZE);
-       mem_ptr2 =
-           ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);
+       if (mem_len == NETXEN_PCI_128MB_SIZE) {
+               mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE);
+               mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START,
+                               SECOND_PAGE_GROUP_SIZE);
+               mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START,
+                               THIRD_PAGE_GROUP_SIZE);
+               first_page_group_start = FIRST_PAGE_GROUP_START;
+               first_page_group_end   = FIRST_PAGE_GROUP_END;
+       } else if (mem_len == NETXEN_PCI_32MB_SIZE) {
+               mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE);
+               mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START -
+                       SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);
+               first_page_group_start = 0;
+               first_page_group_end   = 0;
+       } else {
+               err = -EIO; 
+               goto err_out_free_netdev;
+       }
 
-       if ((mem_ptr0 == 0UL) || (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {
+       if (((mem_ptr0 == 0UL) && (mem_len == NETXEN_PCI_128MB_SIZE)) ||
+                       (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {
                DPRINTK(ERR,
                        "Cannot remap adapter memory aborting.:"
                        "0 -> %p, 1 -> %p, 2 -> %p\n",
@@ -198,30 +298,87 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr);
 
-/*
- *      Allocate a adapter structure which will manage all the initialization
- *      as well as the common resources for all ports...
- *      all the ports will have pointer to this adapter as well as Adapter
- *      will have pointers of all the ports structures.
- */
+       adapter->ahw.pci_base0 = mem_ptr0;
+       adapter->ahw.first_page_group_start = first_page_group_start;
+       adapter->ahw.first_page_group_end   = first_page_group_end;
+       adapter->ahw.pci_base1 = mem_ptr1;
+       adapter->ahw.pci_base2 = mem_ptr2;
+       adapter->ahw.db_base = db_ptr;
+       adapter->ahw.db_len = db_len;
 
-       /* One adapter structure for all 4 ports....   */
-       adapter = kzalloc(sizeof(struct netxen_adapter), GFP_KERNEL);
-       if (adapter == NULL) {
-               printk(KERN_ERR "%s: Could not allocate adapter memory:%d\n",
-                      netxen_nic_driver_name,
-                      (int)sizeof(struct netxen_adapter));
-               err = -ENOMEM;
-               goto err_out_dbunmap;
-       }
+       adapter->netdev  = netdev;
+       adapter->pdev    = pdev;
+       adapter->portnum = pci_func_id;
+
+       netdev->open               = netxen_nic_open;
+       netdev->stop               = netxen_nic_close;
+       netdev->hard_start_xmit    = netxen_nic_xmit_frame;
+       netdev->get_stats          = netxen_nic_get_stats;      
+       netdev->set_multicast_list = netxen_nic_set_multi;
+       netdev->set_mac_address    = netxen_nic_set_mac;
+       netdev->change_mtu         = netxen_nic_change_mtu;
+       netdev->tx_timeout         = netxen_tx_timeout;
+       netdev->watchdog_timeo     = HZ;
+
+       netxen_nic_change_mtu(netdev, netdev->mtu);
+
+       SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
+       netdev->poll = netxen_nic_poll;
+       netdev->weight = NETXEN_NETDEV_WEIGHT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       netdev->poll_controller = netxen_nic_poll_controller;
+#endif
+       /* ScatterGather support */
+       netdev->features = NETIF_F_SG;
+       netdev->features |= NETIF_F_IP_CSUM;
+       netdev->features |= NETIF_F_TSO;
+
+       if (pci_using_dac)
+               netdev->features |= NETIF_F_HIGHDMA;
+
+       if (pci_enable_msi(pdev)) {
+               adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
+               printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
+                      " error\n", netxen_nic_driver_name);
+       } else
+               adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+
+       netdev->irq = pdev->irq;
+       INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task);
 
-       adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS;
-       adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
+       /*
+        * Set the CRB window to invalid. If any register in window 0 is
+        * accessed it should set the window to 0 and then reset it to 1.
+        */
+       adapter->curr_window = 255;
+
+       /* initialize the adapter */
+       netxen_initialize_adapter_hw(adapter);
+
+#ifdef CONFIG_PPC
+       if ((adapter->ahw.boardcfg.board_type ==
+               NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) &&
+                       (pci_func_id == 2))
+                   goto err_out_free_adapter;
+#endif /* CONFIG_PPC */
+
+       /*
+        *  Adapter in our case is quad port so initialize it before
+        *  initializing the ports
+        */
+
+       netxen_initialize_adapter_ops(adapter);
+
+       adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST;
+       if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB35_4G) ||
+                       (adapter->ahw.boardcfg.board_type == 
+                        NETXEN_BRDTYPE_P2_SB31_2G)) 
+               adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
+       else
+               adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
        adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS;
        adapter->max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS;
 
-       pci_set_drvdata(pdev, adapter);
-
        cmd_buf_arr = (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE);
        if (cmd_buf_arr == NULL) {
                printk(KERN_ERR
@@ -231,6 +388,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_free_adapter;
        }
        memset(cmd_buf_arr, 0, TX_RINGSIZE);
+       adapter->cmd_buf_arr = cmd_buf_arr;
 
        for (i = 0; i < MAX_RCV_CTX; ++i) {
                recv_ctx = &adapter->recv_ctx[i];
@@ -278,33 +436,20 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        }
 
-       adapter->cmd_buf_arr = cmd_buf_arr;
-       adapter->ahw.pci_base0 = mem_ptr0;
-       adapter->ahw.pci_base1 = mem_ptr1;
-       adapter->ahw.pci_base2 = mem_ptr2;
-       adapter->ahw.db_base = db_ptr;
-       adapter->ahw.db_len = db_len;
-       spin_lock_init(&adapter->tx_lock);
-       spin_lock_init(&adapter->lock);
        netxen_initialize_adapter_sw(adapter);  /* initialize the buffers in adapter */
-#ifdef CONFIG_IA64
-       netxen_pinit_from_rom(adapter, 0);
-       udelay(500);
-       netxen_load_firmware(adapter);
-#endif
 
-       /*
-        * Set the CRB window to invalid. If any register in window 0 is
-        * accessed it should set the window to 0 and then reset it to 1.
-        */
-       adapter->curr_window = 255;
-       /*
-        *  Adapter in our case is quad port so initialize it before
-        *  initializing the ports
-        */
-       netxen_initialize_adapter_hw(adapter);  /* initialize the adapter */
+       /* Mezz cards have PCI function 0,2,3 enabled */
+       if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ)
+               && (pci_func_id >= 2))
+                       adapter->portnum = pci_func_id - 2;
 
-       netxen_initialize_adapter_ops(adapter);
+#ifdef CONFIG_IA64
+       if(adapter->portnum == 0) {
+               netxen_pinit_from_rom(adapter, 0);
+               udelay(500);
+               netxen_load_firmware(adapter);
+       }
+#endif
 
        init_timer(&adapter->watchdog_timer);
        adapter->ahw.xg_linkup = 0;
@@ -315,12 +460,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter->proc_cmd_buf_counter = 0;
        adapter->ahw.revision_id = nx_p2_id;
 
-       if (pci_enable_msi(pdev)) {
-               adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
-               printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
-                      " error\n", netxen_nic_driver_name);
-       } else
-               adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+       /* make sure Window == 1 */
+       netxen_nic_pci_change_crbwindow(adapter, 1);
+
+       netxen_nic_update_cmd_producer(adapter, 0);
+       netxen_nic_update_cmd_consumer(adapter, 0);
+       writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO));
 
        if (netxen_is_flash_supported(adapter) == 0 &&
            netxen_get_flash_mac_addr(adapter, mac_addr) == 0)
@@ -328,153 +473,118 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        else
                valid_mac = 0;
 
-       /*
-        * Initialize all the CRB registers here.
-        */
-       writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET));
-       writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_CONSUMER_OFFSET));
-       writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO));
-
-       /* do this before waking up pegs so that we have valid dummy dma addr */
-       err = netxen_initialize_adapter_offload(adapter);
-       if (err) {
-               goto err_out_free_dev;
+       if (valid_mac) {
+               unsigned char *p = (unsigned char *)&mac_addr[adapter->portnum];
+               netdev->dev_addr[0] = *(p + 5);
+               netdev->dev_addr[1] = *(p + 4);
+               netdev->dev_addr[2] = *(p + 3);
+               netdev->dev_addr[3] = *(p + 2);
+               netdev->dev_addr[4] = *(p + 1);
+               netdev->dev_addr[5] = *(p + 0);
+
+               memcpy(netdev->perm_addr, netdev->dev_addr,
+                       netdev->addr_len);
+               if (!is_valid_ether_addr(netdev->perm_addr)) {
+                       printk(KERN_ERR "%s: Bad MAC address "
+                               "%02x:%02x:%02x:%02x:%02x:%02x.\n",
+                               netxen_nic_driver_name,
+                               netdev->dev_addr[0],
+                               netdev->dev_addr[1],
+                               netdev->dev_addr[2],
+                               netdev->dev_addr[3],
+                               netdev->dev_addr[4],
+                               netdev->dev_addr[5]);
+               } else {
+                       if (adapter->macaddr_set)
+                               adapter->macaddr_set(adapter,
+                                                       netdev->dev_addr);
+               }
        }
 
-       /* Unlock the HW, prompting the boot sequence */
-       writel(1,
-              NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE));
-
-       /* Handshake with the card before we register the devices. */
-       netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
-
-       /* initialize the all the ports */
-       adapter->active_ports = 0;
-
-       for (i = 0; i < adapter->ahw.max_ports; i++) {
-               netdev = alloc_etherdev(sizeof(struct netxen_port));
-               if (!netdev) {
-                       printk(KERN_ERR "%s: could not allocate netdev for port"
-                              " %d\n", netxen_nic_driver_name, i + 1);
+       if (adapter->portnum == 0) {
+               err = netxen_initialize_adapter_offload(adapter);
+               if (err) 
+                       goto err_out_free_rx_buffer;
+               val = readl(NETXEN_CRB_NORMALIZE(adapter, 
+                                       NETXEN_CAM_RAM(0x1fc)));
+               if (val == 0x55555555) {
+                   /* This is the first boot after power up */
+                   val = readl(NETXEN_CRB_NORMALIZE(adapter,
+                                       NETXEN_ROMUSB_GLB_SW_RESET));
+                   printk(KERN_INFO"NetXen: read 0x%08x for reset reg.\n",val);
+                   if (val != 0x80000f) {
+                       /* clear the register for future unloads/loads */
+                       writel(0, NETXEN_CRB_NORMALIZE(adapter,
+                                               NETXEN_CAM_RAM(0x1fc)));
+                       printk(KERN_ERR "ERROR in NetXen HW init sequence.\n");
+                       err = -ENODEV;
                        goto err_out_free_dev;
-               }
+                   }
 
-               SET_MODULE_OWNER(netdev);
-               SET_NETDEV_DEV(netdev, &pdev->dev);
-
-               port = netdev_priv(netdev);
-               port->netdev = netdev;
-               port->pdev = pdev;
-               port->adapter = adapter;
-               port->portnum = i;      /* Gigabit port number from 0-3 */
-
-               netdev->open = netxen_nic_open;
-               netdev->stop = netxen_nic_close;
-               netdev->hard_start_xmit = netxen_nic_xmit_frame;
-               netdev->get_stats = netxen_nic_get_stats;
-               netdev->set_multicast_list = netxen_nic_set_multi;
-               netdev->set_mac_address = netxen_nic_set_mac;
-               netdev->change_mtu = netxen_nic_change_mtu;
-               netdev->tx_timeout = netxen_tx_timeout;
-               netdev->watchdog_timeo = HZ;
-
-               netxen_nic_change_mtu(netdev, netdev->mtu);
-
-               SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
-               netdev->poll = netxen_nic_poll;
-               netdev->weight = NETXEN_NETDEV_WEIGHT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-               netdev->poll_controller = netxen_nic_poll_controller;
-#endif
-               /* ScatterGather support */
-               netdev->features = NETIF_F_SG;
-               netdev->features |= NETIF_F_IP_CSUM;
-               netdev->features |= NETIF_F_TSO;
-
-               if (pci_using_dac)
-                       netdev->features |= NETIF_F_HIGHDMA;
-
-               if (valid_mac) {
-                       unsigned char *p = (unsigned char *)&mac_addr[i];
-                       netdev->dev_addr[0] = *(p + 5);
-                       netdev->dev_addr[1] = *(p + 4);
-                       netdev->dev_addr[2] = *(p + 3);
-                       netdev->dev_addr[3] = *(p + 2);
-                       netdev->dev_addr[4] = *(p + 1);
-                       netdev->dev_addr[5] = *(p + 0);
-
-                       memcpy(netdev->perm_addr, netdev->dev_addr,
-                              netdev->addr_len);
-                       if (!is_valid_ether_addr(netdev->perm_addr)) {
-                               printk(KERN_ERR "%s: Bad MAC address "
-                                      "%02x:%02x:%02x:%02x:%02x:%02x.\n",
-                                      netxen_nic_driver_name,
-                                      netdev->dev_addr[0],
-                                      netdev->dev_addr[1],
-                                      netdev->dev_addr[2],
-                                      netdev->dev_addr[3],
-                                      netdev->dev_addr[4],
-                                      netdev->dev_addr[5]);
-                       } else {
-                               if (adapter->macaddr_set)
-                                       adapter->macaddr_set(port,
-                                                            netdev->dev_addr);
-                       }
+                   /* clear the register for future unloads/loads */
+                   writel(0, NETXEN_CRB_NORMALIZE(adapter, 
+                                           NETXEN_CAM_RAM(0x1fc)));
                }
-               INIT_WORK(&port->tx_timeout_task, netxen_tx_timeout_task);
-               netif_carrier_off(netdev);
-               netif_stop_queue(netdev);
+               printk(KERN_INFO "State: 0x%0x\n",
+                       readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
 
-               if ((err = register_netdev(netdev))) {
-                       printk(KERN_ERR "%s: register_netdev failed port #%d"
-                              " aborting\n", netxen_nic_driver_name, i + 1);
-                       err = -EIO;
-                       free_netdev(netdev);
-                       goto err_out_free_dev;
-               }
-               adapter->port_count++;
-               adapter->port[i] = port;
+               /*
+                * Tell the hardware our version number.
+                */
+               i = (_NETXEN_NIC_LINUX_MAJOR << 16) 
+                       | ((_NETXEN_NIC_LINUX_MINOR << 8))
+                       | (_NETXEN_NIC_LINUX_SUBVERSION);
+               writel(i, NETXEN_CRB_NORMALIZE(adapter, CRB_DRIVER_VERSION));
+
+               /* Unlock the HW, prompting the boot sequence */
+               writel(1,
+                       NETXEN_CRB_NORMALIZE(adapter,
+                               NETXEN_ROMUSB_GLB_PEGTUNE_DONE));
+               /* Handshake with the card before we register the devices. */
+               netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
        }
-       writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
-       netxen_pinit_from_rom(adapter, 0);
-       udelay(500);
-       netxen_load_firmware(adapter);
-       netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+
        /*
-        * delay a while to ensure that the Pegs are up & running.
-        * Otherwise, we might see some flaky behaviour.
+        * See if the firmware gave us a virtual-physical port mapping.
         */
-       udelay(100);
+       i = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_V2P(adapter->portnum)));
+       if (i != 0x55555555)
+               physical_port[adapter->portnum] = i;
+
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+
+       if ((err = register_netdev(netdev))) {
+               printk(KERN_ERR "%s: register_netdev failed port #%d"
+                              " aborting\n", netxen_nic_driver_name,
+                              adapter->portnum);
+               err = -EIO;
+               goto err_out_free_dev;
+       }
+
+       pci_set_drvdata(pdev, adapter);
 
        switch (adapter->ahw.board_type) {
-       case NETXEN_NIC_GBE:
-               printk("%s: QUAD GbE board initialized\n",
-                      netxen_nic_driver_name);
-               break;
+               case NETXEN_NIC_GBE:
+                       printk(KERN_INFO "%s: QUAD GbE board initialized\n",
+                              netxen_nic_driver_name);
+                       break;
 
-       case NETXEN_NIC_XGBE:
-               printk("%s: XGbE board initialized\n", netxen_nic_driver_name);
-               break;
+               case NETXEN_NIC_XGBE:
+                       printk(KERN_INFO "%s: XGbE board initialized\n", 
+                                       netxen_nic_driver_name);
+                       break;
        }
 
        adapter->driver_mismatch = 0;
 
        return 0;
 
-      err_out_free_dev:
-       if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
-               pci_disable_msi(pdev);
-       for (i = 0; i < adapter->port_count; i++) {
-               port = adapter->port[i];
-               if ((port) && (port->netdev)) {
-                       unregister_netdev(port->netdev);
-                       free_netdev(port->netdev);
-               }
-       }
+err_out_free_dev:
+       if (adapter->portnum == 0)
+               netxen_free_adapter_offload(adapter);
 
-       netxen_free_adapter_offload(adapter);
-
-      err_out_free_rx_buffer:
+err_out_free_rx_buffer:
        for (i = 0; i < MAX_RCV_CTX; ++i) {
                recv_ctx = &adapter->recv_ctx[i];
                for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) {
@@ -487,15 +597,16 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        vfree(cmd_buf_arr);
 
-      err_out_free_adapter:
+err_out_free_adapter:
+       if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
+               pci_disable_msi(pdev);
+
        pci_set_drvdata(pdev, NULL);
-       kfree(adapter);
 
-      err_out_dbunmap:
        if (db_ptr)
                iounmap(db_ptr);
 
-      err_out_iounmap:
+err_out_iounmap:
        if (mem_ptr0)
                iounmap(mem_ptr0);
        if (mem_ptr1)
@@ -503,9 +614,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (mem_ptr2)
                iounmap(mem_ptr2);
 
-      err_out_free_res:
+err_out_free_netdev:
+       free_netdev(netdev);
+
+err_out_free_res:
        pci_release_regions(pdev);
-      err_out_disable_pdev:
+
+err_out_disable_pdev:
        pci_disable_device(pdev);
        return err;
 }
@@ -513,7 +628,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 static void __devexit netxen_nic_remove(struct pci_dev *pdev)
 {
        struct netxen_adapter *adapter;
-       struct netxen_port *port;
+       struct net_device *netdev;
        struct netxen_rx_buffer *buffer;
        struct netxen_recv_context *recv_ctx;
        struct netxen_rcv_desc_ctx *rcv_desc;
@@ -524,38 +639,34 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
        if (adapter == NULL)
                return;
 
+       netdev = adapter->netdev;
+
+       netxen_nic_disable_int(adapter);
        if (adapter->irq)
                free_irq(adapter->irq, adapter);
-       netxen_nic_stop_all_ports(adapter);
-       /* leave the hw in the same state as reboot */
-       writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
-       netxen_pinit_from_rom(adapter, 0);
-       udelay(500);
-       netxen_load_firmware(adapter);
-       netxen_free_adapter_offload(adapter);
-
-       mdelay(1000);           /* Delay for a while to drain the DMA engines */
-       for (i = 0; i < adapter->port_count; i++) {
-               port = adapter->port[i];
-               if ((port) && (port->netdev)) {
-                       unregister_netdev(port->netdev);
-                       free_netdev(port->netdev);
-               }
-       }
+       
+       if (adapter->stop_port)
+               adapter->stop_port(adapter);
 
        if ((adapter->flags & NETXEN_NIC_MSI_ENABLED))
                pci_disable_msi(pdev);
-       if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
-               netxen_free_hw_resources(adapter);
 
-       iounmap(adapter->ahw.db_base);
-       iounmap(adapter->ahw.pci_base0);
-       iounmap(adapter->ahw.pci_base1);
-       iounmap(adapter->ahw.pci_base2);
+       if (adapter->portnum == 0)
+               netxen_free_adapter_offload(adapter);
 
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
+       if (adapter->irq)
+               free_irq(adapter->irq, adapter);
+       if(adapter->portnum == 0) {
+               /* leave the hw in the same state as reboot */
+               writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
+               netxen_pinit_from_rom(adapter, 0);
+               udelay(500);
+               netxen_load_firmware(adapter);
+               netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+       }
+
+       if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
+               netxen_free_hw_resources(adapter);
 
        for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) {
                recv_ctx = &adapter->recv_ctx[ctxid];
@@ -575,8 +686,20 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
                }
        }
 
+       unregister_netdev(netdev);
+
        vfree(adapter->cmd_buf_arr);
-       kfree(adapter);
+
+       iounmap(adapter->ahw.db_base);
+       iounmap(adapter->ahw.pci_base0);
+       iounmap(adapter->ahw.pci_base1);
+       iounmap(adapter->ahw.pci_base2);
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+
+       free_netdev(netdev);
 }
 
 /*
@@ -585,8 +708,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
  */
 static int netxen_nic_open(struct net_device *netdev)
 {
-       struct netxen_port *port = netdev_priv(netdev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv;
        int err = 0;
        int ctx, ring;
 
@@ -597,8 +719,6 @@ static int netxen_nic_open(struct net_device *netdev)
                        return -EIO;
                }
                netxen_nic_flash_print(adapter);
-               if (adapter->init_niu)
-                       adapter->init_niu(adapter);
 
                /* setup all the resources for the Phantom... */
                /* this include the descriptors for rcv, tx, and status */
@@ -609,21 +729,14 @@ static int netxen_nic_open(struct net_device *netdev)
                               err);
                        return err;
                }
-               if (adapter->init_port
-                   && adapter->init_port(adapter, port->portnum) != 0) {
-                       printk(KERN_ERR "%s: Failed to initialize port %d\n",
-                              netxen_nic_driver_name, port->portnum);
-                       netxen_free_hw_resources(adapter);
-                       return -EIO;
-               }
                for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
                        for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++)
                                netxen_post_rx_buffers(adapter, ctx, ring);
                }
                adapter->irq = adapter->ahw.pdev->irq;
-               err = request_irq(adapter->ahw.pdev->irq, &netxen_intr,
-                                 IRQF_SHARED | IRQF_SAMPLE_RANDOM,
-                                 netdev->name, adapter);
+               err = request_irq(adapter->ahw.pdev->irq, netxen_intr,
+                                 SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name,
+                                 adapter);
                if (err) {
                        printk(KERN_ERR "request_irq failed with: %d\n", err);
                        netxen_free_hw_resources(adapter);
@@ -632,23 +745,28 @@ static int netxen_nic_open(struct net_device *netdev)
 
                adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
        }
-       adapter->active_ports++;
-       if (adapter->active_ports == 1) {
-               if (!adapter->driver_mismatch)
-                       mod_timer(&adapter->watchdog_timer, jiffies);
+       if (!adapter->driver_mismatch)
+               mod_timer(&adapter->watchdog_timer, jiffies);
 
-               netxen_nic_enable_int(adapter);
-       }
+       netxen_nic_enable_int(adapter);
 
        /* Done here again so that even if phantom sw overwrote it,
         * we set it */
        if (adapter->macaddr_set)
-               adapter->macaddr_set(port, netdev->dev_addr);
-       netxen_nic_set_link_parameters(port);
+               adapter->macaddr_set(adapter, netdev->dev_addr);
+       if (adapter->init_port
+           && adapter->init_port(adapter, adapter->portnum) != 0) {
+           del_timer_sync(&adapter->watchdog_timer);
+               printk(KERN_ERR "%s: Failed to initialize port %d\n",
+                               netxen_nic_driver_name, adapter->portnum);
+               return -EIO;
+       }
+
+       netxen_nic_set_link_parameters(adapter);
 
        netxen_nic_set_multi(netdev);
        if (adapter->set_mtu)
-               adapter->set_mtu(port, netdev->mtu);
+               adapter->set_mtu(adapter, netdev->mtu);
 
        if (!adapter->driver_mismatch)
                netif_start_queue(netdev);
@@ -661,8 +779,7 @@ static int netxen_nic_open(struct net_device *netdev)
  */
 static int netxen_nic_close(struct net_device *netdev)
 {
-       struct netxen_port *port = netdev_priv(netdev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(netdev);
        int i, j;
        struct netxen_cmd_buffer *cmd_buff;
        struct netxen_skb_frag *buffrag;
@@ -670,47 +787,39 @@ static int netxen_nic_close(struct net_device *netdev)
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
 
-       adapter->active_ports--;
-
-       if (!adapter->active_ports) {
-               netxen_nic_disable_int(adapter);
-               cmd_buff = adapter->cmd_buf_arr;
-               for (i = 0; i < adapter->max_tx_desc_count; i++) {
-                       buffrag = cmd_buff->frag_array;
+       cmd_buff = adapter->cmd_buf_arr;
+       for (i = 0; i < adapter->max_tx_desc_count; i++) {
+               buffrag = cmd_buff->frag_array;
+               if (buffrag->dma) {
+                       pci_unmap_single(adapter->pdev, buffrag->dma,
+                                        buffrag->length, PCI_DMA_TODEVICE);
+                       buffrag->dma = (u64) NULL;
+               }
+               for (j = 0; j < cmd_buff->frag_count; j++) {
+                       buffrag++;
                        if (buffrag->dma) {
-                               pci_unmap_single(port->pdev, buffrag->dma,
-                                                buffrag->length,
-                                                PCI_DMA_TODEVICE);
+                               pci_unmap_page(adapter->pdev, buffrag->dma,
+                                              buffrag->length, 
+                                              PCI_DMA_TODEVICE);
                                buffrag->dma = (u64) NULL;
                        }
-                       for (j = 0; j < cmd_buff->frag_count; j++) {
-                               buffrag++;
-                               if (buffrag->dma) {
-                                       pci_unmap_page(port->pdev,
-                                                      buffrag->dma,
-                                                      buffrag->length,
-                                                      PCI_DMA_TODEVICE);
-                                       buffrag->dma = (u64) NULL;
-                               }
-                       }
-                       /* Free the skb we received in netxen_nic_xmit_frame */
-                       if (cmd_buff->skb) {
-                               dev_kfree_skb_any(cmd_buff->skb);
-                               cmd_buff->skb = NULL;
-                       }
-                       cmd_buff++;
                }
-               FLUSH_SCHEDULED_WORK();
-               del_timer_sync(&adapter->watchdog_timer);
+               /* Free the skb we received in netxen_nic_xmit_frame */
+               if (cmd_buff->skb) {
+                       dev_kfree_skb_any(cmd_buff->skb);
+                       cmd_buff->skb = NULL;
+               }
+               cmd_buff++;
        }
+       FLUSH_SCHEDULED_WORK();
+       del_timer_sync(&adapter->watchdog_timer);
 
        return 0;
 }
 
 static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
-       struct netxen_port *port = netdev_priv(netdev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(netdev);
        struct netxen_hardware_context *hw = &adapter->ahw;
        unsigned int first_seg_len = skb->len - skb->data_len;
        struct netxen_skb_frag *buffrag;
@@ -728,12 +837,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        u32 last_cmd_consumer = 0;
        int no_of_desc;
 
-       port->stats.xmitcalled++;
+       adapter->stats.xmitcalled++;
        frag_count = skb_shinfo(skb)->nr_frags + 1;
 
        if (unlikely(skb->len <= 0)) {
                dev_kfree_skb_any(skb);
-               port->stats.badskblen++;
+               adapter->stats.badskblen++;
                return NETDEV_TX_OK;
        }
 
@@ -742,7 +851,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                       "too large, can handle only %d frags\n",
                       netxen_nic_driver_name, netdev->name,
                       frag_count, MAX_BUFFERS_PER_CMD);
-               port->stats.txdropped++;
+               adapter->stats.txdropped++;
                if ((++dropped_packet & 0xff) == 0xff)
                        printk("%s: %s droppped packets = %d\n",
                               netxen_nic_driver_name, netdev->name,
@@ -759,7 +868,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
         */
       retry_getting_window:
        spin_lock_bh(&adapter->tx_lock);
-       if (adapter->total_threads == MAX_XMIT_PRODUCERS) {
+       if (adapter->total_threads >= MAX_XMIT_PRODUCERS) {
                spin_unlock_bh(&adapter->tx_lock);
                /*
                 * Yield CPU
@@ -792,15 +901,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        if ((k + no_of_desc) >=
            ((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count :
             last_cmd_consumer)) {
-               port->stats.nocmddescriptor++;
-               DPRINTK(ERR, "No command descriptors available,"
-                       " producer = %d, consumer = %d count=%llu,"
-                       " dropping packet\n", producer,
-                       adapter->last_cmd_consumer,
-                       port->stats.nocmddescriptor);
-
                netif_stop_queue(netdev);
-               port->flags |= NETXEN_NETDEV_STATUS;
+               adapter->flags |= NETXEN_NETDEV_STATUS;
                spin_unlock_bh(&adapter->tx_lock);
                return NETDEV_TX_BUSY;
        }
@@ -828,16 +930,17 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        pbuf->skb = skb;
        pbuf->cmd = TX_ETHER_PKT;
        pbuf->frag_count = frag_count;
-       pbuf->port = port->portnum;
+       pbuf->port = adapter->portnum;
        buffrag = &pbuf->frag_array[0];
-       buffrag->dma = pci_map_single(port->pdev, skb->data, first_seg_len,
+       buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len,
                                      PCI_DMA_TODEVICE);
        buffrag->length = first_seg_len;
        netxen_set_cmd_desc_totallength(hwdesc, skb->len);
        netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count);
        netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT);
 
-       netxen_set_cmd_desc_port(hwdesc, port->portnum);
+       netxen_set_cmd_desc_port(hwdesc, adapter->portnum);
+       netxen_set_cmd_desc_ctxid(hwdesc, adapter->portnum);
        hwdesc->buffer1_length = cpu_to_le16(first_seg_len);
        hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
 
@@ -860,7 +963,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                offset = frag->page_offset;
 
                temp_len = len;
-               temp_dma = pci_map_page(port->pdev, frag->page, offset,
+               temp_dma = pci_map_page(adapter->pdev, frag->page, offset,
                                        len, PCI_DMA_TODEVICE);
 
                buffrag++;
@@ -927,21 +1030,29 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                        producer = get_next_index(producer, max_tx_desc_count);
                }
        }
+
+       i = netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]);
+
+       hw->cmd_desc_head[saved_producer].flags_opcode =
+               cpu_to_le16(hw->cmd_desc_head[saved_producer].flags_opcode);
+       hw->cmd_desc_head[saved_producer].num_of_buffers_total_length =
+         cpu_to_le32(hw->cmd_desc_head[saved_producer].
+                         num_of_buffers_total_length);
+
        spin_lock_bh(&adapter->tx_lock);
-       port->stats.txbytes +=
-           netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]);
+       adapter->stats.txbytes += i;
+
        /* Code to update the adapter considering how many producer threads
           are currently working */
        if ((--adapter->num_threads) == 0) {
                /* This is the last thread */
                u32 crb_producer = adapter->cmd_producer;
-               writel(crb_producer,
-                      NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET));
+               netxen_nic_update_cmd_producer(adapter, crb_producer);
                wmb();
                adapter->total_threads = 0;
        }
 
-       port->stats.xmitfinished++;
+       adapter->stats.xmitfinished++;
        spin_unlock_bh(&adapter->tx_lock);
 
        netdev->trans_start = jiffies;
@@ -961,27 +1072,26 @@ static void netxen_watchdog(unsigned long v)
 
 static void netxen_tx_timeout(struct net_device *netdev)
 {
-       struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
-
-       SCHEDULE_WORK(&port->tx_timeout_task);
+       struct netxen_adapter *adapter = (struct netxen_adapter *)
+                                               netdev_priv(netdev);
+       SCHEDULE_WORK(&adapter->tx_timeout_task);
 }
 
 static void netxen_tx_timeout_task(struct work_struct *work)
 {
-       struct netxen_port *port =
-               container_of(work, struct netxen_port, tx_timeout_task);
-       struct net_device *netdev = port->netdev;
+       struct netxen_adapter *adapter = 
+               container_of(work, struct netxen_adapter, tx_timeout_task);
        unsigned long flags;
 
        printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
-              netxen_nic_driver_name, netdev->name);
-
-       spin_lock_irqsave(&port->adapter->lock, flags);
-       netxen_nic_close(netdev);
-       netxen_nic_open(netdev);
-       spin_unlock_irqrestore(&port->adapter->lock, flags);
-       netdev->trans_start = jiffies;
-       netif_wake_queue(netdev);
+              netxen_nic_driver_name, adapter->netdev->name);
+
+       spin_lock_irqsave(&adapter->lock, flags);
+       netxen_nic_close(adapter->netdev);
+       netxen_nic_open(adapter->netdev);
+       spin_unlock_irqrestore(&adapter->lock, flags);
+       adapter->netdev->trans_start = jiffies;
+       netif_wake_queue(adapter->netdev);
 }
 
 static int
@@ -990,17 +1100,16 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
        u32 ret = 0;
 
        DPRINTK(INFO, "Entered handle ISR\n");
-
        adapter->stats.ints++;
 
        if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
                int count = 0;
                u32 mask;
-               mask = readl(pci_base_offset(adapter, ISR_INT_VECTOR));
-               if ((mask & 0x80) == 0) {
-                       /* not our interrupt */
+               u32 our_int = 0;
+               our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+               /* not our interrupt */
+               if ((our_int & (0x80 << adapter->portnum)) == 0)
                        return ret;
-               }
                netxen_nic_disable_int(adapter);
                /* Window = 0 or 1 */
                do {
@@ -1012,7 +1121,6 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
                        printk("Could not disable interrupt completely\n");
 
        }
-       adapter->stats.hostints++;
 
        if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) {
                if (netif_rx_schedule_prep(netdev)) {
@@ -1046,33 +1154,24 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
 irqreturn_t netxen_intr(int irq, void *data)
 {
        struct netxen_adapter *adapter;
-       struct netxen_port *port;
        struct net_device *netdev;
-       int i;
 
        if (unlikely(!irq)) {
                return IRQ_NONE;        /* Not our interrupt */
        }
 
        adapter = (struct netxen_adapter *)data;
-       for (i = 0; i < adapter->ahw.max_ports; i++) {
-               port = adapter->port[i];
-               netdev = port->netdev;
-
-               /* process our status queue (for all 4 ports) */
-               if (netif_running(netdev)) {
-                       netxen_handle_int(adapter, netdev);
-                       break;
-               }
-       }
+       netdev  = adapter->netdev;
+       /* process our status queue (for all 4 ports) */
+       if (netif_running(netdev))
+               netxen_handle_int(adapter, netdev);
 
        return IRQ_HANDLED;
 }
 
 static int netxen_nic_poll(struct net_device *netdev, int *budget)
 {
-       struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(netdev);
        int work_to_do = min(*budget, netdev->quota);
        int done = 1;
        int ctx;
@@ -1080,7 +1179,6 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
        int work_done = 0;
 
        DPRINTK(INFO, "polling for %d descriptors\n", *budget);
-       port->stats.polled++;
 
        work_done = 0;
        for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
@@ -1124,8 +1222,7 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void netxen_nic_poll_controller(struct net_device *netdev)
 {
-       struct netxen_port *port = netdev_priv(netdev);
-       struct netxen_adapter *adapter = port->adapter;
+       struct netxen_adapter *adapter = netdev_priv(netdev);
        disable_irq(adapter->irq);
        netxen_intr(adapter->irq, adapter);
        enable_irq(adapter->irq);
index d5d95074e56942a93a171671de337e36b6e9ce5c..cef90a78351e91d51d5bb5f2c8c758cd979592bf 100644 (file)
@@ -88,12 +88,13 @@ static inline int phy_unlock(struct netxen_adapter *adapter)
  *       -1 on error
  *
  */
-int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
-                           long reg, __u32 * readval)
+int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, 
+                               __u32 * readval)
 {
        long timeout = 0;
        long result = 0;
        long restore = 0;
+       long phy = physical_port[adapter->portnum];
        __u32 address;
        __u32 command;
        __u32 status;
@@ -183,12 +184,13 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
  *       -1 on error
  *
  */
-int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
-                            long phy, long reg, __u32 val)
+int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, 
+                               __u32 val)
 {
        long timeout = 0;
        long result = 0;
        long restore = 0;
+       long phy = physical_port[adapter->portnum];
        __u32 address;
        __u32 command;
        __u32 status;
@@ -258,15 +260,13 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
        return result;
 }
 
-int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter,
-                                         int port)
+int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter)
 {
        netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f);
        return 0;
 }
 
-int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
-                                        int port)
+int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter)
 {
        int result = 0;
        __u32 enable = 0;
@@ -275,7 +275,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
        netxen_set_phy_int_speed_changed(enable);
 
        if (0 !=
-           netxen_niu_gbe_phy_write(adapter, port,
+           netxen_niu_gbe_phy_write(adapter, 
                                     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE,
                                     enable))
                result = -EIO;
@@ -283,38 +283,34 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
        return result;
 }
 
-int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter,
-                                          int port)
+int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter)
 {
        netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f);
        return 0;
 }
 
-int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter,
-                                         int port)
+int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter)
 {
        int result = 0;
        if (0 !=
-           netxen_niu_gbe_phy_write(adapter, port,
+           netxen_niu_gbe_phy_write(adapter,
                                     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0))
                result = -EIO;
 
        return result;
 }
 
-int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter,
-                                        int port)
+int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter)
 {
        netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1);
        return 0;
 }
 
-int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter,
-                                       int port)
+int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter)
 {
        int result = 0;
        if (0 !=
-           netxen_niu_gbe_phy_write(adapter, port,
+           netxen_niu_gbe_phy_write(adapter, 
                                     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
                                     -EIO))
                result = -EIO;
@@ -355,9 +351,9 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter,
                                            0x5);
        }
 
-       if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+       if (netxen_niu_gbe_enable_phy_interrupts(adapter))
                printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");
-       if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+       if (netxen_niu_gbe_clear_phy_interrupts(adapter))
                printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
 }
 
@@ -393,9 +389,9 @@ void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter,
                                            0x5);
        }
 
-       if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+       if (netxen_niu_gbe_enable_phy_interrupts(adapter))
                printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");
-       if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+       if (netxen_niu_gbe_clear_phy_interrupts(adapter))
                printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
 }
 
@@ -404,11 +400,11 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
        int result = 0;
        __u32 status;
        if (adapter->disable_phy_interrupts)
-               adapter->disable_phy_interrupts(adapter, port);
+               adapter->disable_phy_interrupts(adapter);
        mdelay(2);
 
        if (0 ==
-           netxen_niu_gbe_phy_read(adapter, port,
+           netxen_niu_gbe_phy_read(adapter,
                                    NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
                                    &status)) {
                if (netxen_get_phy_link(status)) {
@@ -439,13 +435,13 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
                                                    | NETXEN_GB_MAC_ENABLE_TX_RX
                                                    |
                                                    NETXEN_GB_MAC_PAUSED_FRMS);
-                       if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+                       if (netxen_niu_gbe_clear_phy_interrupts(adapter))
                                printk(KERN_ERR PFX
                                       "ERROR clearing PHY interrupts\n");
-                       if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+                       if (netxen_niu_gbe_enable_phy_interrupts(adapter))
                                printk(KERN_ERR PFX
                                       "ERROR enabling PHY interrupts\n");
-                       if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+                       if (netxen_niu_gbe_clear_phy_interrupts(adapter))
                                printk(KERN_ERR PFX
                                       "ERROR clearing PHY interrupts\n");
                        result = -1;
@@ -458,26 +454,18 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
 
 int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
 {
-       u32 reg = 0, ret = 0;
+       u32 reg;
+       u32 portnum = physical_port[adapter->portnum];
 
-       if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
-               netxen_crb_writelit_adapter(adapter,
-                                           NETXEN_NIU_XG1_CONFIG_0, 0x5);
-               /* XXX hack for Mez cards: both ports in promisc mode */
-               netxen_nic_hw_read_wx(adapter,
-                                     NETXEN_NIU_XGE_CONFIG_1, &reg, 4);
-               reg = (reg | 0x2000UL);
-               netxen_crb_writelit_adapter(adapter,
-                                           NETXEN_NIU_XGE_CONFIG_1, reg);
-               reg = 0;
-               netxen_nic_hw_read_wx(adapter,
-                                     NETXEN_NIU_XG1_CONFIG_1, &reg, 4);
-               reg = (reg | 0x2000UL);
-               netxen_crb_writelit_adapter(adapter,
-                                           NETXEN_NIU_XG1_CONFIG_1, reg);
-       }
+       netxen_crb_writelit_adapter(adapter,
+               NETXEN_NIU_XGE_CONFIG_0+(0x10000*portnum), 0x5);
+       netxen_nic_hw_read_wx(adapter,
+               NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), &reg, 4);
+       reg = (reg & ~0x2000UL);
+       netxen_crb_writelit_adapter(adapter,
+               NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), reg);
 
-       return ret;
+       return 0;
 }
 
 /* 
@@ -498,7 +486,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
         * The read of the PHY INT status will clear the pending
         * interrupt status
         */
-       if (netxen_niu_gbe_phy_read(adapter, port,
+       if (netxen_niu_gbe_phy_read(adapter,
                                    NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
                                    &int_src) != 0)
                result = -EINVAL;
@@ -535,7 +523,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
                        printk(KERN_INFO PFX
                               "speed_changed or link status changed");
                        if (netxen_niu_gbe_phy_read
-                           (adapter, port,
+                           (adapter,
                             NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
                             &status) == 0) {
                                if (netxen_get_phy_speed(status) == 2) {
@@ -581,10 +569,11 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
  * Note that the passed-in value must already be in network byte order.
  */
 int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
-                          int phy, netxen_ethernet_macaddr_t * addr)
+                          netxen_ethernet_macaddr_t * addr)
 {
        u32 stationhigh;
        u32 stationlow;
+       int phy = physical_port[adapter->portnum];
        u8 val[8];
 
        if (addr == NULL)
@@ -610,13 +599,12 @@ int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
  * Set the station MAC address.
  * Note that the passed-in value must already be in network byte order.
  */
-int netxen_niu_macaddr_set(struct netxen_port *port,
+int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
                           netxen_ethernet_macaddr_t addr)
 {
        u8 temp[4];
        u32 val;
-       struct netxen_adapter *adapter = port->adapter;
-       int phy = port->portnum;
+       int phy = physical_port[adapter->portnum];
        unsigned char mac_addr[6];
        int i;
 
@@ -634,7 +622,7 @@ int netxen_niu_macaddr_set(struct netxen_port *port,
                    (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4))
                        return -2;
 
-               netxen_niu_macaddr_get(adapter, phy,
+               netxen_niu_macaddr_get(adapter, 
                                       (netxen_ethernet_macaddr_t *) mac_addr);
                if (memcmp(mac_addr, addr, 6) == 0)
                        break;
@@ -642,7 +630,7 @@ int netxen_niu_macaddr_set(struct netxen_port *port,
 
        if (i == 10) {
                printk(KERN_ERR "%s: cannot set Mac addr for %s\n",
-                      netxen_nic_driver_name, port->netdev->name);
+                      netxen_nic_driver_name, adapter->netdev->name);
                printk(KERN_ERR "MAC address set: "
                       "%02x:%02x:%02x:%02x:%02x:%02x.\n",
                       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
@@ -735,13 +723,13 @@ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter,
 }
 
 /* Disable a GbE interface */
-int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port)
+int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter)
 {
        __u32 mac_cfg0;
+       u32 port = physical_port[adapter->portnum];
 
        if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
                return -EINVAL;
-
        mac_cfg0 = 0;
        netxen_gb_soft_reset(mac_cfg0);
        if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
@@ -751,13 +739,13 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port)
 }
 
 /* Disable an XG interface */
-int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port)
+int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
 {
        __u32 mac_cfg;
+       u32 port = physical_port[adapter->portnum];
 
        if (port != 0)
                return -EINVAL;
-
        mac_cfg = 0;
        netxen_xg_soft_reset(mac_cfg);
        if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_CONFIG_0,
@@ -767,10 +755,11 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port)
 }
 
 /* Set promiscuous mode for a GbE interface */
-int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
+int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, 
                                    netxen_niu_prom_mode_t mode)
 {
        __u32 reg;
+       u32 port = physical_port[adapter->portnum];
 
        if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
                return -EINVAL;
@@ -824,25 +813,50 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
  * Set the MAC address for an XG port
  * Note that the passed-in value must already be in network byte order.
  */
-int netxen_niu_xg_macaddr_set(struct netxen_port *port,
+int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
                              netxen_ethernet_macaddr_t addr)
 {
+       int phy = physical_port[adapter->portnum];
        u8 temp[4];
        u32 val;
-       struct netxen_adapter *adapter = port->adapter;
+
+       if ((phy < 0) || (phy > NETXEN_NIU_MAX_XG_PORTS))
+               return -EIO;
 
        temp[0] = temp[1] = 0;
-       memcpy(temp + 2, addr, 2);
-       val = le32_to_cpu(*(__le32 *)temp);
-       if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
-                                  &val, 4))
+       switch (phy) {
+       case 0:
+           memcpy(temp + 2, addr, 2);
+           val = le32_to_cpu(*(__le32 *)temp);
+           if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
+                               &val, 4))
                return -EIO;
 
-       memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
-       val = le32_to_cpu(*(__le32 *)temp);
-       if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
-                                  &val, 4))
+           memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
+           val = le32_to_cpu(*(__le32 *)temp);
+           if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
+                               &val, 4))
+               return -EIO;
+           break;
+
+       case 1:
+           memcpy(temp + 2, addr, 2);
+           val = le32_to_cpu(*(__le32 *)temp);
+           if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1,
+                               &val, 4))
+               return -EIO;
+
+           memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
+           val = le32_to_cpu(*(__le32 *)temp);
+           if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI,
+                               &val, 4))
                return -EIO;
+           break;
+
+       default:
+           printk(KERN_ERR "Unknown port %d\n", phy);
+           break;
+       }
 
        return 0;
 }
@@ -851,9 +865,10 @@ int netxen_niu_xg_macaddr_set(struct netxen_port *port,
  * Return the current station MAC address.
  * Note that the passed-in value must already be in network byte order.
  */
-int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
+int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
                              netxen_ethernet_macaddr_t * addr)
 {
+       int phy = physical_port[adapter->portnum];
        u32 stationhigh;
        u32 stationlow;
        u8 val[8];
@@ -878,21 +893,24 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
 }
 
 int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
-                                      int port, netxen_niu_prom_mode_t mode)
+                                      netxen_niu_prom_mode_t mode)
 {
        __u32 reg;
+       u32 port = physical_port[adapter->portnum];
 
-       if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+       if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
                return -EINVAL;
 
-       if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_CONFIG_1, &reg, 4))
-               return -EIO;
+       if (netxen_nic_hw_read_wx(adapter,
+               NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), &reg, 4))
+                       return -EIO;
        if (mode == NETXEN_NIU_PROMISC_MODE)
                reg = (reg | 0x2000UL);
        else
                reg = (reg & ~0x2000UL);
 
-       netxen_crb_writelit_adapter(adapter, NETXEN_NIU_XGE_CONFIG_1, reg);
+       netxen_crb_writelit_adapter(adapter,
+               NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg);
 
        return 0;
 }
index 0c7c94328b7f6749489fc5746cac526e3bd9c1b5..9457fc7249c86ed77fc9bdf367be152ea2fa0ac2 100644 (file)
 
 #define CRB_CMD_PRODUCER_OFFSET_1   NETXEN_NIC_REG(0x1ac)
 #define CRB_CMD_CONSUMER_OFFSET_1   NETXEN_NIC_REG(0x1b0)
+#define CRB_CMD_PRODUCER_OFFSET_2   NETXEN_NIC_REG(0x1b8)
+#define CRB_CMD_CONSUMER_OFFSET_2   NETXEN_NIC_REG(0x1bc)
+
+// 1c0 to 1cc used for signature reg
+#define CRB_CMD_PRODUCER_OFFSET_3   NETXEN_NIC_REG(0x1d0)
+#define CRB_CMD_CONSUMER_OFFSET_3   NETXEN_NIC_REG(0x1d4)
 #define CRB_TEMP_STATE              NETXEN_NIC_REG(0x1b4)
 
+#define CRB_V2P_0                  NETXEN_NIC_REG(0x290)
+#define CRB_V2P_1                  NETXEN_NIC_REG(0x294)
+#define CRB_V2P_2                  NETXEN_NIC_REG(0x298)
+#define CRB_V2P_3                  NETXEN_NIC_REG(0x29c)
+#define CRB_V2P(port)              (CRB_V2P_0+((port)*4))
+#define CRB_DRIVER_VERSION         NETXEN_NIC_REG(0x2a0)
+
 /* used for ethtool tests */
 #define CRB_SCRATCHPAD_TEST        NETXEN_NIC_REG(0x280)
 
@@ -139,128 +152,13 @@ struct netxen_recv_crb {
 };
 
 #if defined(DEFINE_GLOBAL_RECV_CRB)
-struct netxen_recv_crb recv_crb_registers[] = {
-       /*
-        * Instance 0.
-        */
-       {
-        /* rcv_desc_crb: */
-        {
-         {
-          /* crb_rcv_producer_offset: */
-          NETXEN_NIC_REG(0x100),
-          /* crb_rcv_consumer_offset: */
-          NETXEN_NIC_REG(0x104),
-          /* crb_gloablrcv_ring: */
-          NETXEN_NIC_REG(0x108),
-          /* crb_rcv_ring_size */
-          NETXEN_NIC_REG(0x10c),
-
-          },
-         /* Jumbo frames */
-         {
-          /* crb_rcv_producer_offset: */
-          NETXEN_NIC_REG(0x110),
-          /* crb_rcv_consumer_offset: */
-          NETXEN_NIC_REG(0x114),
-          /* crb_gloablrcv_ring: */
-          NETXEN_NIC_REG(0x118),
-          /* crb_rcv_ring_size */
-          NETXEN_NIC_REG(0x11c),
-          },
-         /* LRO */
-         {
-          /* crb_rcv_producer_offset: */
-          NETXEN_NIC_REG(0x120),
-          /* crb_rcv_consumer_offset: */
-          NETXEN_NIC_REG(0x124),
-          /* crb_gloablrcv_ring: */
-          NETXEN_NIC_REG(0x128),
-          /* crb_rcv_ring_size */
-          NETXEN_NIC_REG(0x12c),
-          }
-         },
-        /* crb_rcvstatus_ring: */
-        NETXEN_NIC_REG(0x130),
-        /* crb_rcv_status_producer: */
-        NETXEN_NIC_REG(0x134),
-        /* crb_rcv_status_consumer: */
-        NETXEN_NIC_REG(0x138),
-        /* crb_rcvpeg_state: */
-        NETXEN_NIC_REG(0x13c),
-        /* crb_status_ring_size */
-        NETXEN_NIC_REG(0x140),
-
-        },
-       /*
-        * Instance 1,
-        */
-       {
-        /* rcv_desc_crb: */
-        {
-         {
-          /* crb_rcv_producer_offset: */
-          NETXEN_NIC_REG(0x144),
-          /* crb_rcv_consumer_offset: */
-          NETXEN_NIC_REG(0x148),
-          /* crb_globalrcv_ring: */
-          NETXEN_NIC_REG(0x14c),
-          /* crb_rcv_ring_size */
-          NETXEN_NIC_REG(0x150),
-
-          },
-         /* Jumbo frames */
-         {
-          /* crb_rcv_producer_offset: */
-          NETXEN_NIC_REG(0x154),
-          /* crb_rcv_consumer_offset: */
-          NETXEN_NIC_REG(0x158),
-          /* crb_globalrcv_ring: */
-          NETXEN_NIC_REG(0x15c),
-          /* crb_rcv_ring_size */
-          NETXEN_NIC_REG(0x160),
-          },
-         /* LRO */
-         {
-          /* crb_rcv_producer_offset: */
-          NETXEN_NIC_REG(0x164),
-          /* crb_rcv_consumer_offset: */
-          NETXEN_NIC_REG(0x168),
-          /* crb_globalrcv_ring: */
-          NETXEN_NIC_REG(0x16c),
-          /* crb_rcv_ring_size */
-          NETXEN_NIC_REG(0x170),
-          }
-
-         },
-        /* crb_rcvstatus_ring: */
-        NETXEN_NIC_REG(0x174),
-        /* crb_rcv_status_producer: */
-        NETXEN_NIC_REG(0x178),
-        /* crb_rcv_status_consumer: */
-        NETXEN_NIC_REG(0x17c),
-        /* crb_rcvpeg_state: */
-        NETXEN_NIC_REG(0x180),
-        /* crb_status_ring_size */
-        NETXEN_NIC_REG(0x184),
-
-        },
-};
-
-u64 ctx_addr_sig_regs[][3] = {
-       {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)},
-       {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)},
-       {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)},
-       {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)}
-};
-
 #else
 extern struct netxen_recv_crb recv_crb_registers[];
 extern u64 ctx_addr_sig_regs[][3];
-#define CRB_CTX_ADDR_REG_LO            (ctx_addr_sig_regs[0][0])
-#define CRB_CTX_ADDR_REG_HI            (ctx_addr_sig_regs[0][2])
-#define CRB_CTX_SIGNATURE_REG       (ctx_addr_sig_regs[0][1])
 #endif                         /* DEFINE_GLOBAL_RECEIVE_CRB */
+#define CRB_CTX_ADDR_REG_LO(FUNC_ID)           (ctx_addr_sig_regs[FUNC_ID][0])
+#define CRB_CTX_ADDR_REG_HI(FUNC_ID)           (ctx_addr_sig_regs[FUNC_ID][2])
+#define CRB_CTX_SIGNATURE_REG(FUNC_ID)         (ctx_addr_sig_regs[FUNC_ID][1])
 
 /*
  * Temperature control.
index 0791360a6a66b5638b9708eb3b3fc9fe9d704b06..9c171a7390e2b4ab09e5a77f3fee8c19732e05d3 100644 (file)
@@ -253,12 +253,12 @@ struct pcnet32_access {
  * so the structure should be allocated using pci_alloc_consistent().
  */
 struct pcnet32_private {
-       struct pcnet32_init_block init_block;
+       struct pcnet32_init_block *init_block;
        /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
        struct pcnet32_rx_head  *rx_ring;
        struct pcnet32_tx_head  *tx_ring;
-       dma_addr_t              dma_addr;/* DMA address of beginning of this
-                                  object, returned by pci_alloc_consistent */
+       dma_addr_t              init_dma_addr;/* DMA address of beginning of the init block,
+                                  returned by pci_alloc_consistent */
        struct pci_dev          *pci_dev;
        const char              *name;
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
@@ -653,7 +653,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
 
 static void pcnet32_purge_rx_ring(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        int i;
 
        /* free all allocated skbuffs */
@@ -681,7 +681,7 @@ static void pcnet32_poll_controller(struct net_device *dev)
 
 static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long flags;
        int r = -EOPNOTSUPP;
 
@@ -696,7 +696,7 @@ static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 
 static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long flags;
        int r = -EOPNOTSUPP;
 
@@ -711,7 +711,7 @@ static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void pcnet32_get_drvinfo(struct net_device *dev,
                                struct ethtool_drvinfo *info)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
 
        strcpy(info->driver, DRV_NAME);
        strcpy(info->version, DRV_VERSION);
@@ -723,7 +723,7 @@ static void pcnet32_get_drvinfo(struct net_device *dev,
 
 static u32 pcnet32_get_link(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long flags;
        int r;
 
@@ -743,19 +743,19 @@ static u32 pcnet32_get_link(struct net_device *dev)
 
 static u32 pcnet32_get_msglevel(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        return lp->msg_enable;
 }
 
 static void pcnet32_set_msglevel(struct net_device *dev, u32 value)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        lp->msg_enable = value;
 }
 
 static int pcnet32_nway_reset(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long flags;
        int r = -EOPNOTSUPP;
 
@@ -770,7 +770,7 @@ static int pcnet32_nway_reset(struct net_device *dev)
 static void pcnet32_get_ringparam(struct net_device *dev,
                                  struct ethtool_ringparam *ering)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
 
        ering->tx_max_pending = TX_MAX_RING_SIZE;
        ering->tx_pending = lp->tx_ring_size;
@@ -781,7 +781,7 @@ static void pcnet32_get_ringparam(struct net_device *dev,
 static int pcnet32_set_ringparam(struct net_device *dev,
                                 struct ethtool_ringparam *ering)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long flags;
        unsigned int size;
        ulong ioaddr = dev->base_addr;
@@ -847,7 +847,7 @@ static int pcnet32_self_test_count(struct net_device *dev)
 static void pcnet32_ethtool_test(struct net_device *dev,
                                 struct ethtool_test *test, u64 * data)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        int rc;
 
        if (test->flags == ETH_TEST_FL_OFFLINE) {
@@ -868,7 +868,7 @@ static void pcnet32_ethtool_test(struct net_device *dev,
 
 static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        struct pcnet32_access *a = &lp->a;      /* access to registers */
        ulong ioaddr = dev->base_addr;  /* card base I/O address */
        struct sk_buff *skb;    /* sk buff */
@@ -1047,7 +1047,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
 
 static void pcnet32_led_blink_callback(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        struct pcnet32_access *a = &lp->a;
        ulong ioaddr = dev->base_addr;
        unsigned long flags;
@@ -1064,7 +1064,7 @@ static void pcnet32_led_blink_callback(struct net_device *dev)
 
 static int pcnet32_phys_id(struct net_device *dev, u32 data)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        struct pcnet32_access *a = &lp->a;
        ulong ioaddr = dev->base_addr;
        unsigned long flags;
@@ -1109,7 +1109,7 @@ static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
                int can_sleep)
 {
        int csr5;
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        struct pcnet32_access *a = &lp->a;
        ulong ioaddr = dev->base_addr;
        int ticks;
@@ -1257,7 +1257,7 @@ static void pcnet32_rx_entry(struct net_device *dev,
 
 static int pcnet32_rx(struct net_device *dev, int quota)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        int entry = lp->cur_rx & lp->rx_mod_mask;
        struct pcnet32_rx_head *rxp = &lp->rx_ring[entry];
        int npackets = 0;
@@ -1282,7 +1282,7 @@ static int pcnet32_rx(struct net_device *dev, int quota)
 
 static int pcnet32_tx(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned int dirty_tx = lp->dirty_tx;
        int delta;
        int must_restart = 0;
@@ -1381,7 +1381,7 @@ static int pcnet32_tx(struct net_device *dev)
 #ifdef CONFIG_PCNET32_NAPI
 static int pcnet32_poll(struct net_device *dev, int *budget)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        int quota = min(dev->quota, *budget);
        unsigned long ioaddr = dev->base_addr;
        unsigned long flags;
@@ -1428,7 +1428,7 @@ static int pcnet32_poll(struct net_device *dev, int *budget)
 #define PCNET32_MAX_PHYS       32
 static int pcnet32_get_regs_len(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        int j = lp->phycount * PCNET32_REGS_PER_PHY;
 
        return ((PCNET32_NUM_REGS + j) * sizeof(u16));
@@ -1439,7 +1439,7 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
 {
        int i, csr0;
        u16 *buff = ptr;
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        struct pcnet32_access *a = &lp->a;
        ulong ioaddr = dev->base_addr;
        unsigned long flags;
@@ -1592,7 +1592,6 @@ static int __devinit
 pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
 {
        struct pcnet32_private *lp;
-       dma_addr_t lp_dma_addr;
        int i, media;
        int fdx, mii, fset, dxsuflo;
        int chip_version;
@@ -1714,7 +1713,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                dxsuflo = 1;
        }
 
-       dev = alloc_etherdev(0);
+       dev = alloc_etherdev(sizeof(*lp));
        if (!dev) {
                if (pcnet32_debug & NETIF_MSG_PROBE)
                        printk(KERN_ERR PFX "Memory allocation failed.\n");
@@ -1805,25 +1804,22 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
        }
 
        dev->base_addr = ioaddr;
+       lp = netdev_priv(dev);
        /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
-       if ((lp =
-            pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) {
+       if ((lp->init_block =
+            pci_alloc_consistent(pdev, sizeof(*lp->init_block), &lp->init_dma_addr)) == NULL) {
                if (pcnet32_debug & NETIF_MSG_PROBE)
                        printk(KERN_ERR PFX
                               "Consistent memory allocation failed.\n");
                ret = -ENOMEM;
                goto err_free_netdev;
        }
-
-       memset(lp, 0, sizeof(*lp));
-       lp->dma_addr = lp_dma_addr;
        lp->pci_dev = pdev;
 
        spin_lock_init(&lp->lock);
 
        SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
-       dev->priv = lp;
        lp->name = chipname;
        lp->shared_irq = shared;
        lp->tx_ring_size = TX_RING_SIZE;        /* default tx ring size */
@@ -1870,23 +1866,21 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
            && dev->dev_addr[2] == 0x75)
                lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
 
-       lp->init_block.mode = le16_to_cpu(0x0003);      /* Disable Rx and Tx. */
-       lp->init_block.tlen_rlen =
+       lp->init_block->mode = le16_to_cpu(0x0003);     /* Disable Rx and Tx. */
+       lp->init_block->tlen_rlen =
            le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
        for (i = 0; i < 6; i++)
-               lp->init_block.phys_addr[i] = dev->dev_addr[i];
-       lp->init_block.filter[0] = 0x00000000;
-       lp->init_block.filter[1] = 0x00000000;
-       lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
-       lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+               lp->init_block->phys_addr[i] = dev->dev_addr[i];
+       lp->init_block->filter[0] = 0x00000000;
+       lp->init_block->filter[1] = 0x00000000;
+       lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
+       lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
 
        /* switch pcnet32 to 32bit mode */
        a->write_bcr(ioaddr, 20, 2);
 
-       a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private,
-                                                        init_block)) & 0xffff);
-       a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private,
-                                                        init_block)) >> 16);
+       a->write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
+       a->write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
 
        if (pdev) {             /* use the IRQ provided by PCI */
                dev->irq = pdev->irq;
@@ -1992,7 +1986,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
       err_free_ring:
        pcnet32_free_ring(dev);
       err_free_consistent:
-       pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+       pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), 
+                           lp->init_block, lp->init_dma_addr);
       err_free_netdev:
        free_netdev(dev);
       err_release_region:
@@ -2003,7 +1998,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
 /* if any allocation fails, caller must also call pcnet32_free_ring */
 static int pcnet32_alloc_ring(struct net_device *dev, char *name)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
 
        lp->tx_ring = pci_alloc_consistent(lp->pci_dev,
                                           sizeof(struct pcnet32_tx_head) *
@@ -2070,7 +2065,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
 
 static void pcnet32_free_ring(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
 
        kfree(lp->tx_skbuff);
        lp->tx_skbuff = NULL;
@@ -2103,7 +2098,7 @@ static void pcnet32_free_ring(struct net_device *dev)
 
 static int pcnet32_open(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
        u16 val;
        int i;
@@ -2134,8 +2129,7 @@ static int pcnet32_open(struct net_device *dev)
                       "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
                       dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr),
                       (u32) (lp->rx_ring_dma_addr),
-                      (u32) (lp->dma_addr +
-                             offsetof(struct pcnet32_private, init_block)));
+                      (u32) (lp->init_dma_addr));
 
        /* set/reset autoselect bit */
        val = lp->a.read_bcr(ioaddr, 2) & ~2;
@@ -2274,7 +2268,7 @@ static int pcnet32_open(struct net_device *dev)
        }
 #endif
 
-       lp->init_block.mode =
+       lp->init_block->mode =
            le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
        pcnet32_load_multicast(dev);
 
@@ -2284,12 +2278,8 @@ static int pcnet32_open(struct net_device *dev)
        }
 
        /* Re-initialize the PCNET32, and start it when done. */
-       lp->a.write_csr(ioaddr, 1, (lp->dma_addr +
-                                   offsetof(struct pcnet32_private,
-                                            init_block)) & 0xffff);
-       lp->a.write_csr(ioaddr, 2,
-                       (lp->dma_addr +
-                        offsetof(struct pcnet32_private, init_block)) >> 16);
+       lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
+       lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
 
        lp->a.write_csr(ioaddr, CSR4, 0x0915);  /* auto tx pad */
        lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
@@ -2316,8 +2306,7 @@ static int pcnet32_open(struct net_device *dev)
                printk(KERN_DEBUG
                       "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n",
                       dev->name, i,
-                      (u32) (lp->dma_addr +
-                             offsetof(struct pcnet32_private, init_block)),
+                      (u32) (lp->init_dma_addr),
                       lp->a.read_csr(ioaddr, CSR0));
 
        spin_unlock_irqrestore(&lp->lock, flags);
@@ -2355,7 +2344,7 @@ static int pcnet32_open(struct net_device *dev)
 
 static void pcnet32_purge_tx_ring(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        int i;
 
        for (i = 0; i < lp->tx_ring_size; i++) {
@@ -2375,7 +2364,7 @@ static void pcnet32_purge_tx_ring(struct net_device *dev)
 /* Initialize the PCNET32 Rx and Tx rings. */
 static int pcnet32_init_ring(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        int i;
 
        lp->tx_full = 0;
@@ -2417,12 +2406,12 @@ static int pcnet32_init_ring(struct net_device *dev)
                lp->tx_dma_addr[i] = 0;
        }
 
-       lp->init_block.tlen_rlen =
+       lp->init_block->tlen_rlen =
            le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
        for (i = 0; i < 6; i++)
-               lp->init_block.phys_addr[i] = dev->dev_addr[i];
-       lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
-       lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+               lp->init_block->phys_addr[i] = dev->dev_addr[i];
+       lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
+       lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
        wmb();                  /* Make sure all changes are visible */
        return 0;
 }
@@ -2433,7 +2422,7 @@ static int pcnet32_init_ring(struct net_device *dev)
  */
 static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
        int i;
 
@@ -2463,7 +2452,7 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
 
 static void pcnet32_tx_timeout(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr, flags;
 
        spin_lock_irqsave(&lp->lock, flags);
@@ -2504,7 +2493,7 @@ static void pcnet32_tx_timeout(struct net_device *dev)
 
 static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
        u16 status;
        int entry;
@@ -2569,7 +2558,7 @@ pcnet32_interrupt(int irq, void *dev_id)
        int boguscnt = max_interrupt_work;
 
        ioaddr = dev->base_addr;
-       lp = dev->priv;
+       lp = netdev_priv(dev);
 
        spin_lock(&lp->lock);
 
@@ -2651,7 +2640,7 @@ pcnet32_interrupt(int irq, void *dev_id)
 static int pcnet32_close(struct net_device *dev)
 {
        unsigned long ioaddr = dev->base_addr;
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long flags;
 
        del_timer_sync(&lp->watchdog_timer);
@@ -2692,7 +2681,7 @@ static int pcnet32_close(struct net_device *dev)
 
 static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
        unsigned long flags;
 
@@ -2706,8 +2695,8 @@ static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
 /* taken from the sunlance driver, which it took from the depca driver */
 static void pcnet32_load_multicast(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
-       volatile struct pcnet32_init_block *ib = &lp->init_block;
+       struct pcnet32_private *lp = netdev_priv(dev);
+       volatile struct pcnet32_init_block *ib = lp->init_block;
        volatile u16 *mcast_table = (u16 *) & ib->filter;
        struct dev_mc_list *dmi = dev->mc_list;
        unsigned long ioaddr = dev->base_addr;
@@ -2756,7 +2745,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
 static void pcnet32_set_multicast_list(struct net_device *dev)
 {
        unsigned long ioaddr = dev->base_addr, flags;
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        int csr15, suspended;
 
        spin_lock_irqsave(&lp->lock, flags);
@@ -2767,12 +2756,12 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
                if (netif_msg_hw(lp))
                        printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
                               dev->name);
-               lp->init_block.mode =
+               lp->init_block->mode =
                    le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
                                7);
                lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
        } else {
-               lp->init_block.mode =
+               lp->init_block->mode =
                    le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
                lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
                pcnet32_load_multicast(dev);
@@ -2795,7 +2784,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
 /* This routine assumes that the lp->lock is held */
 static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
        u16 val_out;
 
@@ -2811,7 +2800,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
 /* This routine assumes that the lp->lock is held */
 static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long ioaddr = dev->base_addr;
 
        if (!lp->mii)
@@ -2823,7 +2812,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
 
 static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        int rc;
        unsigned long flags;
 
@@ -2841,7 +2830,7 @@ static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
 static int pcnet32_check_otherphy(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        struct mii_if_info mii = lp->mii_if;
        u16 bmcr;
        int i;
@@ -2888,7 +2877,7 @@ static int pcnet32_check_otherphy(struct net_device *dev)
 
 static void pcnet32_check_media(struct net_device *dev, int verbose)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        int curr_link;
        int prev_link = netif_carrier_ok(dev) ? 1 : 0;
        u32 bcr9;
@@ -2944,7 +2933,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
 
 static void pcnet32_watchdog(struct net_device *dev)
 {
-       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_private *lp = netdev_priv(dev);
        unsigned long flags;
 
        /* Print the link status if it has changed */
@@ -2960,12 +2949,13 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
 
        if (dev) {
-               struct pcnet32_private *lp = dev->priv;
+               struct pcnet32_private *lp = netdev_priv(dev);
 
                unregister_netdev(dev);
                pcnet32_free_ring(dev);
                release_region(dev->base_addr, PCNET32_TOTAL_SIZE);
-               pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+               pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), 
+                                   lp->init_block, lp->init_dma_addr);
                free_netdev(dev);
                pci_disable_device(pdev);
                pci_set_drvdata(pdev, NULL);
@@ -3040,12 +3030,13 @@ static void __exit pcnet32_cleanup_module(void)
        struct net_device *next_dev;
 
        while (pcnet32_dev) {
-               struct pcnet32_private *lp = pcnet32_dev->priv;
+               struct pcnet32_private *lp = netdev_priv(pcnet32_dev);
                next_dev = lp->next;
                unregister_netdev(pcnet32_dev);
                pcnet32_free_ring(pcnet32_dev);
                release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
-               pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+               pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), 
+                                   lp->init_block, lp->init_dma_addr);
                free_netdev(pcnet32_dev);
                pcnet32_dev = next_dev;
        }
index b31ce278bf35be071e6aa5cbbfe528c36086c00f..fc4aee96cdfd87757d35786d19ddbd6211d1f8be 100644 (file)
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-/* mdiobus_register 
+/**
+ * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
+ * @bus: target mii_bus
  *
- * description: Called by a bus driver to bring up all the PHYs
- *   on a given bus, and attach them to the bus
+ * Description: Called by a bus driver to bring up all the PHYs
+ *   on a given bus, and attach them to the bus.
+ *
+ * Returns 0 on success or < 0 on error.
  */
 int mdiobus_register(struct mii_bus *bus)
 {
@@ -114,10 +118,13 @@ void mdiobus_unregister(struct mii_bus *bus)
 }
 EXPORT_SYMBOL(mdiobus_unregister);
 
-/* mdio_bus_match
+/**
+ * mdio_bus_match - determine if given PHY driver supports the given PHY device
+ * @dev: target PHY device
+ * @drv: given PHY driver
  *
- * description: Given a PHY device, and a PHY driver, return 1 if
- *   the driver supports the device.  Otherwise, return 0
+ * Description: Given a PHY device, and a PHY driver, return 1 if
+ *   the driver supports the device.  Otherwise, return 0.
  */
 static int mdio_bus_match(struct device *dev, struct device_driver *drv)
 {
index c94a1fb3a4bee56bcb9bf9d8235b3453cfce7195..eed433d6056a2ddae3bad391e09ebec087892475 100644 (file)
@@ -39,7 +39,9 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-/* Convenience function to print out the current phy status
+/**
+ * phy_print_status - Convenience function to print out the current phy status
+ * @phydev: the phy_device struct
  */
 void phy_print_status(struct phy_device *phydev)
 {
@@ -55,10 +57,15 @@ void phy_print_status(struct phy_device *phydev)
 EXPORT_SYMBOL(phy_print_status);
 
 
-/* Convenience functions for reading/writing a given PHY
- * register. They MUST NOT be called from interrupt context,
+/**
+ * phy_read - Convenience function for reading a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to read
+ *
+ * NOTE: MUST NOT be called from interrupt context,
  * because the bus read/write functions may wait for an interrupt
- * to conclude the operation. */
+ * to conclude the operation.
+ */
 int phy_read(struct phy_device *phydev, u16 regnum)
 {
        int retval;
@@ -72,6 +79,16 @@ int phy_read(struct phy_device *phydev, u16 regnum)
 }
 EXPORT_SYMBOL(phy_read);
 
+/**
+ * phy_write - Convenience function for writing a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
 int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
 {
        int err;
@@ -85,7 +102,15 @@ int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
 }
 EXPORT_SYMBOL(phy_write);
 
-
+/**
+ * phy_clear_interrupt - Ack the phy device's interrupt
+ * @phydev: the phy_device struct
+ *
+ * If the @phydev driver has an ack_interrupt function, call it to
+ * ack and clear the phy device's interrupt.
+ *
+ * Returns 0 on success on < 0 on error.
+ */
 int phy_clear_interrupt(struct phy_device *phydev)
 {
        int err = 0;
@@ -96,7 +121,13 @@ int phy_clear_interrupt(struct phy_device *phydev)
        return err;
 }
 
-
+/**
+ * phy_config_interrupt - configure the PHY device for the requested interrupts
+ * @phydev: the phy_device struct
+ * @interrupts: interrupt flags to configure for this @phydev
+ *
+ * Returns 0 on success on < 0 on error.
+ */
 int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
 {
        int err = 0;
@@ -109,9 +140,11 @@ int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
 }
 
 
-/* phy_aneg_done
+/**
+ * phy_aneg_done - return auto-negotiation status
+ * @phydev: target phy_device struct
  *
- * description: Reads the status register and returns 0 either if
+ * Description: Reads the status register and returns 0 either if
  *   auto-negotiation is incomplete, or if there was an error.
  *   Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
  */
@@ -173,9 +206,12 @@ static const struct phy_setting settings[] = {
 
 #define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))
 
-/* phy_find_setting
+/**
+ * phy_find_setting - find a PHY settings array entry that matches speed & duplex
+ * @speed: speed to match
+ * @duplex: duplex to match
  *
- * description: Searches the settings array for the setting which
+ * Description: Searches the settings array for the setting which
  *   matches the desired speed and duplex, and returns the index
  *   of that setting.  Returns the index of the last setting if
  *   none of the others match.
@@ -192,11 +228,12 @@ static inline int phy_find_setting(int speed, int duplex)
        return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
 }
 
-/* phy_find_valid
- * idx: The first index in settings[] to search
- * features: A mask of the valid settings
+/**
+ * phy_find_valid - find a PHY setting that matches the requested features mask
+ * @idx: The first index in settings[] to search
+ * @features: A mask of the valid settings
  *
- * description: Returns the index of the first valid setting less
+ * Description: Returns the index of the first valid setting less
  *   than or equal to the one pointed to by idx, as determined by
  *   the mask in features.  Returns the index of the last setting
  *   if nothing else matches.
@@ -209,11 +246,13 @@ static inline int phy_find_valid(int idx, u32 features)
        return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
 }
 
-/* phy_sanitize_settings
+/**
+ * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex
+ * @phydev: the target phy_device struct
  *
- * description: Make sure the PHY is set to supported speeds and
+ * Description: Make sure the PHY is set to supported speeds and
  *   duplexes.  Drop down by one in this order:  1000/FULL,
- *   1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF
+ *   1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
  */
 void phy_sanitize_settings(struct phy_device *phydev)
 {
@@ -232,16 +271,17 @@ void phy_sanitize_settings(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_sanitize_settings);
 
-/* phy_ethtool_sset:
- * A generic ethtool sset function.  Handles all the details
+/**
+ * phy_ethtool_sset - generic ethtool sset function, handles all the details
+ * @phydev: target phy_device struct
+ * @cmd: ethtool_cmd
  *
  * A few notes about parameter checking:
  * - We don't set port or transceiver, so we don't care what they
  *   were set to.
  * - phy_start_aneg() will make sure forced settings are sane, and
  *   choose the next best ones from the ones selected, so we don't
- *   care if ethtool tries to give us bad values
- *
+ *   care if ethtool tries to give us bad values.
  */
 int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
 {
@@ -304,9 +344,15 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
 }
 EXPORT_SYMBOL(phy_ethtool_gset);
 
-/* Note that this function is currently incompatible with the
+/**
+ * phy_mii_ioctl - generic PHY MII ioctl interface
+ * @phydev: the phy_device struct
+ * @mii_data: MII ioctl data
+ * @cmd: ioctl cmd to execute
+ *
+ * Note that this function is currently incompatible with the
  * PHYCONTROL layer.  It changes registers without regard to
- * current state.  Use at own risk
+ * current state.  Use at own risk.
  */
 int phy_mii_ioctl(struct phy_device *phydev,
                struct mii_ioctl_data *mii_data, int cmd)
@@ -336,6 +382,12 @@ int phy_mii_ioctl(struct phy_device *phydev,
                                        phydev->duplex = DUPLEX_FULL;
                                else
                                        phydev->duplex = DUPLEX_HALF;
+                               if ((!phydev->autoneg) &&
+                                               (val & BMCR_SPEED1000))
+                                       phydev->speed = SPEED_1000;
+                               else if ((!phydev->autoneg) &&
+                                               (val & BMCR_SPEED100))
+                                       phydev->speed = SPEED_100;
                                break;
                        case MII_ADVERTISE:
                                phydev->advertising = val;
@@ -358,13 +410,14 @@ int phy_mii_ioctl(struct phy_device *phydev,
        return 0;
 }
 
-/* phy_start_aneg
+/**
+ * phy_start_aneg - start auto-negotiation for this PHY device
+ * @phydev: the phy_device struct
  *
- * description: Sanitizes the settings (if we're not
- *   autonegotiating them), and then calls the driver's
- *   config_aneg function.  If the PHYCONTROL Layer is operating,
- *   we change the state to reflect the beginning of
- *   Auto-negotiation or forcing.
+ * Description: Sanitizes the settings (if we're not autonegotiating
+ *   them), and then calls the driver's config_aneg function.
+ *   If the PHYCONTROL Layer is operating, we change the state to
+ *   reflect the beginning of Auto-negotiation or forcing.
  */
 int phy_start_aneg(struct phy_device *phydev)
 {
@@ -400,15 +453,19 @@ EXPORT_SYMBOL(phy_start_aneg);
 static void phy_change(struct work_struct *work);
 static void phy_timer(unsigned long data);
 
-/* phy_start_machine:
+/**
+ * phy_start_machine - start PHY state machine tracking
+ * @phydev: the phy_device struct
+ * @handler: callback function for state change notifications
  *
- * description: The PHY infrastructure can run a state machine
+ * Description: The PHY infrastructure can run a state machine
  *   which tracks whether the PHY is starting up, negotiating,
  *   etc.  This function starts the timer which tracks the state
- *   of the PHY.  If you want to be notified when the state
- *   changes, pass in the callback, otherwise, pass NULL.  If you
+ *   of the PHY.  If you want to be notified when the state changes,
+ *   pass in the callback @handler, otherwise, pass NULL.  If you
  *   want to maintain your own state machine, do not call this
- *   function. */
+ *   function.
+ */
 void phy_start_machine(struct phy_device *phydev,
                void (*handler)(struct net_device *))
 {
@@ -420,9 +477,11 @@ void phy_start_machine(struct phy_device *phydev,
        mod_timer(&phydev->phy_timer, jiffies + HZ);
 }
 
-/* phy_stop_machine
+/**
+ * phy_stop_machine - stop the PHY state machine tracking
+ * @phydev: target phy_device struct
  *
- * description: Stops the state machine timer, sets the state to UP
+ * Description: Stops the state machine timer, sets the state to UP
  *   (unless it wasn't up yet). This function must be called BEFORE
  *   phy_detach.
  */
@@ -438,12 +497,14 @@ void phy_stop_machine(struct phy_device *phydev)
        phydev->adjust_state = NULL;
 }
 
-/* phy_force_reduction
+/**
+ * phy_force_reduction - reduce PHY speed/duplex settings by one step
+ * @phydev: target phy_device struct
  *
- * description: Reduces the speed/duplex settings by
- *   one notch.  The order is so:
- *   1000/FULL, 1000/HALF, 100/FULL, 100/HALF,
- *   10/FULL, 10/HALF.  The function bottoms out at 10/HALF.
+ * Description: Reduces the speed/duplex settings by one notch,
+ *   in this order--
+ *   1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
+ *   The function bottoms out at 10/HALF.
  */
 static void phy_force_reduction(struct phy_device *phydev)
 {
@@ -464,7 +525,9 @@ static void phy_force_reduction(struct phy_device *phydev)
 }
 
 
-/* phy_error:
+/**
+ * phy_error - enter HALTED state for this PHY device
+ * @phydev: target phy_device struct
  *
  * Moves the PHY to the HALTED state in response to a read
  * or write error, and tells the controller the link is down.
@@ -478,9 +541,12 @@ void phy_error(struct phy_device *phydev)
        spin_unlock(&phydev->lock);
 }
 
-/* phy_interrupt
+/**
+ * phy_interrupt - PHY interrupt handler
+ * @irq: interrupt line
+ * @phy_dat: phy_device pointer
  *
- * description: When a PHY interrupt occurs, the handler disables
+ * Description: When a PHY interrupt occurs, the handler disables
  * interrupts, and schedules a work task to clear the interrupt.
  */
 static irqreturn_t phy_interrupt(int irq, void *phy_dat)
@@ -501,7 +567,10 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
        return IRQ_HANDLED;
 }
 
-/* Enable the interrupts from the PHY side */
+/**
+ * phy_enable_interrupts - Enable the interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
 int phy_enable_interrupts(struct phy_device *phydev)
 {
        int err;
@@ -517,7 +586,10 @@ int phy_enable_interrupts(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_enable_interrupts);
 
-/* Disable the PHY interrupts from the PHY side */
+/**
+ * phy_disable_interrupts - Disable the PHY interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
 int phy_disable_interrupts(struct phy_device *phydev)
 {
        int err;
@@ -543,13 +615,15 @@ phy_err:
 }
 EXPORT_SYMBOL(phy_disable_interrupts);
 
-/* phy_start_interrupts
+/**
+ * phy_start_interrupts - request and enable interrupts for a PHY device
+ * @phydev: target phy_device struct
  *
- * description: Request the interrupt for the given PHY.  If
- *   this fails, then we set irq to PHY_POLL.
+ * Description: Request the interrupt for the given PHY.
+ *   If this fails, then we set irq to PHY_POLL.
  *   Otherwise, we enable the interrupts in the PHY.
- *   Returns 0 on success.
  *   This should only be called with a valid IRQ number.
+ *   Returns 0 on success or < 0 on error.
  */
 int phy_start_interrupts(struct phy_device *phydev)
 {
@@ -574,6 +648,10 @@ int phy_start_interrupts(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_start_interrupts);
 
+/**
+ * phy_stop_interrupts - disable interrupts from a PHY device
+ * @phydev: target phy_device struct
+ */
 int phy_stop_interrupts(struct phy_device *phydev)
 {
        int err;
@@ -596,7 +674,10 @@ int phy_stop_interrupts(struct phy_device *phydev)
 EXPORT_SYMBOL(phy_stop_interrupts);
 
 
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
+/**
+ * phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes
+ * @work: work_struct that describes the work to be done
+ */
 static void phy_change(struct work_struct *work)
 {
        int err;
@@ -630,7 +711,10 @@ phy_err:
        phy_error(phydev);
 }
 
-/* Bring down the PHY link, and stop checking the status. */
+/**
+ * phy_stop - Bring down the PHY link, and stop checking the status
+ * @phydev: target phy_device struct
+ */
 void phy_stop(struct phy_device *phydev)
 {
        spin_lock(&phydev->lock);
@@ -659,9 +743,11 @@ out_unlock:
 }
 
 
-/* phy_start
+/**
+ * phy_start - start or restart a PHY device
+ * @phydev: target phy_device struct
  *
- * description: Indicates the attached device's readiness to
+ * Description: Indicates the attached device's readiness to
  *   handle PHY-related work.  Used during startup to start the
  *   PHY, and after a call to phy_stop() to resume operation.
  *   Also used to indicate the MDIO bus has cleared an error
index 8f01952c48500457315624a2b6f962a8043ab838..a8b74cdab1ea2793b9f30822b416f652f883b521 100644 (file)
@@ -74,11 +74,13 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
 }
 EXPORT_SYMBOL(phy_device_create);
 
-/* get_phy_device
+/**
+ * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
  *
- * description: Reads the ID registers of the PHY at addr on the
- *   bus, then allocates and returns the phy_device to
- *   represent it.
+ * Description: Reads the ID registers of the PHY at @addr on the
+ *   @bus, then allocates and returns the phy_device to represent it.
  */
 struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
 {
@@ -112,23 +114,33 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
        return dev;
 }
 
-/* phy_prepare_link:
+/**
+ * phy_prepare_link - prepares the PHY layer to monitor link status
+ * @phydev: target phy_device struct
+ * @handler: callback function for link status change notifications
  *
- * description: Tells the PHY infrastructure to handle the
+ * Description: Tells the PHY infrastructure to handle the
  *   gory details on monitoring link status (whether through
  *   polling or an interrupt), and to call back to the
  *   connected device driver when the link status changes.
  *   If you want to monitor your own link state, don't call
- *   this function */
+ *   this function.
+ */
 void phy_prepare_link(struct phy_device *phydev,
                void (*handler)(struct net_device *))
 {
        phydev->adjust_link = handler;
 }
 
-/* phy_connect:
+/**
+ * phy_connect - connect an ethernet device to a PHY device
+ * @dev: the network device to connect
+ * @phy_id: the PHY device to connect
+ * @handler: callback function for state change notifications
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
  *
- * description: Convenience function for connecting ethernet
+ * Description: Convenience function for connecting ethernet
  *   devices to PHY devices.  The default behavior is for
  *   the PHY infrastructure to handle everything, and only notify
  *   the connected driver when the link status changes.  If you
@@ -158,6 +170,10 @@ struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
 }
 EXPORT_SYMBOL(phy_connect);
 
+/**
+ * phy_disconnect - disable interrupts, stop state machine, and detach a PHY device
+ * @phydev: target phy_device struct
+ */
 void phy_disconnect(struct phy_device *phydev)
 {
        if (phydev->irq > 0)
@@ -171,21 +187,25 @@ void phy_disconnect(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_disconnect);
 
-/* phy_attach:
+static int phy_compare_id(struct device *dev, void *data)
+{
+       return strcmp((char *)data, dev->bus_id) ? 0 : 1;
+}
+
+/**
+ * phy_attach - attach a network device to a particular PHY device
+ * @dev: network device to attach
+ * @phy_id: PHY device to attach
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
  *
- *   description: Called by drivers to attach to a particular PHY
+ * Description: Called by drivers to attach to a particular PHY
  *     device. The phy_device is found, and properly hooked up
  *     to the phy_driver.  If no driver is attached, then the
  *     genphy_driver is used.  The phy_device is given a ptr to
  *     the attaching device, and given a callback for link status
- *     change.  The phy_device is returned to the attaching
- *     driver.
+ *     change.  The phy_device is returned to the attaching driver.
  */
-static int phy_compare_id(struct device *dev, void *data)
-{
-       return strcmp((char *)data, dev->bus_id) ? 0 : 1;
-}
-
 struct phy_device *phy_attach(struct net_device *dev,
                const char *phy_id, u32 flags, phy_interface_t interface)
 {
@@ -246,6 +266,10 @@ struct phy_device *phy_attach(struct net_device *dev,
 }
 EXPORT_SYMBOL(phy_attach);
 
+/**
+ * phy_detach - detach a PHY device from its network device
+ * @phydev: target phy_device struct
+ */
 void phy_detach(struct phy_device *phydev)
 {
        phydev->attached_dev = NULL;
@@ -262,11 +286,13 @@ EXPORT_SYMBOL(phy_detach);
 
 /* Generic PHY support and helper functions */
 
-/* genphy_config_advert
+/**
+ * genphy_config_advert - sanitize and advertise auto-negotation parameters
+ * @phydev: target phy_device struct
  *
- * description: Writes MII_ADVERTISE with the appropriate values,
+ * Description: Writes MII_ADVERTISE with the appropriate values,
  *   after sanitizing the values to make sure we only advertise
- *   what is supported
+ *   what is supported.
  */
 int genphy_config_advert(struct phy_device *phydev)
 {
@@ -328,11 +354,14 @@ int genphy_config_advert(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_config_advert);
 
-/* genphy_setup_forced
+/**
+ * genphy_setup_forced - configures/forces speed/duplex from @phydev
+ * @phydev: target phy_device struct
  *
- * description: Configures MII_BMCR to force speed/duplex
+ * Description: Configures MII_BMCR to force speed/duplex
  *   to the values in phydev. Assumes that the values are valid.
- *   Please see phy_sanitize_settings() */
+ *   Please see phy_sanitize_settings().
+ */
 int genphy_setup_forced(struct phy_device *phydev)
 {
        int ctl = BMCR_RESET;
@@ -361,7 +390,10 @@ int genphy_setup_forced(struct phy_device *phydev)
 }
 
 
-/* Enable and Restart Autonegotiation */
+/**
+ * genphy_restart_aneg - Enable and Restart Autonegotiation
+ * @phydev: target phy_device struct
+ */
 int genphy_restart_aneg(struct phy_device *phydev)
 {
        int ctl;
@@ -382,11 +414,13 @@ int genphy_restart_aneg(struct phy_device *phydev)
 }
 
 
-/* genphy_config_aneg
+/**
+ * genphy_config_aneg - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
  *
- * description: If auto-negotiation is enabled, we configure the
+ * Description: If auto-negotiation is enabled, we configure the
  *   advertising, and then restart auto-negotiation.  If it is not
- *   enabled, then we write the BMCR
+ *   enabled, then we write the BMCR.
  */
 int genphy_config_aneg(struct phy_device *phydev)
 {
@@ -406,11 +440,13 @@ int genphy_config_aneg(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_config_aneg);
 
-/* genphy_update_link
+/**
+ * genphy_update_link - update link status in @phydev
+ * @phydev: target phy_device struct
  *
- * description: Update the value in phydev->link to reflect the
+ * Description: Update the value in phydev->link to reflect the
  *   current link value.  In order to do this, we need to read
- *   the status register twice, keeping the second value
+ *   the status register twice, keeping the second value.
  */
 int genphy_update_link(struct phy_device *phydev)
 {
@@ -437,9 +473,11 @@ int genphy_update_link(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_update_link);
 
-/* genphy_read_status
+/**
+ * genphy_read_status - check the link status and update current link state
+ * @phydev: target phy_device struct
  *
- * description: Check the link, then figure out the current state
+ * Description: Check the link, then figure out the current state
  *   by comparing what we advertise with what the link partner
  *   advertises.  Start by checking the gigabit possibilities,
  *   then move on to 10/100.
@@ -579,9 +617,11 @@ static int genphy_config_init(struct phy_device *phydev)
 }
 
 
-/* phy_probe
+/**
+ * phy_probe - probe and init a PHY device
+ * @dev: device to probe and init
  *
- * description: Take care of setting up the phy_device structure,
+ * Description: Take care of setting up the phy_device structure,
  *   set the state to READY (the driver's init function should
  *   set it to STARTING if needed).
  */
@@ -643,6 +683,10 @@ static int phy_remove(struct device *dev)
        return 0;
 }
 
+/**
+ * phy_driver_register - register a phy_driver with the PHY layer
+ * @new_driver: new phy_driver to register
+ */
 int phy_driver_register(struct phy_driver *new_driver)
 {
        int retval;
index 7b80fb7a9d9babb7af240859c3f3d24cafcc9958..d8766c0e825585c230171dcb57cc0a627a791c5f 100755 (executable)
@@ -39,7 +39,7 @@
 
 #define DRV_NAME       "qla3xxx"
 #define DRV_STRING     "QLogic ISP3XXX Network Driver"
-#define DRV_VERSION    "v2.03.00-k3"
+#define DRV_VERSION    "v2.03.00-k4"
 #define PFX            DRV_NAME " "
 
 static const char ql3xxx_driver_name[] = DRV_NAME;
@@ -71,6 +71,30 @@ static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl);
 
+/*
+ *  These are the known PHY's which are used
+ */
+typedef enum {
+   PHY_TYPE_UNKNOWN   = 0,
+   PHY_VITESSE_VSC8211,
+   PHY_AGERE_ET1011C,
+   MAX_PHY_DEV_TYPES
+} PHY_DEVICE_et;
+
+typedef struct {
+       PHY_DEVICE_et phyDevice; 
+       u32             phyIdOUI;
+       u16             phyIdModel;
+       char            *name;
+} PHY_DEVICE_INFO_t;
+
+static const PHY_DEVICE_INFO_t PHY_DEVICES[] =
+       {{PHY_TYPE_UNKNOWN,    0x000000, 0x0, "PHY_TYPE_UNKNOWN"},
+        {PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"},
+        {PHY_AGERE_ET1011C,   0x00a0bc, 0x1, "PHY_AGERE_ET1011C"},
+};
+
+
 /*
  * Caller must take hw_lock.
  */
@@ -662,7 +686,7 @@ static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev)
 }
 
 static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
-                              u16 regAddr, u16 value, u32 mac_index)
+                              u16 regAddr, u16 value, u32 phyAddr)
 {
        struct ql3xxx_port_registers __iomem *port_regs =
                        qdev->mem_map_registers;
@@ -680,7 +704,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
        }
 
        ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
-                          PHYAddr[mac_index] | regAddr);
+                          phyAddr | regAddr);
 
        ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
 
@@ -701,7 +725,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
 }
 
 static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
-                             u16 * value, u32 mac_index)
+                             u16 * value, u32 phyAddr)
 {
        struct ql3xxx_port_registers __iomem *port_regs =
                        qdev->mem_map_registers;
@@ -720,7 +744,7 @@ static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
        }
 
        ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
-                          PHYAddr[mac_index] | regAddr);
+                          phyAddr | regAddr);
 
        ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
                           (MAC_MII_CONTROL_RC << 16));
@@ -850,28 +874,31 @@ static void ql_petbi_start_neg(struct ql3_adapter *qdev)
 
 }
 
-static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_reset_ex(struct ql3_adapter *qdev)
 {
        ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET,
-                           mac_index);
+                           PHYAddr[qdev->mac_index]);
 }
 
-static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev)
 {
        u16 reg;
 
        /* Enable Auto-negotiation sense */
-       ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg, mac_index);
+       ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg, 
+                          PHYAddr[qdev->mac_index]);
        reg |= PETBI_TBI_AUTO_SENSE;
-       ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, mac_index);
+       ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, 
+                           PHYAddr[qdev->mac_index]);
 
        ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
-                           PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index);
+                           PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, 
+                           PHYAddr[qdev->mac_index]);
 
        ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG,
                            PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
                            PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000,
-                           mac_index);
+                           PHYAddr[qdev->mac_index]);
 }
 
 static void ql_petbi_init(struct ql3_adapter *qdev)
@@ -880,10 +907,10 @@ static void ql_petbi_init(struct ql3_adapter *qdev)
        ql_petbi_start_neg(qdev);
 }
 
-static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_init_ex(struct ql3_adapter *qdev)
 {
-       ql_petbi_reset_ex(qdev, mac_index);
-       ql_petbi_start_neg_ex(qdev, mac_index);
+       ql_petbi_reset_ex(qdev);
+       ql_petbi_start_neg_ex(qdev);
 }
 
 static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
@@ -896,33 +923,128 @@ static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
        return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE;
 }
 
+static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
+{
+       printk(KERN_INFO "%s: enabling Agere specific PHY\n", qdev->ndev->name);
+       /* power down device bit 11 = 1 */
+       ql_mii_write_reg_ex(qdev, 0x00, 0x1940, miiAddr);
+       /* enable diagnostic mode bit 2 = 1 */
+       ql_mii_write_reg_ex(qdev, 0x12, 0x840e, miiAddr);
+       /* 1000MB amplitude adjust (see Agere errata) */
+       ql_mii_write_reg_ex(qdev, 0x10, 0x8805, miiAddr);
+       /* 1000MB amplitude adjust (see Agere errata) */
+       ql_mii_write_reg_ex(qdev, 0x11, 0xf03e, miiAddr);
+       /* 100MB amplitude adjust (see Agere errata) */
+       ql_mii_write_reg_ex(qdev, 0x10, 0x8806, miiAddr);
+       /* 100MB amplitude adjust (see Agere errata) */
+       ql_mii_write_reg_ex(qdev, 0x11, 0x003e, miiAddr);
+       /* 10MB amplitude adjust (see Agere errata) */
+       ql_mii_write_reg_ex(qdev, 0x10, 0x8807, miiAddr);
+       /* 10MB amplitude adjust (see Agere errata) */
+       ql_mii_write_reg_ex(qdev, 0x11, 0x1f00, miiAddr);
+       /* point to hidden reg 0x2806 */
+       ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr);
+       /* Write new PHYAD w/bit 5 set */
+       ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
+       /* 
+        * Disable diagnostic mode bit 2 = 0
+        * Power up device bit 11 = 0
+        * Link up (on) and activity (blink)
+        */
+       ql_mii_write_reg(qdev, 0x12, 0x840a);
+       ql_mii_write_reg(qdev, 0x00, 0x1140);
+       ql_mii_write_reg(qdev, 0x1c, 0xfaf0);
+}
+
+static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, 
+                                u16 phyIdReg0, u16 phyIdReg1)
+{
+       PHY_DEVICE_et result = PHY_TYPE_UNKNOWN;
+       u32   oui;     
+       u16   model;
+       int i;   
+
+       if (phyIdReg0 == 0xffff) {
+               return result;
+       }
+   
+       if (phyIdReg1 == 0xffff) {
+               return result;
+       }
+
+       /* oui is split between two registers */
+       oui = (phyIdReg0 << 6) | ((phyIdReg1 & PHY_OUI_1_MASK) >> 10);
+
+       model = (phyIdReg1 & PHY_MODEL_MASK) >> 4;
+
+       /* Scan table for this PHY */
+       for(i = 0; i < MAX_PHY_DEV_TYPES; i++) {
+               if ((oui == PHY_DEVICES[i].phyIdOUI) && (model == PHY_DEVICES[i].phyIdModel))
+               {
+                       result = PHY_DEVICES[i].phyDevice;
+
+                       printk(KERN_INFO "%s: Phy: %s\n",
+                               qdev->ndev->name, PHY_DEVICES[i].name);
+                       
+                       break;
+               }
+       }
+
+       return result;
+}
+
 static int ql_phy_get_speed(struct ql3_adapter *qdev)
 {
        u16 reg;
 
+       switch(qdev->phyType) {
+       case PHY_AGERE_ET1011C:
+       {
+               if (ql_mii_read_reg(qdev, 0x1A, &reg) < 0)
+                       return 0;
+
+               reg = (reg >> 8) & 3;
+               break;
+       }
+       default:
        if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
                return 0;
 
        reg = (((reg & 0x18) >> 3) & 3);
+       }
 
-       if (reg == 2)
+       switch(reg) {
+               case 2:
                return SPEED_1000;
-       else if (reg == 1)
+               case 1:
                return SPEED_100;
-       else if (reg == 0)
+               case 0:
                return SPEED_10;
-       else
+               default:
                return -1;
+       }
 }
 
 static int ql_is_full_dup(struct ql3_adapter *qdev)
 {
        u16 reg;
 
-       if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
-               return 0;
-
-       return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+       switch(qdev->phyType) {
+       case PHY_AGERE_ET1011C:
+       {
+               if (ql_mii_read_reg(qdev, 0x1A, &reg))
+                       return 0;
+                       
+               return ((reg & 0x0080) && (reg & 0x1000)) != 0;
+       }
+       case PHY_VITESSE_VSC8211:
+       default:
+       {
+               if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+                       return 0;
+               return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+       }
+       }
 }
 
 static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
@@ -935,6 +1057,73 @@ static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
        return (reg & PHY_NEG_PAUSE) != 0;
 }
 
+static int PHY_Setup(struct ql3_adapter *qdev)
+{
+       u16   reg1;
+       u16   reg2;
+       bool  agereAddrChangeNeeded = false;
+       u32 miiAddr = 0;
+       int err;
+
+       /*  Determine the PHY we are using by reading the ID's */
+       err = ql_mii_read_reg(qdev, PHY_ID_0_REG, &reg1);
+       if(err != 0) {
+               printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
+                      qdev->ndev->name);
+                return err;
+       }
+
+       err = ql_mii_read_reg(qdev, PHY_ID_1_REG, &reg2);
+       if(err != 0) {
+               printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
+                      qdev->ndev->name);
+                return err;
+       }
+
+       /*  Check if we have a Agere PHY */
+       if ((reg1 == 0xffff) || (reg2 == 0xffff)) {
+
+               /* Determine which MII address we should be using 
+                  determined by the index of the card */
+               if (qdev->mac_index == 0) {
+                       miiAddr = MII_AGERE_ADDR_1;
+               } else {
+                       miiAddr = MII_AGERE_ADDR_2;
+               }
+      
+               err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
+               if(err != 0) {
+                       printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
+                              qdev->ndev->name);
+                       return err; 
+               }
+
+               err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, &reg2, miiAddr);
+               if(err != 0) {
+                       printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
+                              qdev->ndev->name);
+                       return err;
+               }
+   
+               /*  We need to remember to initialize the Agere PHY */
+               agereAddrChangeNeeded = true; 
+       }
+
+       /*  Determine the particular PHY we have on board to apply
+           PHY specific initializations */
+       qdev->phyType = getPhyType(qdev, reg1, reg2);
+
+       if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) {
+               /* need this here so address gets changed */
+               phyAgereSpecificInit(qdev, miiAddr);  
+       } else if (qdev->phyType == PHY_TYPE_UNKNOWN) {
+               printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name);
+               return -EIO;
+       }
+
+       return 0;
+}
+
 /*
  * Caller holds hw_lock.
  */
@@ -1205,15 +1394,14 @@ static int ql_link_down_detect_clear(struct ql3_adapter *qdev)
 /*
  * Caller holds hw_lock.
  */
-static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
-                                        u32 mac_index)
+static int ql_this_adapter_controls_port(struct ql3_adapter *qdev)
 {
        struct ql3xxx_port_registers __iomem *port_regs =
                        qdev->mem_map_registers;
        u32 bitToCheck = 0;
        u32 temp;
 
-       switch (mac_index) {
+       switch (qdev->mac_index) {
        case 0:
                bitToCheck = PORT_STATUS_F1_ENABLED;
                break;
@@ -1238,27 +1426,96 @@ static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
        }
 }
 
-static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_reset_ex(struct ql3_adapter *qdev)
 {
-       ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index);
+       ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, 
+                           PHYAddr[qdev->mac_index]);
 }
 
-static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
 {
        u16 reg;
+       u16 portConfiguration;
+
+       if(qdev->phyType == PHY_AGERE_ET1011C) {
+               /* turn off external loopback */
+               ql_mii_write_reg(qdev, 0x13, 0x0000); 
+       }
+
+       if(qdev->mac_index == 0)
+               portConfiguration = qdev->nvram_data.macCfg_port0.portConfiguration;
+       else
+               portConfiguration = qdev->nvram_data.macCfg_port1.portConfiguration;
+
+       /*  Some HBA's in the field are set to 0 and they need to
+           be reinterpreted with a default value */
+       if(portConfiguration == 0)
+               portConfiguration = PORT_CONFIG_DEFAULT;
+
+       /* Set the 1000 advertisements */
+       ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, &reg, 
+                          PHYAddr[qdev->mac_index]);
+       reg &= ~PHY_GIG_ALL_PARAMS;
+
+       if(portConfiguration & 
+          PORT_CONFIG_FULL_DUPLEX_ENABLED &
+          PORT_CONFIG_1000MB_SPEED) {
+               reg |= PHY_GIG_ADV_1000F;
+       }
+        
+       if(portConfiguration & 
+          PORT_CONFIG_HALF_DUPLEX_ENABLED &
+          PORT_CONFIG_1000MB_SPEED) {
+               reg |= PHY_GIG_ADV_1000H;
+       }
 
-       ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER,
-                           PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index);
+       ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg, 
+                           PHYAddr[qdev->mac_index]);
 
-       ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, mac_index);
-       ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG,
-                           mac_index);
+       /* Set the 10/100 & pause negotiation advertisements */
+       ql_mii_read_reg_ex(qdev, PHY_NEG_ADVER, &reg,
+                          PHYAddr[qdev->mac_index]);
+       reg &= ~PHY_NEG_ALL_PARAMS;
+
+       if(portConfiguration & PORT_CONFIG_SYM_PAUSE_ENABLED)
+               reg |= PHY_NEG_ASY_PAUSE | PHY_NEG_SYM_PAUSE;
+
+       if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
+               if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+                       reg |= PHY_NEG_ADV_100F;
+               
+               if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+                       reg |= PHY_NEG_ADV_10F;
+       }
+
+       if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
+               if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+                       reg |= PHY_NEG_ADV_100H;
+               
+               if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+                       reg |= PHY_NEG_ADV_10H;
+       }
+
+       if(portConfiguration &
+          PORT_CONFIG_1000MB_SPEED) {
+               reg |= 1;       
+       }
+
+       ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg, 
+                           PHYAddr[qdev->mac_index]);
+
+       ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, PHYAddr[qdev->mac_index]);
+       
+       ql_mii_write_reg_ex(qdev, CONTROL_REG, 
+                           reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG,
+                           PHYAddr[qdev->mac_index]);
 }
 
-static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_init_ex(struct ql3_adapter *qdev)
 {
-       ql_phy_reset_ex(qdev, mac_index);
-       ql_phy_start_neg_ex(qdev, mac_index);
+       ql_phy_reset_ex(qdev);
+       PHY_Setup(qdev);
+       ql_phy_start_neg_ex(qdev);
 }
 
 /*
@@ -1295,14 +1552,17 @@ static int ql_port_start(struct ql3_adapter *qdev)
 {
        if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
                (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
-                        2) << 7))
+                        2) << 7)) {
+               printk(KERN_ERR "%s: Could not get hw lock for GIO\n",
+                      qdev->ndev->name);
                return -1;
+       }
 
        if (ql_is_fiber(qdev)) {
                ql_petbi_init(qdev);
        } else {
                /* Copper port */
-               ql_phy_init_ex(qdev, qdev->mac_index);
+               ql_phy_init_ex(qdev);
        }
 
        ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
@@ -1453,7 +1713,7 @@ static void ql_link_state_machine(struct ql3_adapter *qdev)
  */
 static void ql_get_phy_owner(struct ql3_adapter *qdev)
 {
-       if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+       if (ql_this_adapter_controls_port(qdev))
                set_bit(QL_LINK_MASTER,&qdev->flags);
        else
                clear_bit(QL_LINK_MASTER,&qdev->flags);
@@ -1467,11 +1727,11 @@ static void ql_init_scan_mode(struct ql3_adapter *qdev)
        ql_mii_enable_scan_mode(qdev);
 
        if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
-               if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
-                       ql_petbi_init_ex(qdev, qdev->mac_index);
+               if (ql_this_adapter_controls_port(qdev))
+                       ql_petbi_init_ex(qdev);
        } else {
-               if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
-                       ql_phy_init_ex(qdev, qdev->mac_index);
+               if (ql_this_adapter_controls_port(qdev))
+                       ql_phy_init_ex(qdev);
        }
 }
 
@@ -1624,6 +1884,23 @@ static void ql_set_msglevel(struct net_device *ndev, u32 value)
        qdev->msg_enable = value;
 }
 
+static void ql_get_pauseparam(struct net_device *ndev,
+                             struct ethtool_pauseparam *pause)
+{
+       struct ql3_adapter *qdev = netdev_priv(ndev);
+       struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+       u32 reg;
+       if(qdev->mac_index == 0)
+               reg = ql_read_page0_reg(qdev, &port_regs->mac0ConfigReg);
+       else
+               reg = ql_read_page0_reg(qdev, &port_regs->mac1ConfigReg);
+
+       pause->autoneg  = ql_get_auto_cfg_status(qdev);
+       pause->rx_pause = (reg & MAC_CONFIG_REG_RF) >> 2;
+       pause->tx_pause = (reg & MAC_CONFIG_REG_TF) >> 1;
+}
+
 static const struct ethtool_ops ql3xxx_ethtool_ops = {
        .get_settings = ql_get_settings,
        .get_drvinfo = ql_get_drvinfo,
@@ -1631,6 +1908,7 @@ static const struct ethtool_ops ql3xxx_ethtool_ops = {
        .get_link = ethtool_op_get_link,
        .get_msglevel = ql_get_msglevel,
        .set_msglevel = ql_set_msglevel,
+       .get_pauseparam = ql_get_pauseparam,
 };
 
 static int ql_populate_free_queue(struct ql3_adapter *qdev)
@@ -1815,14 +2093,14 @@ invalid_seg_count:
        atomic_inc(&qdev->tx_count);
 }
 
-void ql_get_sbuf(struct ql3_adapter *qdev)
+static void ql_get_sbuf(struct ql3_adapter *qdev)
 {
        if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
                qdev->small_buf_index = 0;
        qdev->small_buf_release_cnt++;
 }
 
-struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
+static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
 {
        struct ql_rcv_buf_cb *lrg_buf_cb = NULL;
        lrg_buf_cb = &qdev->lrg_buf[qdev->lrg_buf_index];
@@ -3074,6 +3352,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
                goto out;
        }
 
+       PHY_Setup(qdev);
        ql_init_scan_mode(qdev);
        ql_get_phy_owner(qdev);
 
index 0203f88f0544413eb52c6a30c5c70797435aff92..4a832c46c274813541731937374389caad3efbe9 100755 (executable)
@@ -293,6 +293,16 @@ struct net_rsp_iocb {
 
 #define MII_SCAN_REGISTER 0x00000001
 
+#define PHY_ID_0_REG    2
+#define PHY_ID_1_REG    3
+
+#define PHY_OUI_1_MASK       0xfc00
+#define PHY_MODEL_MASK       0x03f0
+
+/*  Address for the Agere Phy */
+#define MII_AGERE_ADDR_1  0x00001000
+#define MII_AGERE_ADDR_2  0x00001100
+
 /* 32-bit ispControlStatus */
 enum {
        ISP_CONTROL_NP_MASK = 0x0003,
@@ -789,6 +799,7 @@ enum {
        PHY_CTRL_LOOPBACK = 0x4000,
 
        PETBI_CONTROL_REG = 0x00,
+       PETBI_CTRL_ALL_PARAMS = 0x7140,
        PETBI_CTRL_SOFT_RESET = 0x8000,
        PETBI_CTRL_AUTO_NEG = 0x1000,
        PETBI_CTRL_RESTART_NEG = 0x0200,
@@ -811,6 +822,23 @@ enum {
        PETBI_EXPANSION_REG = 0x06,
        PETBI_EXP_PAGE_RX = 0x0002,
 
+       PHY_GIG_CONTROL = 9,
+       PHY_GIG_ENABLE_MAN = 0x1000,  /* Enable Master/Slave Manual Config*/
+       PHY_GIG_SET_MASTER = 0x0800,  /* Set Master (slave if clear)*/
+       PHY_GIG_ALL_PARAMS = 0x0300,
+       PHY_GIG_ADV_1000F = 0x0200,
+       PHY_GIG_ADV_1000H = 0x0100,
+
+       PHY_NEG_ADVER = 4,
+       PHY_NEG_ALL_PARAMS = 0x0fe0,
+       PHY_NEG_ASY_PAUSE =  0x0800,
+       PHY_NEG_SYM_PAUSE =  0x0400,
+       PHY_NEG_ADV_SPEED =  0x01e0,
+       PHY_NEG_ADV_100F =   0x0100,
+       PHY_NEG_ADV_100H =   0x0080,
+       PHY_NEG_ADV_10F =    0x0040,
+       PHY_NEG_ADV_10H =    0x0020,
+
        PETBI_TBI_CTRL = 0x11,
        PETBI_TBI_RESET = 0x8000,
        PETBI_TBI_AUTO_SENSE = 0x0100,
@@ -826,8 +854,7 @@ enum {
        PHY_AUX_RESET_STICK = 0x0002,
        PHY_NEG_PAUSE = 0x0400,
        PHY_CTRL_SOFT_RESET = 0x8000,
-       PHY_NEG_ADVER = 4,
-       PHY_NEG_ADV_SPEED = 0x01e0,
+       PHY_CTRL_AUTO_NEG = 0x1000,
        PHY_CTRL_RESTART_NEG = 0x0200,
 };
 enum {
@@ -892,6 +919,7 @@ enum {EEPROM_SIZE = FM93C86A_SIZE_16,
        u16 pauseThreshold_mac;
        u16 resumeThreshold_mac;
        u16 portConfiguration;
+#define PORT_CONFIG_DEFAULT                 0xf700
 #define PORT_CONFIG_AUTO_NEG_ENABLED        0x8000
 #define PORT_CONFIG_SYM_PAUSE_ENABLED       0x4000
 #define PORT_CONFIG_FULL_DUPLEX_ENABLED     0x2000
@@ -1259,6 +1287,7 @@ struct ql3_adapter {
        struct delayed_work tx_timeout_work;
        u32 max_frame_size;
        u32 device_id;
+       u16 phyType;
 };
 
 #endif                         /* _QLA3XXX_H_ */
index 33fb7f3b7041800e87b73f0d63c782551ab1f478..4cb710bbe72909ff3f010ea850e240823c942a20 100644 (file)
@@ -1,6 +1,6 @@
 /************************************************************************
  * regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
index 600d3ff347fc83229cf7cbbb49fe4aa8e3810491..290e1c1f30c6b0792953a6a285b6e60cfce03620 100644 (file)
@@ -1,6 +1,6 @@
 /************************************************************************
  * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
@@ -84,7 +84,7 @@
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.17.1"
+#define DRV_VERSION "2.0.22.1"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -316,7 +316,7 @@ static void s2io_vlan_rx_register(struct net_device *dev,
 }
 
 /* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
-int vlan_strip_flag;
+static int vlan_strip_flag;
 
 /* Unregister the vlan */
 static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
@@ -394,7 +394,6 @@ static const u64 fix_mac[] = {
        END_SIGN
 };
 
-MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
@@ -516,7 +515,7 @@ static int init_shared_mem(struct s2io_nic *nic)
                mac_control->fifos[i].list_info = kmalloc(list_holder_size,
                                                          GFP_KERNEL);
                if (!mac_control->fifos[i].list_info) {
-                       DBG_PRINT(ERR_DBG,
+                       DBG_PRINT(INFO_DBG,
                                  "Malloc failed for list_info\n");
                        return -ENOMEM;
                }
@@ -542,9 +541,9 @@ static int init_shared_mem(struct s2io_nic *nic)
                        tmp_v = pci_alloc_consistent(nic->pdev,
                                                     PAGE_SIZE, &tmp_p);
                        if (!tmp_v) {
-                               DBG_PRINT(ERR_DBG,
+                               DBG_PRINT(INFO_DBG,
                                          "pci_alloc_consistent ");
-                               DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+                               DBG_PRINT(INFO_DBG, "failed for TxDL\n");
                                return -ENOMEM;
                        }
                        /* If we got a zero DMA address(can happen on
@@ -561,9 +560,9 @@ static int init_shared_mem(struct s2io_nic *nic)
                                tmp_v = pci_alloc_consistent(nic->pdev,
                                                     PAGE_SIZE, &tmp_p);
                                if (!tmp_v) {
-                                       DBG_PRINT(ERR_DBG,
+                                       DBG_PRINT(INFO_DBG,
                                          "pci_alloc_consistent ");
-                                       DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+                                       DBG_PRINT(INFO_DBG, "failed for TxDL\n");
                                        return -ENOMEM;
                                }
                        }
@@ -2187,7 +2186,7 @@ static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
        /* skb_shinfo(skb)->frag_list will have L4 data payload */
        skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
        if (skb_shinfo(skb)->frag_list == NULL) {
-               DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
+               DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
                return -ENOMEM ;
        }
        frag_list = skb_shinfo(skb)->frag_list;
@@ -2242,6 +2241,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
        struct buffAdd *ba;
        unsigned long flags;
        struct RxD_t *first_rxdp = NULL;
+       u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
 
        mac_control = &nic->mac_control;
        config = &nic->config;
@@ -2313,8 +2313,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                /* allocate skb */
                skb = dev_alloc_skb(size);
                if(!skb) {
-                       DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
-                       DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+                       DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+                       DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
                        if (first_rxdp) {
                                wmb();
                                first_rxdp->Control_1 |= RXD_OWN_XENA;
@@ -2342,7 +2342,14 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                         * payload
                         */
 
+                       /* save the buffer pointers to avoid frequent dma mapping */
+                       Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr;
+                       Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr;
                        memset(rxdp, 0, sizeof(struct RxD3));
+                       /* restore the buffer pointers for dma sync*/
+                       ((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr;
+                       ((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr;
+
                        ba = &mac_control->rings[ring_no].ba[block_no][off];
                        skb_reserve(skb, BUF0_LEN);
                        tmp = (u64)(unsigned long) skb->data;
@@ -2573,8 +2580,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
 
        for (i = 0; i < config->rx_ring_num; i++) {
                if (fill_rx_buffers(nic, i) == -ENOMEM) {
-                       DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
-                       DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
+                       DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+                       DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
                        break;
                }
        }
@@ -2590,8 +2597,8 @@ no_rx:
 
        for (i = 0; i < config->rx_ring_num; i++) {
                if (fill_rx_buffers(nic, i) == -ENOMEM) {
-                       DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
-                       DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
+                       DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+                       DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
                        break;
                }
        }
@@ -2640,8 +2647,8 @@ static void s2io_netpoll(struct net_device *dev)
 
        for (i = 0; i < config->rx_ring_num; i++) {
                if (fill_rx_buffers(nic, i) == -ENOMEM) {
-                       DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
-                       DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
+                       DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+                       DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
                        break;
                }
        }
@@ -3307,6 +3314,7 @@ static void s2io_reset(struct s2io_nic * sp)
        u16 subid, pci_cmd;
        int i;
        u16 val16;
+       unsigned long long reset_cnt = 0;
        DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
                        __FUNCTION__, sp->dev->name);
 
@@ -3372,6 +3380,11 @@ new_way:
 
        /* Reset device statistics maintained by OS */
        memset(&sp->stats, 0, sizeof (struct net_device_stats));
+       /* save reset count */
+       reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt;
+       memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
+       /* restore reset count */
+       sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt;
 
        /* SXE-002: Configure link and activity LED to turn it off */
        subid = sp->pdev->subsystem_device;
@@ -3659,7 +3672,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
        nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
                               GFP_KERNEL);
        if (nic->entries == NULL) {
-               DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+               DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
                return -ENOMEM;
        }
        memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
@@ -3668,7 +3681,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
                kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
                                   GFP_KERNEL);
        if (nic->s2io_entries == NULL) {
-               DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+               DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
                kfree(nic->entries);
                return -ENOMEM;
        }
@@ -4019,7 +4032,7 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
                        DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
                        DBG_PRINT(INTR_DBG, "PANIC levels\n");
                        if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
-                               DBG_PRINT(ERR_DBG, "Out of memory in %s",
+                               DBG_PRINT(INFO_DBG, "Out of memory in %s",
                                          __FUNCTION__);
                                clear_bit(0, (&sp->tasklet_status));
                                return -1;
@@ -4029,8 +4042,8 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
                        tasklet_schedule(&sp->task);
 
        } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
-                       DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name);
-                       DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
+                       DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
+                       DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
        }
        return 0;
 }
@@ -4279,9 +4292,7 @@ static void s2io_updt_stats(struct s2io_nic *sp)
                        if (cnt == 5)
                                break; /* Updt failed */
                } while(1);
-       } else {
-               memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
-       }
+       } 
 }
 
 /**
@@ -5949,12 +5960,12 @@ static void s2io_tasklet(unsigned long dev_addr)
                for (i = 0; i < config->rx_ring_num; i++) {
                        ret = fill_rx_buffers(sp, i);
                        if (ret == -ENOMEM) {
-                               DBG_PRINT(ERR_DBG, "%s: Out of ",
+                               DBG_PRINT(INFO_DBG, "%s: Out of ",
                                          dev->name);
                                DBG_PRINT(ERR_DBG, "memory in tasklet\n");
                                break;
                        } else if (ret == -EFILL) {
-                               DBG_PRINT(ERR_DBG,
+                               DBG_PRINT(INFO_DBG,
                                          "%s: Rx Ring %d is full\n",
                                          dev->name, i);
                                break;
@@ -6065,8 +6076,8 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
                } else {
                        *skb = dev_alloc_skb(size);
                        if (!(*skb)) {
-                               DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
-                               DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+                               DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+                               DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
                                return -ENOMEM ;
                        }
                        /* storing the mapped addr in a temp variable
@@ -6088,7 +6099,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
                } else {
                        *skb = dev_alloc_skb(size);
                        if (!(*skb)) {
-                               DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
+                               DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n",
                                        dev->name);
                                return -ENOMEM;
                        }
@@ -6115,7 +6126,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
                } else {
                        *skb = dev_alloc_skb(size);
                        if (!(*skb)) {
-                               DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
+                               DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n",
                                          dev->name);
                                return -ENOMEM;
                        }
@@ -6616,7 +6627,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
 
        /* Updating statistics */
        rxdp->Host_Control = 0;
-       sp->rx_pkt_count++;
        sp->stats.rx_packets++;
        if (sp->rxd_mode == RXD_MODE_1) {
                int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
@@ -7252,7 +7262,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                goto register_failed;
        }
        s2io_vpd_read(sp);
-       DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
+       DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n");
        DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
                  sp->product_name, get_xena_rev_id(sp->pdev));
        DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
index 803137ca4b6c52f254b050d893cb9b42fe458a52..a656d18b33df200fa34c9af8f3c648c804e8c213 100644 (file)
@@ -1,6 +1,6 @@
 /************************************************************************
  * s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
@@ -760,7 +760,6 @@ struct s2io_nic {
 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
 
        struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED];
-       struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED];
 
        struct net_device_stats stats;
        int high_dma_flag;
@@ -794,11 +793,6 @@ struct s2io_nic {
        u16 all_multi_pos;
        u16 promisc_flg;
 
-       u16 tx_pkt_count;
-       u16 rx_pkt_count;
-       u16 tx_err_count;
-       u16 rx_err_count;
-
        /*  Id timer, used to blink NIC to physically identify NIC. */
        struct timer_list id_timer;
 
index 0a3a379b634c15a39de6e7f25f06d207f5630537..132e2148b21c6d5095ef1bd498df470d7fbdc936 100644 (file)
@@ -95,19 +95,28 @@ MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS));
 #endif
 
 #ifdef CONFIG_SBMAC_COALESCE
-static int int_pktcnt = 0;
-module_param(int_pktcnt, int, S_IRUGO);
-MODULE_PARM_DESC(int_pktcnt, "Packet count");
+static int int_pktcnt_tx = 255;
+module_param(int_pktcnt_tx, int, S_IRUGO);
+MODULE_PARM_DESC(int_pktcnt_tx, "TX packet count");
 
-static int int_timeout = 0;
-module_param(int_timeout, int, S_IRUGO);
-MODULE_PARM_DESC(int_timeout, "Timeout value");
+static int int_timeout_tx = 255;
+module_param(int_timeout_tx, int, S_IRUGO);
+MODULE_PARM_DESC(int_timeout_tx, "TX timeout value");
+
+static int int_pktcnt_rx = 64;
+module_param(int_pktcnt_rx, int, S_IRUGO);
+MODULE_PARM_DESC(int_pktcnt_rx, "RX packet count");
+
+static int int_timeout_rx = 64;
+module_param(int_timeout_rx, int, S_IRUGO);
+MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
 #endif
 
 #include <asm/sibyte/sb1250.h>
 #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
 #include <asm/sibyte/bcm1480_regs.h>
 #include <asm/sibyte/bcm1480_int.h>
+#define R_MAC_DMA_OODPKTLOST_RX        R_MAC_DMA_OODPKTLOST
 #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_int.h>
@@ -155,8 +164,8 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
 
 #define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES)
 
-#define SBMAC_MAX_TXDESCR      32
-#define SBMAC_MAX_RXDESCR      32
+#define SBMAC_MAX_TXDESCR      256
+#define SBMAC_MAX_RXDESCR      256
 
 #define ETHER_ALIGN    2
 #define ETHER_ADDR_LEN 6
@@ -185,10 +194,10 @@ typedef struct sbmacdma_s {
         * associated with it.
         */
 
-       struct sbmac_softc *sbdma_eth;          /* back pointer to associated MAC */
-       int              sbdma_channel; /* channel number */
+       struct sbmac_softc *sbdma_eth;      /* back pointer to associated MAC */
+       int              sbdma_channel;     /* channel number */
        int              sbdma_txdir;       /* direction (1=transmit) */
-       int              sbdma_maxdescr;        /* total # of descriptors in ring */
+       int              sbdma_maxdescr;    /* total # of descriptors in ring */
 #ifdef CONFIG_SBMAC_COALESCE
        int              sbdma_int_pktcnt;  /* # descriptors rx/tx before interrupt*/
        int              sbdma_int_timeout; /* # usec rx/tx interrupt */
@@ -197,13 +206,16 @@ typedef struct sbmacdma_s {
        volatile void __iomem *sbdma_config0;   /* DMA config register 0 */
        volatile void __iomem *sbdma_config1;   /* DMA config register 1 */
        volatile void __iomem *sbdma_dscrbase;  /* Descriptor base address */
-       volatile void __iomem *sbdma_dscrcnt;     /* Descriptor count register */
+       volatile void __iomem *sbdma_dscrcnt;   /* Descriptor count register */
        volatile void __iomem *sbdma_curdscr;   /* current descriptor address */
+       volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */
+
 
        /*
         * This stuff is for maintenance of the ring
         */
 
+       sbdmadscr_t     *sbdma_dscrtable_unaligned;
        sbdmadscr_t     *sbdma_dscrtable;       /* base of descriptor table */
        sbdmadscr_t     *sbdma_dscrtable_end; /* end of descriptor table */
 
@@ -286,8 +298,8 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m);
 static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
 static void sbdma_emptyring(sbmacdma_t *d);
 static void sbdma_fillring(sbmacdma_t *d);
-static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d);
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll);
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll);
 static int sbmac_initctx(struct sbmac_softc *s);
 static void sbmac_channel_start(struct sbmac_softc *s);
 static void sbmac_channel_stop(struct sbmac_softc *s);
@@ -308,6 +320,8 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev);
 static void sbmac_set_rx_mode(struct net_device *dev);
 static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int sbmac_close(struct net_device *dev);
+static int sbmac_poll(struct net_device *poll_dev, int *budget);
+
 static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
 static int sbmac_mii_probe(struct net_device *dev);
 
@@ -679,6 +693,10 @@ static void sbdma_initctx(sbmacdma_t *d,
                          int txrx,
                          int maxdescr)
 {
+#ifdef CONFIG_SBMAC_COALESCE
+       int int_pktcnt, int_timeout;
+#endif
+
        /*
         * Save away interesting stuff in the structure
         */
@@ -728,6 +746,11 @@ static void sbdma_initctx(sbmacdma_t *d,
                s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT);
        d->sbdma_curdscr =
                s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR);
+       if (d->sbdma_txdir)
+               d->sbdma_oodpktlost = NULL;
+       else
+               d->sbdma_oodpktlost =
+                       s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_OODPKTLOST_RX);
 
        /*
         * Allocate memory for the ring
@@ -735,6 +758,7 @@ static void sbdma_initctx(sbmacdma_t *d,
 
        d->sbdma_maxdescr = maxdescr;
 
+       d->sbdma_dscrtable_unaligned =
        d->sbdma_dscrtable = (sbdmadscr_t *)
                kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL);
 
@@ -765,12 +789,14 @@ static void sbdma_initctx(sbmacdma_t *d,
         * Setup Rx/Tx DMA coalescing defaults
         */
 
+       int_pktcnt = (txrx == DMA_TX) ? int_pktcnt_tx : int_pktcnt_rx;
        if ( int_pktcnt ) {
                d->sbdma_int_pktcnt = int_pktcnt;
        } else {
                d->sbdma_int_pktcnt = 1;
        }
 
+       int_timeout = (txrx == DMA_TX) ? int_timeout_tx : int_timeout_rx;
        if ( int_timeout ) {
                d->sbdma_int_timeout = int_timeout;
        } else {
@@ -1125,32 +1151,63 @@ static void sbdma_fillring(sbmacdma_t *d)
        }
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sbmac_netpoll(struct net_device *netdev)
+{
+       struct sbmac_softc *sc = netdev_priv(netdev);
+       int irq = sc->sbm_dev->irq;
+
+       __raw_writeq(0, sc->sbm_imr);
+
+       sbmac_intr(irq, netdev, NULL);
+
+#ifdef CONFIG_SBMAC_COALESCE
+       __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
+       ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0),
+       sc->sbm_imr);
+#else
+       __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | 
+       (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr);
+#endif
+}
+#endif
 
 /**********************************************************************
- *  SBDMA_RX_PROCESS(sc,d)
+ *  SBDMA_RX_PROCESS(sc,d,work_to_do,poll)
  *
  *  Process "completed" receive buffers on the specified DMA channel.
- *  Note that this isn't really ideal for priority channels, since
- *  it processes all of the packets on a given channel before
- *  returning.
  *
  *  Input parameters:
- *        sc - softc structure
- *        d - DMA channel context
+ *            sc - softc structure
+ *            d - DMA channel context
+ *    work_to_do - no. of packets to process before enabling interrupt
+ *                 again (for NAPI)
+ *          poll - 1: using polling (for NAPI)
  *
  *  Return value:
  *        nothing
  ********************************************************************* */
 
-static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d,
+                             int work_to_do, int poll)
 {
        int curidx;
        int hwidx;
        sbdmadscr_t *dsc;
        struct sk_buff *sb;
        int len;
+       int work_done = 0;
+       int dropped = 0;
 
-       for (;;) {
+       prefetch(d);
+
+again:
+       /* Check if the HW dropped any frames */
+       sc->sbm_stats.rx_fifo_errors
+           += __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff;
+       __raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost);
+
+       while (work_to_do-- > 0) {
                /*
                 * figure out where we are (as an index) and where
                 * the hardware is (also as an index)
@@ -1162,7 +1219,12 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
                 * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
                 */
 
-               curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+               dsc = d->sbdma_remptr;
+               curidx = dsc - d->sbdma_dscrtable;
+
+               prefetch(dsc);
+               prefetch(&d->sbdma_ctxtable[curidx]);
+
                hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
                                d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
 
@@ -1173,13 +1235,12 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
                 */
 
                if (curidx == hwidx)
-                       break;
+                       goto done;
 
                /*
                 * Otherwise, get the packet's sk_buff ptr back
                 */
 
-               dsc = &(d->sbdma_dscrtable[curidx]);
                sb = d->sbdma_ctxtable[curidx];
                d->sbdma_ctxtable[curidx] = NULL;
 
@@ -1191,7 +1252,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
                 * receive ring.
                 */
 
-               if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
+               if (likely (!(dsc->dscr_a & M_DMA_ETHRX_BAD))) {
 
                        /*
                         * Add a new buffer to replace the old one.  If we fail
@@ -1199,9 +1260,14 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
                         * packet and put it right back on the receive ring.
                         */
 
-                       if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
-                               sc->sbm_stats.rx_dropped++;
+                       if (unlikely (sbdma_add_rcvbuffer(d,NULL) ==
+                                     -ENOBUFS)) {
+                               sc->sbm_stats.rx_dropped++;
                                sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
+                               /* No point in continuing at the moment */
+                               printk(KERN_ERR "dropped packet (1)\n");
+                               d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+                               goto done;
                        } else {
                                /*
                                 * Set length into the packet
@@ -1213,8 +1279,6 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
                                 * receive ring.  Pass the buffer to
                                 * the kernel
                                 */
-                               sc->sbm_stats.rx_bytes += len;
-                               sc->sbm_stats.rx_packets++;
                                sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
                                /* Check hw IPv4/TCP checksum if supported */
                                if (sc->rx_hw_checksum == ENABLE) {
@@ -1226,8 +1290,22 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
                                                sb->ip_summed = CHECKSUM_NONE;
                                        }
                                }
-
-                               netif_rx(sb);
+                               prefetch(sb->data);
+                               prefetch((const void *)(((char *)sb->data)+32));
+                               if (poll)
+                                       dropped = netif_receive_skb(sb);
+                               else
+                                       dropped = netif_rx(sb);
+
+                               if (dropped == NET_RX_DROP) {
+                                       sc->sbm_stats.rx_dropped++;
+                                       d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+                                       goto done;
+                               }
+                               else {
+                                       sc->sbm_stats.rx_bytes += len;
+                                       sc->sbm_stats.rx_packets++;
+                               }
                        }
                } else {
                        /*
@@ -1244,12 +1322,16 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
                 */
 
                d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
-
+               work_done++;
        }
+       if (!poll) {
+               work_to_do = 32;
+               goto again; /* collect fifo drop statistics again */
+       }
+done:
+       return work_done;
 }
 
-
-
 /**********************************************************************
  *  SBDMA_TX_PROCESS(sc,d)
  *
@@ -1261,22 +1343,30 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
  *
  *  Input parameters:
  *      sc - softc structure
- *        d - DMA channel context
+ *      d - DMA channel context
+ *    poll - 1: using polling (for NAPI)
  *
  *  Return value:
  *        nothing
  ********************************************************************* */
 
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
 {
        int curidx;
        int hwidx;
        sbdmadscr_t *dsc;
        struct sk_buff *sb;
        unsigned long flags;
+       int packets_handled = 0;
 
        spin_lock_irqsave(&(sc->sbm_lock), flags);
 
+       if (d->sbdma_remptr == d->sbdma_addptr)
+         goto end_unlock;
+
+       hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+                       d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+
        for (;;) {
                /*
                 * figure out where we are (as an index) and where
@@ -1290,8 +1380,6 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
                 */
 
                curidx = d->sbdma_remptr - d->sbdma_dscrtable;
-               hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
-                               d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
 
                /*
                 * If they're the same, that means we've processed all
@@ -1329,6 +1417,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
 
                d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
 
+               packets_handled++;
+
        }
 
        /*
@@ -1337,8 +1427,10 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
         * watermark on the transmit queue.
         */
 
-       netif_wake_queue(d->sbdma_eth->sbm_dev);
+       if (packets_handled)
+               netif_wake_queue(d->sbdma_eth->sbm_dev);
 
+end_unlock:
        spin_unlock_irqrestore(&(sc->sbm_lock), flags);
 
 }
@@ -1412,9 +1504,9 @@ static int sbmac_initctx(struct sbmac_softc *s)
 
 static void sbdma_uninitctx(struct sbmacdma_s *d)
 {
-       if (d->sbdma_dscrtable) {
-               kfree(d->sbdma_dscrtable);
-               d->sbdma_dscrtable = NULL;
+       if (d->sbdma_dscrtable_unaligned) {
+               kfree(d->sbdma_dscrtable_unaligned);
+               d->sbdma_dscrtable_unaligned = d->sbdma_dscrtable = NULL;
        }
 
        if (d->sbdma_ctxtable) {
@@ -1612,15 +1704,9 @@ static void sbmac_channel_start(struct sbmac_softc *s)
 #endif
 
 #ifdef CONFIG_SBMAC_COALESCE
-       /*
-        * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0
-        */
        __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
                       ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr);
 #else
-       /*
-        * Accept any kind of interrupt on TX and RX DMA channel 0
-        */
        __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
                       (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr);
 #endif
@@ -2053,57 +2139,46 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance)
        uint64_t isr;
        int handled = 0;
 
-       for (;;) {
-
-               /*
-                * Read the ISR (this clears the bits in the real
-                * register, except for counter addr)
-                */
+       /*
+        * Read the ISR (this clears the bits in the real
+        * register, except for counter addr)
+        */
 
-               isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
+       isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
 
-               if (isr == 0)
-                       break;
+       if (isr == 0)
+               return IRQ_RETVAL(0);
+       handled = 1;
 
-               handled = 1;
-
-               /*
-                * Transmits on channel 0
-                */
+       /*
+        * Transmits on channel 0
+        */
 
-               if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
-                       sbdma_tx_process(sc,&(sc->sbm_txdma));
+       if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+               sbdma_tx_process(sc,&(sc->sbm_txdma), 0);
+#ifdef CONFIG_NETPOLL_TRAP
+               if (netpoll_trap()) {
+                       if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
+                               __netif_schedule(dev);
                }
+#endif
+       }
 
-               /*
-                * Receives on channel 0
-                */
-
-               /*
-                * It's important to test all the bits (or at least the
-                * EOP_SEEN bit) when deciding to do the RX process
-                * particularly when coalescing, to make sure we
-                * take care of the following:
-                *
-                * If you have some packets waiting (have been received
-                * but no interrupt) and get a TX interrupt before
-                * the RX timer or counter expires, reading the ISR
-                * above will clear the timer and counter, and you
-                * won't get another interrupt until a packet shows
-                * up to start the timer again.  Testing
-                * EOP_SEEN here takes care of this case.
-                * (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0)
-                */
-
-
-               if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
-                       sbdma_rx_process(sc,&(sc->sbm_rxdma));
+       if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
+               if (netif_rx_schedule_prep(dev)) {
+                       __raw_writeq(0, sc->sbm_imr);
+                       __netif_rx_schedule(dev);
+                       /* Depend on the exit from poll to reenable intr */
+               }
+               else {
+                       /* may leave some packets behind */
+                       sbdma_rx_process(sc,&(sc->sbm_rxdma),
+                                        SBMAC_MAX_RXDESCR * 2, 0);
                }
        }
        return IRQ_RETVAL(handled);
 }
 
-
 /**********************************************************************
  *  SBMAC_START_TX(skb,dev)
  *
@@ -2233,8 +2308,6 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
        }
 }
 
-
-
 #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
 /**********************************************************************
  *  SBMAC_PARSE_XDIGIT(str)
@@ -2397,8 +2470,13 @@ static int sbmac_init(struct net_device *dev, int idx)
        dev->do_ioctl           = sbmac_mii_ioctl;
        dev->tx_timeout         = sbmac_tx_timeout;
        dev->watchdog_timeo     = TX_TIMEOUT;
+       dev->poll               = sbmac_poll;
+       dev->weight             = 16;
 
        dev->change_mtu         = sb1250_change_mtu;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = sbmac_netpoll;
+#endif
 
        /* This is needed for PASS2 for Rx H/W checksum feature */
        sbmac_set_iphdr_offset(sc);
@@ -2796,7 +2874,39 @@ static int sbmac_close(struct net_device *dev)
        return 0;
 }
 
+static int sbmac_poll(struct net_device *dev, int *budget)
+{
+       int work_to_do;
+       int work_done;
+       struct sbmac_softc *sc = netdev_priv(dev);
+
+       work_to_do = min(*budget, dev->quota);
+       work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), work_to_do, 1);
 
+       if (work_done > work_to_do)
+               printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n",
+                      sc->sbm_dev->name, *budget, dev->quota, work_done);
+
+       sbdma_tx_process(sc, &(sc->sbm_txdma), 1);
+
+       *budget -= work_done;
+       dev->quota -= work_done;
+
+       if (work_done < work_to_do) {
+               netif_rx_complete(dev);
+
+#ifdef CONFIG_SBMAC_COALESCE
+               __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
+                            ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0),
+                            sc->sbm_imr);
+#else
+               __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+                            (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr);
+#endif
+       }
+
+       return (work_done >= work_to_do);
+}
 
 #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
 static void
@@ -2883,7 +2993,7 @@ sbmac_init_module(void)
 
                /*
                 * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
-                * value for us by the firmware if we're going to use this MAC.
+                * value for us by the firmware if we are going to use this MAC.
                 * If we find a zero, skip this MAC.
                 */
 
index d8c9c5d66d4fb7a94ddab84444e521cd3221e76c..1fc77300b0552d688d14148ba4def8d82148e0ca 100644 (file)
@@ -624,7 +624,7 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs)
 
 #define ALIGNED(x)  ((((unsigned long)(x)) + 0xf) & ~(0xf))
 
-static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
+static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom)
 {
        struct sgiseeq_init_block *sr;
        struct sgiseeq_private *sp;
@@ -650,7 +650,9 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
 
 #define EADDR_NVOFS     250
        for (i = 0; i < 3; i++) {
-               unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i);
+               unsigned short tmp = has_eeprom ?
+                       ip22_eeprom_read(&hpcregs->eeprom, EADDR_NVOFS / 2+i) :
+                       ip22_nvram_read(EADDR_NVOFS / 2+i);
 
                dev->dev_addr[2 * i]     = tmp >> 8;
                dev->dev_addr[2 * i + 1] = tmp & 0xff;
@@ -678,6 +680,11 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
        setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
        setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
 
+       /* Setup PIO and DMA transfer timing */
+       sp->hregs->pconfig = 0x161;
+       sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
+                            HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
+
        /* Setup PIO and DMA transfer timing */
        sp->hregs->pconfig = 0x161;
        sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
@@ -729,8 +736,23 @@ err_out:
 
 static int __init sgiseeq_probe(void)
 {
+       unsigned int tmp, ret1, ret2 = 0;
+
        /* On board adapter on 1st HPC is always present */
-       return sgiseeq_init(hpc3c0, SGI_ENET_IRQ);
+       ret1 = sgiseeq_init(hpc3c0, SGI_ENET_IRQ, 0);
+       /* Let's see if second HPC is there */
+       if (!(ip22_is_fullhouse()) &&
+           get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]) == 0) {
+               sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 |
+                                SGIMC_GIOPAR_EXP164 |
+                                SGIMC_GIOPAR_HPC264;
+               hpc3c1->pbus_piocfg[0][0] = 0x3ffff;
+               /* interrupt/config register on Challenge S Mezz board */
+               hpc3c1->pbus_extregs[0][0] = 0x30;
+               ret2 = sgiseeq_init(hpc3c1, SGI_GIO_0_IRQ, 1);
+       }
+
+       return (ret1 & ret2) ? ret1 : 0;
 }
 
 static void __exit sgiseeq_exit(void)
index e0a93005e6dce369a788fa82af9d40fd803ace33..bf218621db16003ba393c284579c2f68727349af 100644 (file)
@@ -5123,7 +5123,12 @@ static int skge_resume(struct pci_dev *pdev)
 
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
-       pci_enable_device(pdev);
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               printk(KERN_WARNING "sk98lin: unable to enable device %s "
+                               "in resume\n", dev->name);
+               goto err_out;
+       }
        pci_set_master(pdev);
        if (pAC->GIni.GIMacsFound == 2)
                ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
@@ -5131,10 +5136,8 @@ static int skge_resume(struct pci_dev *pdev)
                ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev);
        if (ret) {
                printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq);
-               pAC->AllocFlag &= ~SK_ALLOC_IRQ;
-               dev->irq = 0;
-               pci_disable_device(pdev);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto err_out_disable_pdev;
        }
 
        netif_device_attach(dev);
@@ -5151,6 +5154,13 @@ static int skge_resume(struct pci_dev *pdev)
        }
 
        return 0;
+
+err_out_disable_pdev:
+       pci_disable_device(pdev);
+err_out:
+       pAC->AllocFlag &= ~SK_ALLOC_IRQ;
+       dev->irq = 0;
+       return ret;
 }
 #else
 #define skge_suspend NULL
diff --git a/drivers/net/skfp/h/lnkstat.h b/drivers/net/skfp/h/lnkstat.h
deleted file mode 100644 (file)
index c73dcd9..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/******************************************************************************
- *
- *     (C)Copyright 1998,1999 SysKonnect,
- *     a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-/*
- * Definition of the Error Log Structure
- * This structure will be copied into the Error Log buffer
- * during the NDIS General Request ReadErrorLog by the MAC Driver
- */
-
-struct s_error_log {
-
-       /*
-        * place holder for token ring adapter error log (zeros)
-        */
-       u_char  reserved_0 ;                    /* byte 0 inside Error Log */
-       u_char  reserved_1 ;                    /* byte 1 */
-       u_char  reserved_2 ;                    /* byte 2 */    
-       u_char  reserved_3 ;                    /* byte 3 */
-       u_char  reserved_4 ;                    /* byte 4 */
-       u_char  reserved_5 ;                    /* byte 5 */
-       u_char  reserved_6 ;                    /* byte 6 */
-       u_char  reserved_7 ;                    /* byte 7 */
-       u_char  reserved_8 ;                    /* byte 8 */
-       u_char  reserved_9 ;                    /* byte 9 */
-       u_char  reserved_10 ;                   /* byte 10 */
-       u_char  reserved_11 ;                   /* byte 11 */
-       u_char  reserved_12 ;                   /* byte 12 */
-       u_char  reserved_13 ;                   /* byte 13 */
-
-       /*
-        * FDDI link statistics 
-        */
-/*
- * smt error low
- */
-#define SMT_ERL_AEB    (1<<15)                 /* A elast. buffer */
-#define SMT_ERL_BLC    (1<<14)                 /* B link error condition */
-#define SMT_ERL_ALC    (1<<13)                 /* A link error condition */
-#define SMT_ERL_NCC    (1<<12)                 /* not copied condition */
-#define SMT_ERL_FEC    (1<<11)                 /* frame error condition */
-
-/*
- * smt event low
- */
-#define SMT_EVL_NCE    (1<<5)
-
-       u_short smt_error_low ;                 /* byte 14/15 */
-       u_short smt_error_high ;                /* byte 16/17 */
-       u_short smt_event_low ;                 /* byte 18/19 */
-       u_short smt_event_high ;                /* byte 20/21 */
-       u_short connection_policy_violation ;   /* byte 22/23 */
-       u_short port_event ;                    /* byte 24/25 */
-       u_short set_count_low ;                 /* byte 26/27 */
-       u_short set_count_high ;                /* byte 28/29 */
-       u_short aci_id_code ;                   /* byte 30/31 */
-       u_short purge_frame_counter ;           /* byte 32/33 */
-
-       /*
-        * CMT and RMT state machines
-        */
-       u_short ecm_state ;                     /* byte 34/35 */
-       u_short pcm_a_state ;                   /* byte 36/37 */
-       u_short pcm_b_state ;                   /* byte 38/39 */
-       u_short cfm_state ;                     /* byte 40/41 */
-       u_short rmt_state ;                     /* byte 42/43 */
-
-       u_short not_used[30] ;                  /* byte 44-103 */
-
-       u_short ucode_version_level ;           /* byte 104/105 */
-
-       u_short not_used_1 ;                    /* byte 106/107 */
-       u_short not_used_2 ;                    /* byte 108/109 */
-} ;
index f1a0e6c0fbdd81ac4bb8e8da0e2135bd2073f126..21afe108d3cb3908efd888650104a09a0b3b4d46 100644 (file)
@@ -42,7 +42,7 @@
 #include "skge.h"
 
 #define DRV_NAME               "skge"
-#define DRV_VERSION            "1.10"
+#define DRV_VERSION            "1.11"
 #define PFX                    DRV_NAME " "
 
 #define DEFAULT_TX_RING_SIZE   128
@@ -2621,6 +2621,7 @@ static int skge_down(struct net_device *dev)
 
 static inline int skge_avail(const struct skge_ring *ring)
 {
+       smp_mb();
        return ((ring->to_clean > ring->to_use) ? 0 : ring->count)
                + (ring->to_clean - ring->to_use) - 1;
 }
@@ -2709,6 +2710,8 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
                       dev->name, e - skge->tx_ring.start, skb->len);
 
        skge->tx_ring.to_use = e->next;
+       smp_wmb();
+
        if (skge_avail(&skge->tx_ring) <= TX_LOW_WATER) {
                pr_debug("%s: transmit queue full\n", dev->name);
                netif_stop_queue(dev);
@@ -2726,8 +2729,6 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e,
 {
        struct pci_dev *pdev = skge->hw->pdev;
 
-       BUG_ON(!e->skb);
-
        /* skb header vs. fragment */
        if (control & BMU_STF)
                pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr),
@@ -2745,7 +2746,6 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e,
 
                dev_kfree_skb(e->skb);
        }
-       e->skb = NULL;
 }
 
 /* Free all buffers in transmit ring */
@@ -3017,21 +3017,29 @@ static void skge_tx_done(struct net_device *dev)
 
        skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
 
-       netif_tx_lock(dev);
        for (e = ring->to_clean; e != ring->to_use; e = e->next) {
-               struct skge_tx_desc *td = e->desc;
+               u32 control = ((const struct skge_tx_desc *) e->desc)->control;
 
-               if (td->control & BMU_OWN)
+               if (control & BMU_OWN)
                        break;
 
-               skge_tx_free(skge, e, td->control);
+               skge_tx_free(skge, e, control);
        }
        skge->tx_ring.to_clean = e;
 
-       if (skge_avail(&skge->tx_ring) > TX_LOW_WATER)
-               netif_wake_queue(dev);
+       /* Can run lockless until we need to synchronize to restart queue. */
+       smp_mb();
+
+       if (unlikely(netif_queue_stopped(dev) &&
+                    skge_avail(&skge->tx_ring) > TX_LOW_WATER)) {
+               netif_tx_lock(dev);
+               if (unlikely(netif_queue_stopped(dev) &&
+                            skge_avail(&skge->tx_ring) > TX_LOW_WATER)) {
+                       netif_wake_queue(dev);
 
-       netif_tx_unlock(dev);
+               }
+               netif_tx_unlock(dev);
+       }
 }
 
 static int skge_poll(struct net_device *dev, int *budget)
index 86467ae74d455582a18b7e13f96e7fdd000c7087..edd71468220ca0e5a19377db04ed312f773181fd 100644 (file)
@@ -232,7 +232,6 @@ enum {
        IS_R2_PAR_ERR   = 1<<0, /* Queue R2 Parity Error */
 
        IS_ERR_MSK      = IS_IRQ_MST_ERR | IS_IRQ_STAT
-                       | IS_NO_STAT_M1 | IS_NO_STAT_M2
                        | IS_RAM_RD_PAR | IS_RAM_WR_PAR
                        | IS_M1_PAR_ERR | IS_M2_PAR_ERR
                        | IS_R1_PAR_ERR | IS_R2_PAR_ERR,
@@ -2447,15 +2446,15 @@ enum pause_status {
 
 
 struct skge_port {
-       u32                  msg_enable;
        struct skge_hw       *hw;
        struct net_device    *netdev;
        int                  port;
+       u32                  msg_enable;
 
        struct skge_ring     tx_ring;
-       struct skge_ring     rx_ring;
 
-       struct net_device_stats net_stats;
+       struct skge_ring     rx_ring ____cacheline_aligned_in_smp;
+       unsigned int         rx_buf_size;
 
        struct timer_list    link_timer;
        enum pause_control   flow_control;
@@ -2471,7 +2470,8 @@ struct skge_port {
        void                 *mem;      /* PCI memory for rings */
        dma_addr_t           dma;
        unsigned long        mem_size;
-       unsigned int         rx_buf_size;
+
+       struct net_device_stats net_stats;
 };
 
 
index 8a2109a913b67bbdee20f17f5151cbac1c56d524..81f24847c9632e538645a23f345e0dbbc542f061 100644 (file)
@@ -499,7 +499,7 @@ static inline void   smc911x_rcv(struct net_device *dev)
                SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_));
                SMC_PULL_DATA(data, pkt_len+2+3);
 
-               DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name,);
+               DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name);
                PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64);
                dev->last_rx = jiffies;
                skb->protocol = eth_type_trans(skb, dev);
index d7741e23f8de205d225f8abb058f214eef437b41..f1e2dfc795a2bdce9036259f76c207e5d6c06af0 100644 (file)
@@ -1,35 +1,34 @@
-/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *                ahennessy@mvista.com
+/*
+ * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
  *
  * Based on skelton.c by Donald Becker.
- * Copyright (C) 2000-2001 Toshiba Corporation
  *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * This driver is a replacement of older and less maintained version.
+ * This is a header of the older version:
+ *     -----<snip>-----
+ *     Copyright 2001 MontaVista Software Inc.
+ *     Author: MontaVista Software, Inc.
+ *             ahennessy@mvista.com
+ *     Copyright (C) 2000-2001 Toshiba Corporation
+ *     static const char *version =
+ *             "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+ *     -----<snip>-----
  *
- * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2005
+ * All Rights Reserved.
  */
 
-static const char *version =
-       "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+#ifdef TC35815_NAPI
+#define DRV_VERSION    "1.35-NAPI"
+#else
+#define DRV_VERSION    "1.35"
+#endif
+static const char *version = "tc35815.c:v" DRV_VERSION "\n";
+#define MODNAME                        "tc35815"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -40,6 +39,7 @@ static const char *version =
 #include <linux/in.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
@@ -47,36 +47,47 @@ static const char *version =
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
-#include <asm/dma.h>
 #include <asm/byteorder.h>
 
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-static const char* cardname = "TC35815CF";
-#define TC35815_PROC_ENTRY "net/tc35815"
-
-#define TC35815_MODULE_NAME "TC35815CF"
-#define TX_TIMEOUT (4*HZ)
-
 /* First, a few definitions that the brave might change. */
 
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef TC35815_DEBUG
-#define TC35815_DEBUG 1
-#endif
-static unsigned int tc35815_debug = TC35815_DEBUG;
-
 #define GATHER_TXINT   /* On-Demand Tx Interrupt */
+#define WORKAROUND_LOSTCAR
+#define WORKAROUND_100HALF_PROMISC
+/* #define TC35815_USE_PACKEDBUFFER */
+
+typedef enum {
+       TC35815CF = 0,
+       TC35815_NWU,
+       TC35815_TX4939,
+} board_t;
+
+/* indexed by board_t, above */
+static const struct {
+       const char *name;
+} board_info[] __devinitdata = {
+       { "TOSHIBA TC35815CF 10/100BaseTX" },
+       { "TOSHIBA TC35815 with Wake on LAN" },
+       { "TOSHIBA TC35815/TX4939" },
+};
+
+static const struct pci_device_id tc35815_pci_tbl[] = {
+       {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
+       {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
+       {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
+       {0,}
+};
+MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
 
-#define vtonocache(p)  KSEG1ADDR(virt_to_phys(p))
+/* see MODULE_PARM_DESC */
+static struct tc35815_options {
+       int speed;
+       int duplex;
+       int doforce;
+} options;
 
 /*
  * Registers
@@ -119,6 +130,11 @@ struct tc35815_regs {
  * Bit assignments
  */
 /* DMA_Ctl bit asign ------------------------------------------------------- */
+#define DMA_RxAlign            0x00c00000 /* 1:Reception Alignment           */
+#define DMA_RxAlign_1          0x00400000
+#define DMA_RxAlign_2          0x00800000
+#define DMA_RxAlign_3          0x00c00000
+#define DMA_M66EnStat          0x00080000 /* 1:66MHz Enable State            */
 #define DMA_IntMask            0x00040000 /* 1:Interupt mask                 */
 #define DMA_SWIntReq           0x00020000 /* 1:Software Interrupt request    */
 #define DMA_TxWakeUp           0x00010000 /* 1:Transmit Wake Up              */
@@ -269,42 +285,6 @@ struct tc35815_regs {
 #define MD_CA_Wr               0x00000400 /* 1:Write 0:Read                  */
 
 
-/* MII register offsets */
-#define MII_CONTROL             0x0000
-#define MII_STATUS              0x0001
-#define MII_PHY_ID0             0x0002
-#define MII_PHY_ID1             0x0003
-#define MII_ANAR                0x0004
-#define MII_ANLPAR              0x0005
-#define MII_ANER                0x0006
-/* MII Control register bit definitions. */
-#define MIICNTL_FDX             0x0100
-#define MIICNTL_RST_AUTO        0x0200
-#define MIICNTL_ISOLATE         0x0400
-#define MIICNTL_PWRDWN          0x0800
-#define MIICNTL_AUTO            0x1000
-#define MIICNTL_SPEED           0x2000
-#define MIICNTL_LPBK            0x4000
-#define MIICNTL_RESET           0x8000
-/* MII Status register bit significance. */
-#define MIISTAT_EXT             0x0001
-#define MIISTAT_JAB             0x0002
-#define MIISTAT_LINK            0x0004
-#define MIISTAT_CAN_AUTO        0x0008
-#define MIISTAT_FAULT           0x0010
-#define MIISTAT_AUTO_DONE       0x0020
-#define MIISTAT_CAN_T           0x0800
-#define MIISTAT_CAN_T_FDX       0x1000
-#define MIISTAT_CAN_TX          0x2000
-#define MIISTAT_CAN_TX_FDX      0x4000
-#define MIISTAT_CAN_T4          0x8000
-/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */
-#define MII_AN_TX_FDX           0x0100
-#define MII_AN_TX_HDX           0x0080
-#define MII_AN_10_FDX           0x0040
-#define MII_AN_10_HDX           0x0020
-
-
 /*
  * Descriptors
  */
@@ -352,32 +332,51 @@ struct BDesc {
 
 #ifdef NO_CHECK_CARRIER
 #define TX_CTL_CMD     (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
-       Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
-       Tx_En)  /* maybe  0x7d01 */
+       Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
+       Tx_En)  /* maybe  0x7b01 */
 #else
 #define TX_CTL_CMD     (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
-       Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
-       Tx_En)  /* maybe  0x7f01 */
+       Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
+       Tx_En)  /* maybe  0x7b01 */
 #endif
 #define RX_CTL_CMD     (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
        | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn)   /* maybe 0x6f01 */
-
 #define INT_EN_CMD  (Int_NRAbtEn | \
-        Int_DParDEn | Int_DParErrEn | \
+       Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
        Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
        Int_STargAbtEn | \
        Int_BLExEn  | Int_FDAExEn) /* maybe 0xb7f*/
+#define DMA_CTL_CMD    DMA_BURST_SIZE
+#define HAVE_DMA_RXALIGN(lp)   likely((lp)->boardtype != TC35815CF)
 
 /* Tuning parameters */
 #define DMA_BURST_SIZE 32
 #define TX_THRESHOLD   1024
+#define TX_THRESHOLD_MAX 1536       /* used threshold with packet max byte for low pci transfer ability.*/
+#define TX_THRESHOLD_KEEP_LIMIT 10  /* setting threshold max value when overrun error occured this count. */
 
+/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */
+#ifdef TC35815_USE_PACKEDBUFFER
 #define FD_PAGE_NUM 2
-#define FD_PAGE_ORDER 1
-/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */
-#define RX_BUF_PAGES   8       /* >= 2 */
+#define RX_BUF_NUM     8       /* >= 2 */
 #define RX_FD_NUM      250     /* >= 32 */
 #define TX_FD_NUM      128
+#define RX_BUF_SIZE    PAGE_SIZE
+#else /* TC35815_USE_PACKEDBUFFER */
+#define FD_PAGE_NUM 4
+#define RX_BUF_NUM     128     /* < 256 */
+#define RX_FD_NUM      256     /* >= 32 */
+#define TX_FD_NUM      128
+#if RX_CTL_CMD & Rx_LongEn
+#define RX_BUF_SIZE    PAGE_SIZE
+#elif RX_CTL_CMD & Rx_StripCRC
+#define RX_BUF_SIZE    ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */
+#else
+#define RX_BUF_SIZE    ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */
+#endif
+#endif /* TC35815_USE_PACKEDBUFFER */
+#define RX_FD_RESERVE  (2 / 2) /* max 2 BD per RxFD */
+#define NAPI_WEIGHT    16
 
 struct TxFD {
        struct FDesc fd;
@@ -392,18 +391,27 @@ struct RxFD {
 
 struct FrFD {
        struct FDesc fd;
-       struct BDesc bd[RX_BUF_PAGES];
+       struct BDesc bd[RX_BUF_NUM];
 };
 
 
-extern unsigned long tc_readl(volatile __u32 *addr);
-extern void tc_writel(unsigned long data, volatile __u32 *addr);
+#define tc_readl(addr) readl(addr)
+#define tc_writel(d, addr)     writel(d, addr)
+
+#define TC35815_TX_TIMEOUT  msecs_to_jiffies(400)
 
-dma_addr_t priv_dma_handle;
+/* Timer state engine. */
+enum tc35815_timer_state {
+       arbwait  = 0,   /* Waiting for auto negotiation to complete.          */
+       lupwait  = 1,   /* Auto-neg complete, awaiting link-up status.        */
+       ltrywait = 2,   /* Forcing try of all modes, from fastest to slowest. */
+       asleep   = 3,   /* Time inactive.                                     */
+       lcheck   = 4,   /* Check link status.                                 */
+};
 
 /* Information that need to be kept for each board. */
 struct tc35815_local {
-       struct net_device *next_module;
+       struct pci_dev *pci_dev;
 
        /* statistics */
        struct net_device_stats stats;
@@ -411,216 +419,372 @@ struct tc35815_local {
                int max_tx_qlen;
                int tx_ints;
                int rx_ints;
+               int tx_underrun;
        } lstats;
 
-       int tbusy;
-       int option;
-#define TC35815_OPT_AUTO       0x00
-#define TC35815_OPT_10M        0x01
-#define TC35815_OPT_100M       0x02
-#define TC35815_OPT_FULLDUP    0x04
-       int linkspeed;  /* 10 or 100 */
+       /* Tx control lock.  This protects the transmit buffer ring
+        * state along with the "tx full" state of the driver.  This
+        * means all netif_queue flow control actions are protected
+        * by this lock as well.
+        */
+       spinlock_t lock;
+
+       int phy_addr;
        int fullduplex;
+       unsigned short saved_lpa;
+       struct timer_list timer;
+       enum tc35815_timer_state timer_state; /* State of auto-neg timer. */
+       unsigned int timer_ticks;       /* Number of clicks at each state  */
 
        /*
         * Transmitting: Batch Mode.
         *      1 BD in 1 TxFD.
-        * Receiving: Packing Mode.
+        * Receiving: Packing Mode. (TC35815_USE_PACKEDBUFFER)
         *      1 circular FD for Free Buffer List.
-        *      RX_BUG_PAGES BD in Free Buffer FD.
+        *      RX_BUF_NUM BD in Free Buffer FD.
         *      One Free Buffer BD has PAGE_SIZE data buffer.
+        * Or Non-Packing Mode.
+        *      1 circular FD for Free Buffer List.
+        *      RX_BUF_NUM BD in Free Buffer FD.
+        *      One Free Buffer BD has ETH_FRAME_LEN data buffer.
         */
-        struct pci_dev *pdev;
-       dma_addr_t fd_buf_dma_handle;
-       void * fd_buf;  /* for TxFD, TxFD, FrFD */
+       void * fd_buf;  /* for TxFD, RxFD, FrFD */
+       dma_addr_t fd_buf_dma;
        struct TxFD *tfd_base;
-       int tfd_start;
-       int tfd_end;
+       unsigned int tfd_start;
+       unsigned int tfd_end;
        struct RxFD *rfd_base;
        struct RxFD *rfd_limit;
        struct RxFD *rfd_cur;
        struct FrFD *fbl_ptr;
+#ifdef TC35815_USE_PACKEDBUFFER
        unsigned char fbl_curid;
-       dma_addr_t data_buf_dma_handle[RX_BUF_PAGES];
-       void * data_buf[RX_BUF_PAGES];          /* packing */
-       spinlock_t lock;
+       void * data_buf[RX_BUF_NUM];            /* packing */
+       dma_addr_t data_buf_dma[RX_BUF_NUM];
+       struct {
+               struct sk_buff *skb;
+               dma_addr_t skb_dma;
+       } tx_skbs[TX_FD_NUM];
+#else
+       unsigned int fbl_count;
+       struct {
+               struct sk_buff *skb;
+               dma_addr_t skb_dma;
+       } tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM];
+#endif
+       struct mii_if_info mii;
+       unsigned short mii_id[2];
+       u32 msg_enable;
+       board_t boardtype;
 };
 
-/* Index to functions, as function prototypes. */
+static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt)
+{
+       return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);
+}
+#ifdef DEBUG
+static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+       return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));
+}
+#endif
+#ifdef TC35815_USE_PACKEDBUFFER
+static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+       int i;
+       for (i = 0; i < RX_BUF_NUM; i++) {
+               if (bus >= lp->data_buf_dma[i] &&
+                   bus < lp->data_buf_dma[i] + PAGE_SIZE)
+                       return (void *)((u8 *)lp->data_buf[i] +
+                                       (bus - lp->data_buf_dma[i]));
+       }
+       return NULL;
+}
+
+#define TC35815_DMA_SYNC_ONDEMAND
+static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+       void *buf;
+       /* pci_map + pci_dma_sync will be more effective than
+        * pci_alloc_consistent on some archs. */
+       if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL)
+               return NULL;
+       *dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE,
+                                    PCI_DMA_FROMDEVICE);
+       if (pci_dma_mapping_error(*dma_handle)) {
+               free_page((unsigned long)buf);
+               return NULL;
+       }
+       return buf;
+#else
+       return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle);
+#endif
+}
+
+static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+       pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+       free_page((unsigned long)buf);
+#else
+       pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle);
+#endif
+}
+#else /* TC35815_USE_PACKEDBUFFER */
+static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
+                                      struct pci_dev *hwdev,
+                                      dma_addr_t *dma_handle)
+{
+       struct sk_buff *skb;
+       skb = dev_alloc_skb(RX_BUF_SIZE);
+       if (!skb)
+               return NULL;
+       skb->dev = dev;
+       *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE,
+                                    PCI_DMA_FROMDEVICE);
+       if (pci_dma_mapping_error(*dma_handle)) {
+               dev_kfree_skb_any(skb);
+               return NULL;
+       }
+       skb_reserve(skb, 2);    /* make IP header 4byte aligned */
+       return skb;
+}
+
+static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle)
+{
+       pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE,
+                        PCI_DMA_FROMDEVICE);
+       dev_kfree_skb_any(skb);
+}
+#endif /* TC35815_USE_PACKEDBUFFER */
 
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq);
+/* Index to functions, as function prototypes. */
 
 static int     tc35815_open(struct net_device *dev);
 static int     tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void     tc35815_tx_timeout(struct net_device *dev);
-static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
+static irqreturn_t     tc35815_interrupt(int irq, void *dev_id);
+#ifdef TC35815_NAPI
+static int     tc35815_rx(struct net_device *dev, int limit);
+static int     tc35815_poll(struct net_device *dev, int *budget);
+#else
 static void    tc35815_rx(struct net_device *dev);
+#endif
 static void    tc35815_txdone(struct net_device *dev);
 static int     tc35815_close(struct net_device *dev);
 static struct  net_device_stats *tc35815_get_stats(struct net_device *dev);
 static void    tc35815_set_multicast_list(struct net_device *dev);
+static void     tc35815_tx_timeout(struct net_device *dev);
+static int     tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void    tc35815_poll_controller(struct net_device *dev);
+#endif
+static const struct ethtool_ops tc35815_ethtool_ops;
 
+/* Example routines you must write ;->. */
 static void    tc35815_chip_reset(struct net_device *dev);
 static void    tc35815_chip_init(struct net_device *dev);
+static void    tc35815_find_phy(struct net_device *dev);
 static void    tc35815_phy_chip_init(struct net_device *dev);
 
-/* A list of all installed tc35815 devices. */
-static struct net_device *root_tc35815_dev = NULL;
+#ifdef DEBUG
+static void    panic_queues(struct net_device *dev);
+#endif
 
-/*
- * PCI device identifiers for "new style" Linux PCI Device Drivers
- */
-static struct pci_device_id tc35815_pci_tbl[] = {
-    { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-    { 0, }
-};
+static void tc35815_timer(unsigned long data);
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+                                          struct ethtool_cmd *ep);
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location);
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+                         int val);
 
-MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
+static void __devinit tc35815_init_dev_addr (struct net_device *dev)
+{
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       int i;
+
+       /* dev_addr will be overwritten on NETDEV_REGISTER event */
+       while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+               ;
+       for (i = 0; i < 6; i += 2) {
+               unsigned short data;
+               tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
+               while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+                       ;
+               data = tc_readl(&tr->PROM_Data);
+               dev->dev_addr[i] = data & 0xff;
+               dev->dev_addr[i+1] = data >> 8;
+       }
+}
 
-int
-tc35815_probe(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+static int __devinit tc35815_init_one (struct pci_dev *pdev,
+                                      const struct pci_device_id *ent)
 {
-       int err = 0;
-       int ret;
-       unsigned long pci_memaddr;
-       unsigned int pci_irq_line;
+       void __iomem *ioaddr = NULL;
+       struct net_device *dev;
+       struct tc35815_local *lp;
+       int rc;
+       unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+
+       static int printed_version;
+       if (!printed_version++) {
+               printk(version);
+               dev_printk(KERN_DEBUG, &pdev->dev,
+                          "speed:%d duplex:%d doforce:%d\n",
+                          options.speed, options.duplex, options.doforce);
+       }
+
+       if (!pdev->irq) {
+               dev_warn(&pdev->dev, "no IRQ assigned.\n");
+               return -ENODEV;
+       }
 
-       printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device);
+       /* dev zeroed in alloc_etherdev */
+       dev = alloc_etherdev (sizeof (*lp));
+       if (dev == NULL) {
+               dev_err(&pdev->dev, "unable to alloc new ethernet\n");
+               return -ENOMEM;
+       }
+       SET_MODULE_OWNER(dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
+       lp = dev->priv;
 
-       err = pci_enable_device(pdev);
-       if (err)
-               return err;
+       /* enable device (incl. PCI PM wakeup), and bus-mastering */
+       rc = pci_enable_device (pdev);
+       if (rc)
+               goto err_out;
 
-        pci_memaddr = pci_resource_start (pdev, 1);
+       mmio_start = pci_resource_start (pdev, 1);
+       mmio_end = pci_resource_end (pdev, 1);
+       mmio_flags = pci_resource_flags (pdev, 1);
+       mmio_len = pci_resource_len (pdev, 1);
 
-        printk(KERN_INFO "    pci_memaddr=%#08lx  resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0));
+       /* set this immediately, we need to know before
+        * we talk to the chip directly */
 
-       if (!pci_memaddr) {
-               printk(KERN_WARNING "no PCI MEM resources, aborting\n");
-               ret = -ENODEV;
+       /* make sure PCI base addr 1 is MMIO */
+       if (!(mmio_flags & IORESOURCE_MEM)) {
+               dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
+               rc = -ENODEV;
                goto err_out;
        }
-       pci_irq_line = pdev->irq;
-       /* irq disabled. */
-       if (pci_irq_line == 0) {
-               printk(KERN_WARNING "no PCI irq, aborting\n");
-               ret = -ENODEV;
+
+       /* check for weird/broken PCI region reporting */
+       if ((mmio_len < sizeof(struct tc35815_regs))) {
+               dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
+               rc = -ENODEV;
                goto err_out;
        }
 
-       ret =  tc35815_probe1(pdev, pci_memaddr, pci_irq_line);
-       if (ret)
+       rc = pci_request_regions (pdev, MODNAME);
+       if (rc)
                goto err_out;
 
-       pci_set_master(pdev);
-
-       return 0;
+       pci_set_master (pdev);
 
-err_out:
-       pci_disable_device(pdev);
-       return ret;
-}
+       /* ioremap MMIO region */
+       ioaddr = ioremap (mmio_start, mmio_len);
+       if (ioaddr == NULL) {
+               dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
+               rc = -EIO;
+               goto err_out_free_res;
+       }
 
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq)
-{
-       static unsigned version_printed = 0;
-       int i, ret;
-       struct tc35815_local *lp;
-       struct tc35815_regs *tr;
-       struct net_device *dev;
+       /* Initialize the device structure. */
+       dev->open = tc35815_open;
+       dev->hard_start_xmit = tc35815_send_packet;
+       dev->stop = tc35815_close;
+       dev->get_stats = tc35815_get_stats;
+       dev->set_multicast_list = tc35815_set_multicast_list;
+       dev->do_ioctl = tc35815_ioctl;
+       dev->ethtool_ops = &tc35815_ethtool_ops;
+       dev->tx_timeout = tc35815_tx_timeout;
+       dev->watchdog_timeo = TC35815_TX_TIMEOUT;
+#ifdef TC35815_NAPI
+       dev->poll = tc35815_poll;
+       dev->weight = NAPI_WEIGHT;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = tc35815_poll_controller;
+#endif
 
-       /* Allocate a new 'dev' if needed. */
-       dev = alloc_etherdev(sizeof(struct tc35815_local));
-       if (dev == NULL)
-               return -ENOMEM;
+       dev->irq = pdev->irq;
+       dev->base_addr = (unsigned long) ioaddr;
 
-       /*
-        * alloc_etherdev allocs and zeros dev->priv
-        */
+       /* dev->priv/lp zeroed and aligned in alloc_etherdev */
        lp = dev->priv;
+       spin_lock_init(&lp->lock);
+       lp->pci_dev = pdev;
+       lp->boardtype = ent->driver_data;
 
-       if (tc35815_debug  &&  version_printed++ == 0)
-               printk(KERN_DEBUG "%s", version);
-
-       /* Fill in the 'dev' fields. */
-       dev->irq = irq;
-       dev->base_addr = (unsigned long)ioremap(base_addr,
-                                               sizeof(struct tc35815_regs));
-       if (!dev->base_addr) {
-               ret = -ENOMEM;
-               goto err_out;
-       }
-       tr = (struct tc35815_regs*)dev->base_addr;
+       lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
+       pci_set_drvdata(pdev, dev);
 
+       /* Soft reset the chip. */
        tc35815_chip_reset(dev);
 
-       /* Retrieve and print the ethernet address. */
-       while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-               ;
-       for (i = 0; i < 6; i += 2) {
-               unsigned short data;
-               tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
-               while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-                       ;
-               data = tc_readl(&tr->PROM_Data);
-               dev->dev_addr[i] = data & 0xff;
-               dev->dev_addr[i+1] = data >> 8;
-       }
+       /* Retrieve the ethernet address. */
+       tc35815_init_dev_addr(dev);
+
+       rc = register_netdev (dev);
+       if (rc)
+               goto err_out_unmap;
+
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+       printk(KERN_INFO "%s: %s at 0x%lx, "
+               "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+               "IRQ %d\n",
+               dev->name,
+               board_info[ent->driver_data].name,
+               dev->base_addr,
+               dev->dev_addr[0], dev->dev_addr[1],
+               dev->dev_addr[2], dev->dev_addr[3],
+               dev->dev_addr[4], dev->dev_addr[5],
+               dev->irq);
+
+       setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev);
+       lp->mii.dev = dev;
+       lp->mii.mdio_read = tc_mdio_read;
+       lp->mii.mdio_write = tc_mdio_write;
+       lp->mii.phy_id_mask = 0x1f;
+       lp->mii.reg_num_mask = 0x1f;
+       tc35815_find_phy(dev);
+       lp->mii.phy_id = lp->phy_addr;
+       lp->mii.full_duplex = 0;
+       lp->mii.force_media = 0;
 
-       /* Initialize the device structure. */
-       lp->pdev = pdev;
-       lp->next_module = root_tc35815_dev;
-       root_tc35815_dev = dev;
+       return 0;
 
-       spin_lock_init(&lp->lock);
+err_out_unmap:
+       iounmap(ioaddr);
+err_out_free_res:
+       pci_release_regions (pdev);
+err_out:
+       free_netdev (dev);
+       return rc;
+}
 
-       if (dev->mem_start > 0) {
-               lp->option = dev->mem_start;
-               if ((lp->option & TC35815_OPT_10M) &&
-                   (lp->option & TC35815_OPT_100M)) {
-                       /* if both speed speficied, auto select. */
-                       lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M);
-               }
-       }
-       //XXX fixme
-        lp->option |= TC35815_OPT_10M;
 
-       /* do auto negotiation */
-       tc35815_phy_chip_init(dev);
+static void __devexit tc35815_remove_one (struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata (pdev);
+       unsigned long mmio_addr;
 
-       dev->open               = tc35815_open;
-       dev->stop               = tc35815_close;
-       dev->tx_timeout         = tc35815_tx_timeout;
-       dev->watchdog_timeo     = TX_TIMEOUT;
-       dev->hard_start_xmit    = tc35815_send_packet;
-       dev->get_stats          = tc35815_get_stats;
-       dev->set_multicast_list = tc35815_set_multicast_list;
-       SET_MODULE_OWNER(dev);
-       SET_NETDEV_DEV(dev, &pdev->dev);
+       mmio_addr = dev->base_addr;
 
-       ret = register_netdev(dev);
-       if (ret)
-               goto err_out_iounmap;
+       unregister_netdev (dev);
 
-       printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC",
-              dev->name, cardname, base_addr, irq);
-       for (i = 0; i < 6; i++)
-               printk(" %2.2x", dev->dev_addr[i]);
-       printk("\n");
-       printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n",
-              dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half");
+       if (mmio_addr) {
+               iounmap ((void __iomem *)mmio_addr);
+               pci_release_regions (pdev);
+       }
 
-       return 0;
+       free_netdev (dev);
 
-err_out_iounmap:
-       iounmap((void *) dev->base_addr);
-err_out:
-       free_netdev(dev);
-       return ret;
+       pci_set_drvdata (pdev, NULL);
 }
 
-
 static int
 tc35815_init_queues(struct net_device *dev)
 {
@@ -629,44 +793,64 @@ tc35815_init_queues(struct net_device *dev)
        unsigned long fd_addr;
 
        if (!lp->fd_buf) {
-               if (sizeof(struct FDesc) +
-                   sizeof(struct BDesc) * RX_BUF_PAGES +
-                   sizeof(struct FDesc) * RX_FD_NUM +
-                   sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) {
-                       printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name);
-                       return -ENOMEM;
-               }
+               BUG_ON(sizeof(struct FDesc) +
+                      sizeof(struct BDesc) * RX_BUF_NUM +
+                      sizeof(struct FDesc) * RX_FD_NUM +
+                      sizeof(struct TxFD) * TX_FD_NUM >
+                      PAGE_SIZE * FD_PAGE_NUM);
 
-               if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0)
+               if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0)
                        return -ENOMEM;
-               for (i = 0; i < RX_BUF_PAGES; i++) {
-                       if ((lp->data_buf[i] = (void *)get_zeroed_page(GFP_KERNEL)) == 0) {
+               for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+                       if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) {
+                               while (--i >= 0) {
+                                       free_rxbuf_page(lp->pci_dev,
+                                                       lp->data_buf[i],
+                                                       lp->data_buf_dma[i]);
+                                       lp->data_buf[i] = NULL;
+                               }
+                               pci_free_consistent(lp->pci_dev,
+                                                   PAGE_SIZE * FD_PAGE_NUM,
+                                                   lp->fd_buf,
+                                                   lp->fd_buf_dma);
+                               lp->fd_buf = NULL;
+                               return -ENOMEM;
+                       }
+#else
+                       lp->rx_skbs[i].skb =
+                               alloc_rxbuf_skb(dev, lp->pci_dev,
+                                               &lp->rx_skbs[i].skb_dma);
+                       if (!lp->rx_skbs[i].skb) {
                                while (--i >= 0) {
-                                       free_page((unsigned long)lp->data_buf[i]);
-                                       lp->data_buf[i] = 0;
+                                       free_rxbuf_skb(lp->pci_dev,
+                                                      lp->rx_skbs[i].skb,
+                                                      lp->rx_skbs[i].skb_dma);
+                                       lp->rx_skbs[i].skb = NULL;
                                }
-                               free_page((unsigned long)lp->fd_buf);
-                               lp->fd_buf = 0;
+                               pci_free_consistent(lp->pci_dev,
+                                                   PAGE_SIZE * FD_PAGE_NUM,
+                                                   lp->fd_buf,
+                                                   lp->fd_buf_dma);
+                               lp->fd_buf = NULL;
                                return -ENOMEM;
                        }
-#ifdef __mips__
-                       dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM);
 #endif
                }
-#ifdef __mips__
-               dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+               printk(KERN_DEBUG "%s: FD buf %p DataBuf",
+                      dev->name, lp->fd_buf);
+#ifdef TC35815_USE_PACKEDBUFFER
+               printk(" DataBuf");
+               for (i = 0; i < RX_BUF_NUM; i++)
+                       printk(" %p", lp->data_buf[i]);
 #endif
+               printk("\n");
        } else {
-               memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM);
-#ifdef __mips__
-               dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
-#endif
+               for (i = 0; i < FD_PAGE_NUM; i++) {
+                       clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE));
+               }
        }
-#ifdef __mips__
-       fd_addr = (unsigned long)vtonocache(lp->fd_buf);
-#else
        fd_addr = (unsigned long)lp->fd_buf;
-#endif
 
        /* Free Descriptors (for Receive) */
        lp->rfd_base = (struct RxFD *)fd_addr;
@@ -675,34 +859,66 @@ tc35815_init_queues(struct net_device *dev)
                lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
        }
        lp->rfd_cur = lp->rfd_base;
-       lp->rfd_limit = (struct RxFD *)(fd_addr -
-                                       sizeof(struct FDesc) -
-                                       sizeof(struct BDesc) * 30);
+       lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1);
 
        /* Transmit Descriptors */
        lp->tfd_base = (struct TxFD *)fd_addr;
        fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
        for (i = 0; i < TX_FD_NUM; i++) {
-               lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1]));
-               lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+               lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1]));
+               lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
                lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
        }
-       lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0]));
+       lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0]));
        lp->tfd_start = 0;
        lp->tfd_end = 0;
 
        /* Buffer List (for Receive) */
        lp->fbl_ptr = (struct FrFD *)fd_addr;
-       lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr));
-       lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD);
-       for (i = 0; i < RX_BUF_PAGES; i++) {
-               lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i]));
+       lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr));
+       lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD);
+#ifndef TC35815_USE_PACKEDBUFFER
+       /*
+        * move all allocated skbs to head of rx_skbs[] array.
+        * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in
+        * tc35815_rx() had failed.
+        */
+       lp->fbl_count = 0;
+       for (i = 0; i < RX_BUF_NUM; i++) {
+               if (lp->rx_skbs[i].skb) {
+                       if (i != lp->fbl_count) {
+                               lp->rx_skbs[lp->fbl_count].skb =
+                                       lp->rx_skbs[i].skb;
+                               lp->rx_skbs[lp->fbl_count].skb_dma =
+                                       lp->rx_skbs[i].skb_dma;
+                       }
+                       lp->fbl_count++;
+               }
+       }
+#endif
+       for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+               lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(lp->data_buf_dma[i]);
+#else
+               if (i >= lp->fbl_count) {
+                       lp->fbl_ptr->bd[i].BuffData = 0;
+                       lp->fbl_ptr->bd[i].BDCtl = 0;
+                       continue;
+               }
+               lp->fbl_ptr->bd[i].BuffData =
+                       cpu_to_le32(lp->rx_skbs[i].skb_dma);
+#endif
                /* BDID is index of FrFD.bd[] */
                lp->fbl_ptr->bd[i].BDCtl =
-                       cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE);
+                       cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) |
+                                   RX_BUF_SIZE);
        }
+#ifdef TC35815_USE_PACKEDBUFFER
        lp->fbl_curid = 0;
+#endif
 
+       printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n",
+              dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr);
        return 0;
 }
 
@@ -713,11 +929,25 @@ tc35815_clear_queues(struct net_device *dev)
        int i;
 
        for (i = 0; i < TX_FD_NUM; i++) {
-               struct sk_buff *skb = (struct sk_buff *)
-                       le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
-               if (skb)
+               u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+               struct sk_buff *skb =
+                       fdsystem != 0xffffffff ?
+                       lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+               if (lp->tx_skbs[i].skb != skb) {
+                       printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+                       panic_queues(dev);
+               }
+#else
+               BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
+               if (skb) {
+                       pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+                       lp->tx_skbs[i].skb = NULL;
+                       lp->tx_skbs[i].skb_dma = 0;
                        dev_kfree_skb_any(skb);
-               lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+               }
+               lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
        }
 
        tc35815_init_queues(dev);
@@ -731,28 +961,53 @@ tc35815_free_queues(struct net_device *dev)
 
        if (lp->tfd_base) {
                for (i = 0; i < TX_FD_NUM; i++) {
-                       struct sk_buff *skb = (struct sk_buff *)
-                               le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
-                       if (skb)
-                               dev_kfree_skb_any(skb);
-                       lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+                       u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+                       struct sk_buff *skb =
+                               fdsystem != 0xffffffff ?
+                               lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+                       if (lp->tx_skbs[i].skb != skb) {
+                               printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+                               panic_queues(dev);
+                       }
+#else
+                       BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
+                       if (skb) {
+                               dev_kfree_skb(skb);
+                               pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+                               lp->tx_skbs[i].skb = NULL;
+                               lp->tx_skbs[i].skb_dma = 0;
+                       }
+                       lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
                }
        }
 
-       lp->rfd_base = NULL;
        lp->rfd_base = NULL;
        lp->rfd_limit = NULL;
        lp->rfd_cur = NULL;
        lp->fbl_ptr = NULL;
 
-       for (i = 0; i < RX_BUF_PAGES; i++) {
-               if (lp->data_buf[i])
-                       free_page((unsigned long)lp->data_buf[i]);
-               lp->data_buf[i] = 0;
+       for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+               if (lp->data_buf[i]) {
+                       free_rxbuf_page(lp->pci_dev,
+                                       lp->data_buf[i], lp->data_buf_dma[i]);
+                       lp->data_buf[i] = NULL;
+               }
+#else
+               if (lp->rx_skbs[i].skb) {
+                       free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb,
+                                      lp->rx_skbs[i].skb_dma);
+                       lp->rx_skbs[i].skb = NULL;
+               }
+#endif
+       }
+       if (lp->fd_buf) {
+               pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM,
+                                   lp->fd_buf, lp->fd_buf_dma);
+               lp->fd_buf = NULL;
        }
-       if (lp->fd_buf)
-               __free_pages(lp->fd_buf, FD_PAGE_ORDER);
-       lp->fd_buf = NULL;
 }
 
 static void
@@ -792,6 +1047,7 @@ dump_rxfd(struct RxFD *fd)
        return bd_count;
 }
 
+#if defined(DEBUG) || defined(TC35815_USE_PACKEDBUFFER)
 static void
 dump_frfd(struct FrFD *fd)
 {
@@ -802,20 +1058,22 @@ dump_frfd(struct FrFD *fd)
               le32_to_cpu(fd->fd.FDStat),
               le32_to_cpu(fd->fd.FDCtl));
        printk("BD: ");
-       for (i = 0; i < RX_BUF_PAGES; i++)
+       for (i = 0; i < RX_BUF_NUM; i++)
                printk(" %08x %08x",
                       le32_to_cpu(fd->bd[i].BuffData),
                       le32_to_cpu(fd->bd[i].BDCtl));
        printk("\n");
 }
+#endif
 
+#ifdef DEBUG
 static void
 panic_queues(struct net_device *dev)
 {
        struct tc35815_local *lp = dev->priv;
        int i;
 
-       printk("TxFD base %p, start %d, end %d\n",
+       printk("TxFD base %p, start %u, end %u\n",
               lp->tfd_base, lp->tfd_start, lp->tfd_end);
        printk("RxFD base %p limit %p cur %p\n",
               lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
@@ -829,31 +1087,13 @@ panic_queues(struct net_device *dev)
        dump_frfd(lp->fbl_ptr);
        panic("%s: Illegal queue state.", dev->name);
 }
-
-#if 0
-static void print_buf(char *add, int length)
-{
-       int i;
-       int len = length;
-
-       printk("print_buf(%08x)(%x)\n", (unsigned int) add,length);
-
-       if (len > 100)
-               len = 100;
-       for (i = 0; i < len; i++) {
-               printk(" %2.2X", (unsigned char) add[i]);
-               if (!(i % 16))
-                       printk("\n");
-       }
-       printk("\n");
-}
 #endif
 
 static void print_eth(char *add)
 {
        int i;
 
-       printk("print_eth(%08x)\n", (unsigned int) add);
+       printk("print_eth(%p)\n", add);
        for (i = 0; i < 6; i++)
                printk(" %2.2X", (unsigned char) add[i + 6]);
        printk(" =>");
@@ -862,6 +1102,73 @@ static void print_eth(char *add)
        printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
 }
 
+static int tc35815_tx_full(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end);
+}
+
+static void tc35815_restart(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       int pid = lp->phy_addr;
+       int do_phy_reset = 1;
+       del_timer(&lp->timer);          /* Kill if running      */
+
+       if (lp->mii_id[0] == 0x0016 && (lp->mii_id[1] & 0xfc00) == 0xf800) {
+               /* Resetting PHY cause problem on some chip... (SEEQ 80221) */
+               do_phy_reset = 0;
+       }
+       if (do_phy_reset) {
+               int timeout;
+               tc_mdio_write(dev, pid, MII_BMCR, BMCR_RESET);
+               timeout = 100;
+               while (--timeout) {
+                       if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_RESET))
+                               break;
+                       udelay(1);
+               }
+               if (!timeout)
+                       printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name);
+       }
+
+       tc35815_chip_reset(dev);
+       tc35815_clear_queues(dev);
+       tc35815_chip_init(dev);
+       /* Reconfigure CAM again since tc35815_chip_init() initialize it. */
+       tc35815_set_multicast_list(dev);
+}
+
+static void tc35815_tx_timeout(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+
+       printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+              dev->name, tc_readl(&tr->Tx_Stat));
+
+       /* Try to restart the adaptor. */
+       spin_lock_irq(&lp->lock);
+       tc35815_restart(dev);
+       spin_unlock_irq(&lp->lock);
+
+       lp->stats.tx_errors++;
+
+       /* If we have space available to accept new transmit
+        * requests, wake up the queueing layer.  This would
+        * be the case if the chipset_init() call above just
+        * flushes out the tx queue and empties it.
+        *
+        * If instead, the tx queue is retained then the
+        * netif_wake_queue() call should be placed in the
+        * TX completion interrupt handler of the driver instead
+        * of here.
+        */
+       if (!tc35815_tx_full(dev))
+               netif_wake_queue(dev);
+}
+
 /*
  * Open/initialize the board. This is called (in the current kernel)
  * sometime after booting when the 'ifconfig' program is run.
@@ -874,16 +1181,16 @@ static int
 tc35815_open(struct net_device *dev)
 {
        struct tc35815_local *lp = dev->priv;
+
        /*
         * This is used if the interrupt line can turned off (shared).
         * See 3c503.c for an example of selecting the IRQ at config-time.
         */
-
-       if (dev->irq == 0  ||
-           request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, cardname, dev)) {
+       if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, dev->name, dev)) {
                return -EAGAIN;
        }
 
+       del_timer(&lp->timer);          /* Kill if running      */
        tc35815_chip_reset(dev);
 
        if (tc35815_init_queues(dev) != 0) {
@@ -892,138 +1199,119 @@ tc35815_open(struct net_device *dev)
        }
 
        /* Reset the hardware here. Don't forget to set the station address. */
+       spin_lock_irq(&lp->lock);
        tc35815_chip_init(dev);
+       spin_unlock_irq(&lp->lock);
 
-       lp->tbusy = 0;
+       /* We are now ready to accept transmit requeusts from
+        * the queueing layer of the networking.
+        */
        netif_start_queue(dev);
 
        return 0;
 }
 
-static void tc35815_tx_timeout(struct net_device *dev)
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
        struct tc35815_local *lp = dev->priv;
-       struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+       struct TxFD *txfd;
        unsigned long flags;
 
+       /* If some error occurs while trying to transmit this
+        * packet, you should return '1' from this function.
+        * In such a case you _may not_ do anything to the
+        * SKB, it is still owned by the network queueing
+        * layer when an error is returned.  This means you
+        * may not modify any SKB fields, you may not free
+        * the SKB, etc.
+        */
+
+       /* This is the most common case for modern hardware.
+        * The spinlock protects this code from the TX complete
+        * hardware interrupt handler.  Queue flow control is
+        * thus managed under this lock as well.
+        */
        spin_lock_irqsave(&lp->lock, flags);
-       printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
-              dev->name, tc_readl(&tr->Tx_Stat));
-       /* Try to restart the adaptor. */
-       tc35815_chip_reset(dev);
-       tc35815_clear_queues(dev);
-       tc35815_chip_init(dev);
-       lp->tbusy=0;
-       spin_unlock_irqrestore(&lp->lock, flags);
-       dev->trans_start = jiffies;
-       netif_wake_queue(dev);
-}
 
-static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-       struct tc35815_local *lp = dev->priv;
-       struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
-
-       if (netif_queue_stopped(dev)) {
-               /*
-                * If we get here, some higher level has decided we are broken.
-                * There should really be a "kick me" function call instead.
-                */
-               int tickssofar = jiffies - dev->trans_start;
-               if (tickssofar < 5)
-                       return 1;
-               printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
-                      dev->name, tc_readl(&tr->Tx_Stat));
-               /* Try to restart the adaptor. */
-               tc35815_chip_reset(dev);
-               tc35815_clear_queues(dev);
-               tc35815_chip_init(dev);
-               lp->tbusy=0;
-               dev->trans_start = jiffies;
-               netif_wake_queue(dev);
+       /* failsafe... (handle txdone now if half of FDs are used) */
+       if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM >
+           TX_FD_NUM / 2)
+               tc35815_txdone(dev);
+
+       if (netif_msg_pktdata(lp))
+               print_eth(skb->data);
+#ifdef DEBUG
+       if (lp->tx_skbs[lp->tfd_start].skb) {
+               printk("%s: tx_skbs conflict.\n", dev->name);
+               panic_queues(dev);
        }
-
-       /*
-        * Block a timer-based transmit from overlapping. This could better be
-        * done with atomic_swap(1, lp->tbusy), but set_bit() works as well.
-        */
-       if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) {
-               printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
-               dev_kfree_skb_any(skb);
-       } else {
-               short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-               unsigned char *buf = skb->data;
-               struct TxFD *txfd = &lp->tfd_base[lp->tfd_start];
-               unsigned long flags;
-               lp->stats.tx_bytes += skb->len;
-
-
-#ifdef __mips__
-               dma_cache_wback_inv((unsigned long)buf, length);
+#else
+       BUG_ON(lp->tx_skbs[lp->tfd_start].skb);
 #endif
-
-               spin_lock_irqsave(&lp->lock, flags);
-
-               /* failsafe... */
-               if (lp->tfd_start != lp->tfd_end)
-                       tc35815_txdone(dev);
-
-
-               txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf));
-
-               txfd->bd.BDCtl = cpu_to_le32(length);
-               txfd->fd.FDSystem = cpu_to_le32((__u32)skb);
-               txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
-
-               if (lp->tfd_start == lp->tfd_end) {
-                       /* Start DMA Transmitter. */
-                       txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+       lp->tx_skbs[lp->tfd_start].skb = skb;
+       lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+       /*add to ring */
+       txfd = &lp->tfd_base[lp->tfd_start];
+       txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
+       txfd->bd.BDCtl = cpu_to_le32(skb->len);
+       txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
+       txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+
+       if (lp->tfd_start == lp->tfd_end) {
+               struct tc35815_regs __iomem *tr =
+                       (struct tc35815_regs __iomem *)dev->base_addr;
+               /* Start DMA Transmitter. */
+               txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
 #ifdef GATHER_TXINT
-                       txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+               txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
 #endif
-                       if (tc35815_debug > 2) {
-                               printk("%s: starting TxFD.\n", dev->name);
-                               dump_txfd(txfd);
-                               if (tc35815_debug > 3)
-                                       print_eth(buf);
-                       }
-                       tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
-               } else {
-                       txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
-                       if (tc35815_debug > 2) {
-                               printk("%s: queueing TxFD.\n", dev->name);
-                               dump_txfd(txfd);
-                               if (tc35815_debug > 3)
-                                       print_eth(buf);
-                       }
+               if (netif_msg_tx_queued(lp)) {
+                       printk("%s: starting TxFD.\n", dev->name);
+                       dump_txfd(txfd);
                }
-               lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
+               tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
+       } else {
+               txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
+               if (netif_msg_tx_queued(lp)) {
+                       printk("%s: queueing TxFD.\n", dev->name);
+                       dump_txfd(txfd);
+               }
+       }
+       lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
 
-               dev->trans_start = jiffies;
+       dev->trans_start = jiffies;
 
-               if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) {
-                       /* we can send another packet */
-                       lp->tbusy = 0;
-                       netif_start_queue(dev);
-               } else {
-                       netif_stop_queue(dev);
-                       if (tc35815_debug > 1)
-                               printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
-               }
-               spin_unlock_irqrestore(&lp->lock, flags);
+       /* If we just used up the very last entry in the
+        * TX ring on this device, tell the queueing
+        * layer to send no more.
+        */
+       if (tc35815_tx_full(dev)) {
+               if (netif_msg_tx_queued(lp))
+                       printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
+               netif_stop_queue(dev);
        }
 
+       /* When the TX completion hw interrupt arrives, this
+        * is when the transmit statistics are updated.
+        */
+
+       spin_unlock_irqrestore(&lp->lock, flags);
        return 0;
 }
 
 #define FATAL_ERROR_INT \
        (Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
-static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
+static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
 {
        static int count;
        printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
               dev->name, status);
-
        if (status & Int_IntPCI)
                printk(" IntPCI");
        if (status & Int_DmParErr)
@@ -1033,110 +1321,170 @@ static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
        printk("\n");
        if (count++ > 100)
                panic("%s: Too many fatal errors.", dev->name);
-       printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname);
+       printk(KERN_WARNING "%s: Resetting ...\n", dev->name);
        /* Try to restart the adaptor. */
-       tc35815_chip_reset(dev);
-       tc35815_clear_queues(dev);
-       tc35815_chip_init(dev);
+       tc35815_restart(dev);
+}
+
+#ifdef TC35815_NAPI
+static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
+#else
+static int tc35815_do_interrupt(struct net_device *dev, u32 status)
+#endif
+{
+       struct tc35815_local *lp = dev->priv;
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       int ret = -1;
+
+       /* Fatal errors... */
+       if (status & FATAL_ERROR_INT) {
+               tc35815_fatal_error_interrupt(dev, status);
+               return 0;
+       }
+       /* recoverable errors */
+       if (status & Int_IntFDAEx) {
+               /* disable FDAEx int. (until we make rooms...) */
+               tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
+               printk(KERN_WARNING
+                      "%s: Free Descriptor Area Exhausted (%#x).\n",
+                      dev->name, status);
+               lp->stats.rx_dropped++;
+               ret = 0;
+       }
+       if (status & Int_IntBLEx) {
+               /* disable BLEx int. (until we make rooms...) */
+               tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
+               printk(KERN_WARNING
+                      "%s: Buffer List Exhausted (%#x).\n",
+                      dev->name, status);
+               lp->stats.rx_dropped++;
+               ret = 0;
+       }
+       if (status & Int_IntExBD) {
+               printk(KERN_WARNING
+                      "%s: Excessive Buffer Descriptiors (%#x).\n",
+                      dev->name, status);
+               lp->stats.rx_length_errors++;
+               ret = 0;
+       }
+
+       /* normal notification */
+       if (status & Int_IntMacRx) {
+               /* Got a packet(s). */
+#ifdef TC35815_NAPI
+               ret = tc35815_rx(dev, limit);
+#else
+               tc35815_rx(dev);
+               ret = 0;
+#endif
+               lp->lstats.rx_ints++;
+       }
+       if (status & Int_IntMacTx) {
+               /* Transmit complete. */
+               lp->lstats.tx_ints++;
+               tc35815_txdone(dev);
+               netif_wake_queue(dev);
+               ret = 0;
+       }
+       return ret;
 }
 
 /*
  * The typical workload of the driver:
- *   Handle the network interface interrupts.
+ * Handle the network interface interrupts.
  */
 static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
-       struct tc35815_regs *tr;
-       struct tc35815_local *lp;
-       int status, boguscount = 0;
-       int handled = 0;
-
-       if (dev == NULL) {
-               printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
-               return IRQ_NONE;
-       }
-
-       tr = (struct tc35815_regs*)dev->base_addr;
-       lp = dev->priv;
-
-       do {
-               status = tc_readl(&tr->Int_Src);
-               if (status == 0)
-                       break;
-               handled = 1;
-               tc_writel(status, &tr->Int_Src);        /* write to clear */
-
-               /* Fatal errors... */
-               if (status & FATAL_ERROR_INT) {
-                       tc35815_fatal_error_interrupt(dev, status);
-                       break;
-               }
-               /* recoverable errors */
-               if (status & Int_IntFDAEx) {
-                       /* disable FDAEx int. (until we make rooms...) */
-                       tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
-                       printk(KERN_WARNING
-                              "%s: Free Descriptor Area Exhausted (%#x).\n",
-                              dev->name, status);
-                       lp->stats.rx_dropped++;
-               }
-               if (status & Int_IntBLEx) {
-                       /* disable BLEx int. (until we make rooms...) */
-                       tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
-                       printk(KERN_WARNING
-                              "%s: Buffer List Exhausted (%#x).\n",
-                              dev->name, status);
-                       lp->stats.rx_dropped++;
-               }
-               if (status & Int_IntExBD) {
-                       printk(KERN_WARNING
-                              "%s: Excessive Buffer Descriptiors (%#x).\n",
-                              dev->name, status);
-                       lp->stats.rx_length_errors++;
-               }
-               /* normal notification */
-               if (status & Int_IntMacRx) {
-                       /* Got a packet(s). */
-                       lp->lstats.rx_ints++;
-                       tc35815_rx(dev);
-               }
-               if (status & Int_IntMacTx) {
-                       lp->lstats.tx_ints++;
-                       tc35815_txdone(dev);
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+#ifdef TC35815_NAPI
+       u32 dmactl = tc_readl(&tr->DMA_Ctl);
+
+       if (!(dmactl & DMA_IntMask)) {
+               /* disable interrupts */
+               tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
+               if (netif_rx_schedule_prep(dev))
+                       __netif_rx_schedule(dev);
+               else {
+                       printk(KERN_ERR "%s: interrupt taken in poll\n",
+                              dev->name);
+                       BUG();
                }
-       } while (++boguscount < 20) ;
+               (void)tc_readl(&tr->Int_Src);   /* flush */
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+#else
+       struct tc35815_local *lp = dev->priv;
+       int handled;
+       u32 status;
+
+       spin_lock(&lp->lock);
+       status = tc_readl(&tr->Int_Src);
+       tc_writel(status, &tr->Int_Src);        /* write to clear */
+       handled = tc35815_do_interrupt(dev, status);
+       (void)tc_readl(&tr->Int_Src);   /* flush */
+       spin_unlock(&lp->lock);
+       return IRQ_RETVAL(handled >= 0);
+#endif /* TC35815_NAPI */
+}
 
-       return IRQ_RETVAL(handled);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tc35815_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       tc35815_interrupt(dev->irq, dev);
+       enable_irq(dev->irq);
 }
+#endif
 
 /* We have a good packet(s), get it/them out of the buffers. */
+#ifdef TC35815_NAPI
+static int
+tc35815_rx(struct net_device *dev, int limit)
+#else
 static void
 tc35815_rx(struct net_device *dev)
+#endif
 {
        struct tc35815_local *lp = dev->priv;
-       struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
        unsigned int fdctl;
        int i;
        int buf_free_count = 0;
        int fd_free_count = 0;
+#ifdef TC35815_NAPI
+       int received = 0;
+#endif
 
        while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
                int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
                int pkt_len = fdctl & FD_FDLength_MASK;
-               struct RxFD *next_rfd;
                int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+#ifdef DEBUG
+               struct RxFD *next_rfd;
+#endif
+#if (RX_CTL_CMD & Rx_StripCRC) == 0
+               pkt_len -= 4;
+#endif
 
-               if (tc35815_debug > 2)
+               if (netif_msg_rx_status(lp))
                        dump_rxfd(lp->rfd_cur);
                if (status & Rx_Good) {
-                       /* Malloc up new buffer. */
                        struct sk_buff *skb;
                        unsigned char *data;
-                       int cur_bd, offset;
-
-                       lp->stats.rx_bytes += pkt_len;
+                       int cur_bd;
+#ifdef TC35815_USE_PACKEDBUFFER
+                       int offset;
+#endif
 
+#ifdef TC35815_NAPI
+                       if (--limit < 0)
+                               break;
+#endif
+#ifdef TC35815_USE_PACKEDBUFFER
+                       BUG_ON(bd_count > 2);
                        skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
                        if (skb == NULL) {
                                printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
@@ -1154,25 +1502,69 @@ tc35815_rx(struct net_device *dev)
                        while (offset < pkt_len && cur_bd < bd_count) {
                                int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) &
                                        BD_BuffLength_MASK;
-                               void *rxbuf =
-                                       bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData));
-#ifdef __mips__
-                               dma_cache_inv((unsigned long)rxbuf, len);
+                               dma_addr_t dma = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData);
+                               void *rxbuf = rxbuf_bus_to_virt(lp, dma);
+                               if (offset + len > pkt_len)
+                                       len = pkt_len - offset;
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+                               pci_dma_sync_single_for_cpu(lp->pci_dev,
+                                                           dma, len,
+                                                           PCI_DMA_FROMDEVICE);
 #endif
                                memcpy(data + offset, rxbuf, len);
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+                               pci_dma_sync_single_for_device(lp->pci_dev,
+                                                              dma, len,
+                                                              PCI_DMA_FROMDEVICE);
+#endif
                                offset += len;
                                cur_bd++;
                        }
-#if 0
-                       print_buf(data,pkt_len);
+#else /* TC35815_USE_PACKEDBUFFER */
+                       BUG_ON(bd_count > 1);
+                       cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl)
+                                 & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
+#ifdef DEBUG
+                       if (cur_bd >= RX_BUF_NUM) {
+                               printk("%s: invalid BDID.\n", dev->name);
+                               panic_queues(dev);
+                       }
+                       BUG_ON(lp->rx_skbs[cur_bd].skb_dma !=
+                              (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3));
+                       if (!lp->rx_skbs[cur_bd].skb) {
+                               printk("%s: NULL skb.\n", dev->name);
+                               panic_queues(dev);
+                       }
+#else
+                       BUG_ON(cur_bd >= RX_BUF_NUM);
 #endif
-                       if (tc35815_debug > 3)
+                       skb = lp->rx_skbs[cur_bd].skb;
+                       prefetch(skb->data);
+                       lp->rx_skbs[cur_bd].skb = NULL;
+                       lp->fbl_count--;
+                       pci_unmap_single(lp->pci_dev,
+                                        lp->rx_skbs[cur_bd].skb_dma,
+                                        RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                       if (!HAVE_DMA_RXALIGN(lp))
+                               memmove(skb->data, skb->data - 2, pkt_len);
+                       data = skb_put(skb, pkt_len);
+#endif /* TC35815_USE_PACKEDBUFFER */
+                       if (netif_msg_pktdata(lp))
                                print_eth(data);
                        skb->protocol = eth_type_trans(skb, dev);
+#ifdef TC35815_NAPI
+                       netif_receive_skb(skb);
+                       received++;
+#else
                        netif_rx(skb);
+#endif
+                       dev->last_rx = jiffies;
                        lp->stats.rx_packets++;
+                       lp->stats.rx_bytes += pkt_len;
                } else {
                        lp->stats.rx_errors++;
+                       printk(KERN_DEBUG "%s: Rx error (status %x)\n",
+                              dev->name, status & Rx_Stat_Mask);
                        /* WORKAROUND: LongErr and CRCErr means Overflow. */
                        if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
                                status &= ~(Rx_LongErr|Rx_CRCErr);
@@ -1189,63 +1581,150 @@ tc35815_rx(struct net_device *dev)
                        int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
                        unsigned char id =
                                (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
-                       if (id >= RX_BUF_PAGES) {
+#ifdef DEBUG
+                       if (id >= RX_BUF_NUM) {
                                printk("%s: invalid BDID.\n", dev->name);
                                panic_queues(dev);
                        }
+#else
+                       BUG_ON(id >= RX_BUF_NUM);
+#endif
                        /* free old buffers */
-                       while (lp->fbl_curid != id) {
-                               bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl);
+#ifdef TC35815_USE_PACKEDBUFFER
+                       while (lp->fbl_curid != id)
+#else
+                       while (lp->fbl_count < RX_BUF_NUM)
+#endif
+                       {
+#ifdef TC35815_USE_PACKEDBUFFER
+                               unsigned char curid = lp->fbl_curid;
+#else
+                               unsigned char curid =
+                                       (id + 1 + lp->fbl_count) % RX_BUF_NUM;
+#endif
+                               struct BDesc *bd = &lp->fbl_ptr->bd[curid];
+#ifdef DEBUG
+                               bdctl = le32_to_cpu(bd->BDCtl);
                                if (bdctl & BD_CownsBD) {
                                        printk("%s: Freeing invalid BD.\n",
                                               dev->name);
                                        panic_queues(dev);
                                }
+#endif
                                /* pass BD to controler */
+#ifndef TC35815_USE_PACKEDBUFFER
+                               if (!lp->rx_skbs[curid].skb) {
+                                       lp->rx_skbs[curid].skb =
+                                               alloc_rxbuf_skb(dev,
+                                                               lp->pci_dev,
+                                                               &lp->rx_skbs[curid].skb_dma);
+                                       if (!lp->rx_skbs[curid].skb)
+                                               break; /* try on next reception */
+                                       bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma);
+                               }
+#endif /* TC35815_USE_PACKEDBUFFER */
                                /* Note: BDLength was modified by chip. */
-                               lp->fbl_ptr->bd[lp->fbl_curid].BDCtl =
-                                       cpu_to_le32(BD_CownsBD |
-                                                   (lp->fbl_curid << BD_RxBDID_SHIFT) |
-                                                   PAGE_SIZE);
-                               lp->fbl_curid =
-                                       (lp->fbl_curid + 1) % RX_BUF_PAGES;
-                               if (tc35815_debug > 2) {
+                               bd->BDCtl = cpu_to_le32(BD_CownsBD |
+                                                       (curid << BD_RxBDID_SHIFT) |
+                                                       RX_BUF_SIZE);
+#ifdef TC35815_USE_PACKEDBUFFER
+                               lp->fbl_curid = (curid + 1) % RX_BUF_NUM;
+                               if (netif_msg_rx_status(lp)) {
                                        printk("%s: Entering new FBD %d\n",
                                               dev->name, lp->fbl_curid);
                                        dump_frfd(lp->fbl_ptr);
                                }
+#else
+                               lp->fbl_count++;
+#endif
                                buf_free_count++;
                        }
                }
 
                /* put RxFD back to controller */
-               next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext));
-#ifdef __mips__
-               next_rfd = (struct RxFD *)vtonocache(next_rfd);
-#endif
+#ifdef DEBUG
+               next_rfd = fd_bus_to_virt(lp,
+                                         le32_to_cpu(lp->rfd_cur->fd.FDNext));
                if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
                        printk("%s: RxFD FDNext invalid.\n", dev->name);
                        panic_queues(dev);
                }
+#endif
                for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
                        /* pass FD to controler */
-                       lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);       /* for debug */
+#ifdef DEBUG
+                       lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);
+#else
+                       lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL);
+#endif
                        lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
                        lp->rfd_cur++;
                        fd_free_count++;
                }
-
-               lp->rfd_cur = next_rfd;
+               if (lp->rfd_cur > lp->rfd_limit)
+                       lp->rfd_cur = lp->rfd_base;
+#ifdef DEBUG
+               if (lp->rfd_cur != next_rfd)
+                       printk("rfd_cur = %p, next_rfd %p\n",
+                              lp->rfd_cur, next_rfd);
+#endif
        }
 
        /* re-enable BL/FDA Exhaust interrupts. */
        if (fd_free_count) {
-               tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En);
+               struct tc35815_regs __iomem *tr =
+                       (struct tc35815_regs __iomem *)dev->base_addr;
+               u32 en, en_old = tc_readl(&tr->Int_En);
+               en = en_old | Int_FDAExEn;
                if (buf_free_count)
-                       tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En);
+                       en |= Int_BLExEn;
+               if (en != en_old)
+                       tc_writel(en, &tr->Int_En);
        }
+#ifdef TC35815_NAPI
+       return received;
+#endif
 }
 
+#ifdef TC35815_NAPI
+static int
+tc35815_poll(struct net_device *dev, int *budget)
+{
+       struct tc35815_local *lp = dev->priv;
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       int limit = min(*budget, dev->quota);
+       int received = 0, handled;
+       u32 status;
+
+       spin_lock(&lp->lock);
+       status = tc_readl(&tr->Int_Src);
+       do {
+               tc_writel(status, &tr->Int_Src);        /* write to clear */
+
+               handled = tc35815_do_interrupt(dev, status, limit);
+               if (handled >= 0) {
+                       received += handled;
+                       limit -= handled;
+                       if (limit <= 0)
+                               break;
+               }
+               status = tc_readl(&tr->Int_Src);
+       } while (status);
+       spin_unlock(&lp->lock);
+
+       dev->quota -= received;
+       *budget -= received;
+       if (limit <= 0)
+               return 1;
+
+       netif_rx_complete(dev);
+       /* enable interrupts */
+       tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
+       return 0;
+}
+#endif
+
 #ifdef NO_CHECK_CARRIER
 #define TX_STA_ERR     (Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr)
 #else
@@ -1264,9 +1743,17 @@ tc35815_check_tx_stat(struct net_device *dev, int status)
        if (status & Tx_TxColl_MASK)
                lp->stats.collisions += status & Tx_TxColl_MASK;
 
+#ifndef NO_CHECK_CARRIER
+       /* TX4939 does not have NCarr */
+       if (lp->boardtype == TC35815_TX4939)
+               status &= ~Tx_NCarr;
+#ifdef WORKAROUND_LOSTCAR
        /* WORKAROUND: ignore LostCrS in full duplex operation */
-       if (lp->fullduplex)
+       if ((lp->timer_state != asleep && lp->timer_state != lcheck)
+           || lp->fullduplex)
                status &= ~Tx_NCarr;
+#endif
+#endif
 
        if (!(status & TX_STA_ERR)) {
                /* no error. */
@@ -1282,6 +1769,15 @@ tc35815_check_tx_stat(struct net_device *dev, int status)
        if (status & Tx_Under) {
                lp->stats.tx_fifo_errors++;
                msg = "Tx FIFO Underrun.";
+               if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {
+                       lp->lstats.tx_underrun++;
+                       if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
+                               struct tc35815_regs __iomem *tr =
+                                       (struct tc35815_regs __iomem *)dev->base_addr;
+                               tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
+                               msg = "Tx FIFO Underrun.Change Tx threshold to max.";
+                       }
+               }
        }
        if (status & Tx_Defer) {
                lp->stats.tx_fifo_errors++;
@@ -1305,18 +1801,19 @@ tc35815_check_tx_stat(struct net_device *dev, int status)
                lp->stats.tx_heartbeat_errors++;
                msg = "Signal Quality Error.";
        }
-       if (msg)
+       if (msg && netif_msg_tx_err(lp))
                printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
 }
 
+/* This handles TX complete events posted by the device
+ * via interrupts.
+ */
 static void
 tc35815_txdone(struct net_device *dev)
 {
        struct tc35815_local *lp = dev->priv;
-       struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
        struct TxFD *txfd;
        unsigned int fdctl;
-       int num_done = 0;
 
        txfd = &lp->tfd_base[lp->tfd_end];
        while (lp->tfd_start != lp->tfd_end &&
@@ -1324,38 +1821,61 @@ tc35815_txdone(struct net_device *dev)
                int status = le32_to_cpu(txfd->fd.FDStat);
                struct sk_buff *skb;
                unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
+               u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem);
 
-               if (tc35815_debug > 2) {
+               if (netif_msg_tx_done(lp)) {
                        printk("%s: complete TxFD.\n", dev->name);
                        dump_txfd(txfd);
                }
                tc35815_check_tx_stat(dev, status);
 
-               skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem);
+               skb = fdsystem != 0xffffffff ?
+                       lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+               if (lp->tx_skbs[lp->tfd_end].skb != skb) {
+                       printk("%s: tx_skbs mismatch.\n", dev->name);
+                       panic_queues(dev);
+               }
+#else
+               BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb);
+#endif
                if (skb) {
+                       lp->stats.tx_bytes += skb->len;
+                       pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE);
+                       lp->tx_skbs[lp->tfd_end].skb = NULL;
+                       lp->tx_skbs[lp->tfd_end].skb_dma = 0;
+#ifdef TC35815_NAPI
                        dev_kfree_skb_any(skb);
+#else
+                       dev_kfree_skb_irq(skb);
+#endif
                }
-               txfd->fd.FDSystem = cpu_to_le32(0);
+               txfd->fd.FDSystem = cpu_to_le32(0xffffffff);
 
-               num_done++;
                lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
                txfd = &lp->tfd_base[lp->tfd_end];
-               if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) {
+#ifdef DEBUG
+               if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {
                        printk("%s: TxFD FDNext invalid.\n", dev->name);
                        panic_queues(dev);
                }
+#endif
                if (fdnext & FD_Next_EOL) {
                        /* DMA Transmitter has been stopping... */
                        if (lp->tfd_end != lp->tfd_start) {
+                               struct tc35815_regs __iomem *tr =
+                                       (struct tc35815_regs __iomem *)dev->base_addr;
                                int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
                                struct TxFD* txhead = &lp->tfd_base[head];
                                int qlen = (lp->tfd_start + TX_FD_NUM
                                            - lp->tfd_end) % TX_FD_NUM;
 
+#ifdef DEBUG
                                if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
                                        printk("%s: TxFD FDCtl invalid.\n", dev->name);
                                        panic_queues(dev);
                                }
+#endif
                                /* log max queue length */
                                if (lp->lstats.max_tx_qlen < qlen)
                                        lp->lstats.max_tx_qlen = qlen;
@@ -1366,21 +1886,23 @@ tc35815_txdone(struct net_device *dev)
 #ifdef GATHER_TXINT
                                txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
 #endif
-                               if (tc35815_debug > 2) {
+                               if (netif_msg_tx_queued(lp)) {
                                        printk("%s: start TxFD on queue.\n",
                                               dev->name);
                                        dump_txfd(txfd);
                                }
-                               tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+                               tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
                        }
                        break;
                }
        }
 
-       if (num_done > 0 && lp->tbusy) {
-               lp->tbusy = 0;
-               netif_start_queue(dev);
-       }
+       /* If we had stopped the queue due to a "tx full"
+        * condition, and space has now been made available,
+        * wake up the queue.
+        */
+       if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev))
+               netif_wake_queue(dev);
 }
 
 /* The inverse routine to tc35815_open(). */
@@ -1388,18 +1910,18 @@ static int
 tc35815_close(struct net_device *dev)
 {
        struct tc35815_local *lp = dev->priv;
-
-       lp->tbusy = 1;
        netif_stop_queue(dev);
 
        /* Flush the Tx and disable Rx here. */
 
+       del_timer(&lp->timer);          /* Kill if running      */
        tc35815_chip_reset(dev);
        free_irq(dev->irq, dev);
 
        tc35815_free_queues(dev);
 
        return 0;
+
 }
 
 /*
@@ -1409,29 +1931,29 @@ tc35815_close(struct net_device *dev)
 static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
 {
        struct tc35815_local *lp = dev->priv;
-       struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-       unsigned long flags;
-
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
        if (netif_running(dev)) {
-               spin_lock_irqsave(&lp->lock, flags);
                /* Update the statistics from the device registers. */
                lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
-               spin_unlock_irqrestore(&lp->lock, flags);
        }
 
        return &lp->stats;
 }
 
-static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr)
+static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr)
 {
+       struct tc35815_local *lp = dev->priv;
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
        int cam_index = index * 6;
-       unsigned long cam_data;
-       unsigned long saved_addr;
+       u32 cam_data;
+       u32 saved_addr;
        saved_addr = tc_readl(&tr->CAM_Adr);
 
-       if (tc35815_debug > 1) {
+       if (netif_msg_hw(lp)) {
                int i;
-               printk(KERN_DEBUG "%s: CAM %d:", cardname, index);
+               printk(KERN_DEBUG "%s: CAM %d:", dev->name, index);
                for (i = 0; i < 6; i++)
                        printk(" %02x", addr[i]);
                printk("\n");
@@ -1458,14 +1980,6 @@ static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned c
                tc_writel(cam_data, &tr->CAM_Data);
        }
 
-       if (tc35815_debug > 2) {
-               int i;
-               for (i = cam_index / 4; i < cam_index / 4 + 2; i++) {
-                       tc_writel(i * 4, &tr->CAM_Adr);
-                       printk("CAM 0x%x: %08lx",
-                              i * 4, tc_readl(&tr->CAM_Data));
-               }
-       }
        tc_writel(saved_addr, &tr->CAM_Adr);
 }
 
@@ -1480,10 +1994,19 @@ static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned c
 static void
 tc35815_set_multicast_list(struct net_device *dev)
 {
-       struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
 
        if (dev->flags&IFF_PROMISC)
        {
+#ifdef WORKAROUND_100HALF_PROMISC
+               /* With some (all?) 100MHalf HUB, controller will hang
+                * if we enabled promiscuous mode before linkup... */
+               struct tc35815_local *lp = dev->priv;
+               int pid = lp->phy_addr;
+               if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS))
+                       return;
+#endif
                /* Enable promiscuous mode */
                tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
        }
@@ -1505,7 +2028,7 @@ tc35815_set_multicast_list(struct net_device *dev)
                        if (!cur_addr)
                                break;
                        /* entry 0,1 is reserved. */
-                       tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr);
+                       tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr);
                        ena_bits |= CAM_Ena_Bit(i + 2);
                }
                tc_writel(ena_bits, &tr->CAM_Ena);
@@ -1517,122 +2040,753 @@ tc35815_set_multicast_list(struct net_device *dev)
        }
 }
 
-static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg)
+static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct tc35815_local *lp = dev->priv;
-       unsigned long data;
-       unsigned long flags;
+       strcpy(info->driver, MODNAME);
+       strcpy(info->version, DRV_VERSION);
+       strcpy(info->bus_info, pci_name(lp->pci_dev));
+}
 
-       spin_lock_irqsave(&lp->lock, flags);
+static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct tc35815_local *lp = dev->priv;
+       spin_lock_irq(&lp->lock);
+       mii_ethtool_gset(&lp->mii, cmd);
+       spin_unlock_irq(&lp->lock);
+       return 0;
+}
+
+static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct tc35815_local *lp = dev->priv;
+       int rc;
+#if 1  /* use our negotiation method... */
+       /* Verify the settings we care about. */
+       if (cmd->autoneg != AUTONEG_ENABLE &&
+           cmd->autoneg != AUTONEG_DISABLE)
+               return -EINVAL;
+       if (cmd->autoneg == AUTONEG_DISABLE &&
+           ((cmd->speed != SPEED_100 &&
+             cmd->speed != SPEED_10) ||
+            (cmd->duplex != DUPLEX_HALF &&
+             cmd->duplex != DUPLEX_FULL)))
+               return -EINVAL;
+
+       /* Ok, do it to it. */
+       spin_lock_irq(&lp->lock);
+       del_timer(&lp->timer);
+       tc35815_start_auto_negotiation(dev, cmd);
+       spin_unlock_irq(&lp->lock);
+       rc = 0;
+#else
+       spin_lock_irq(&lp->lock);
+       rc = mii_ethtool_sset(&lp->mii, cmd);
+       spin_unlock_irq(&lp->lock);
+#endif
+       return rc;
+}
+
+static int tc35815_nway_reset(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       int rc;
+       spin_lock_irq(&lp->lock);
+       rc = mii_nway_restart(&lp->mii);
+       spin_unlock_irq(&lp->lock);
+       return rc;
+}
+
+static u32 tc35815_get_link(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       int rc;
+       spin_lock_irq(&lp->lock);
+       rc = mii_link_ok(&lp->mii);
+       spin_unlock_irq(&lp->lock);
+       return rc;
+}
+
+static u32 tc35815_get_msglevel(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       return lp->msg_enable;
+}
+
+static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
+{
+       struct tc35815_local *lp = dev->priv;
+       lp->msg_enable = datum;
+}
+
+static int tc35815_get_stats_count(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       return sizeof(lp->lstats) / sizeof(int);
+}
 
-       tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
+static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
+{
+       struct tc35815_local *lp = dev->priv;
+       data[0] = lp->lstats.max_tx_qlen;
+       data[1] = lp->lstats.tx_ints;
+       data[2] = lp->lstats.rx_ints;
+       data[3] = lp->lstats.tx_underrun;
+}
+
+static struct {
+       const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+       { "max_tx_qlen" },
+       { "tx_ints" },
+       { "rx_ints" },
+       { "tx_underrun" },
+};
+
+static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+static const struct ethtool_ops tc35815_ethtool_ops = {
+       .get_drvinfo            = tc35815_get_drvinfo,
+       .get_settings           = tc35815_get_settings,
+       .set_settings           = tc35815_set_settings,
+       .nway_reset             = tc35815_nway_reset,
+       .get_link               = tc35815_get_link,
+       .get_msglevel           = tc35815_get_msglevel,
+       .set_msglevel           = tc35815_set_msglevel,
+       .get_strings            = tc35815_get_strings,
+       .get_stats_count        = tc35815_get_stats_count,
+       .get_ethtool_stats      = tc35815_get_ethtool_stats,
+       .get_perm_addr          = ethtool_op_get_perm_addr,
+};
+
+static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct tc35815_local *lp = dev->priv;
+       int rc;
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       spin_lock_irq(&lp->lock);
+       rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+       spin_unlock_irq(&lp->lock);
+
+       return rc;
+}
+
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       u32 data;
+       tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA);
        while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
                ;
        data = tc_readl(&tr->MD_Data);
-       spin_unlock_irqrestore(&lp->lock, flags);
-       return data;
+       return data & 0xffff;
+}
+
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+                         int val)
+{
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       tc_writel(val, &tr->MD_Data);
+       tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA);
+       while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+               ;
 }
 
-static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg)
+/* Auto negotiation.  The scheme is very simple.  We have a timer routine
+ * that keeps watching the auto negotiation process as it progresses.
+ * The DP83840 is first told to start doing it's thing, we set up the time
+ * and place the timer state machine in it's initial state.
+ *
+ * Here the timer peeks at the DP83840 status registers at each click to see
+ * if the auto negotiation has completed, we assume here that the DP83840 PHY
+ * will time out at some point and just tell us what (didn't) happen.  For
+ * complete coverage we only allow so many of the ticks at this level to run,
+ * when this has expired we print a warning message and try another strategy.
+ * This "other" strategy is to force the interface into various speed/duplex
+ * configurations and we stop when we see a link-up condition before the
+ * maximum number of "peek" ticks have occurred.
+ *
+ * Once a valid link status has been detected we configure the BigMAC and
+ * the rest of the Happy Meal to speak the most efficient protocol we could
+ * get a clean link for.  The priority for link configurations, highest first
+ * is:
+ *                 100 Base-T Full Duplex
+ *                 100 Base-T Half Duplex
+ *                 10 Base-T Full Duplex
+ *                 10 Base-T Half Duplex
+ *
+ * We start a new timer now, after a successful auto negotiation status has
+ * been detected.  This timer just waits for the link-up bit to get set in
+ * the BMCR of the DP83840.  When this occurs we print a kernel log message
+ * describing the link type in use and the fact that it is up.
+ *
+ * If a fatal error of some sort is signalled and detected in the interrupt
+ * service routine, and the chip is reset, or the link is ifconfig'd down
+ * and then back up, this entire process repeats itself all over again.
+ */
+/* Note: Above comments are come from sunhme driver. */
+
+static int tc35815_try_next_permutation(struct net_device *dev)
 {
        struct tc35815_local *lp = dev->priv;
-       unsigned long flags;
+       int pid = lp->phy_addr;
+       unsigned short bmcr;
 
-       spin_lock_irqsave(&lp->lock, flags);
+       bmcr = tc_mdio_read(dev, pid, MII_BMCR);
 
-       tc_writel(d, &tr->MD_Data);
-       tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA);
-       while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
-               ;
-       spin_unlock_irqrestore(&lp->lock, flags);
+       /* Downgrade from full to half duplex.  Only possible via ethtool.  */
+       if (bmcr & BMCR_FULLDPLX) {
+               bmcr &= ~BMCR_FULLDPLX;
+               printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+               tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+               return 0;
+       }
+
+       /* Downgrade from 100 to 10. */
+       if (bmcr & BMCR_SPEED100) {
+               bmcr &= ~BMCR_SPEED100;
+               printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+               tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+               return 0;
+       }
+
+       /* We've tried everything. */
+       return -1;
 }
 
-static void tc35815_phy_chip_init(struct net_device *dev)
+static void
+tc35815_display_link_mode(struct net_device *dev)
 {
        struct tc35815_local *lp = dev->priv;
-       struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-       static int first = 1;
-       unsigned short ctl;
-
-       if (first) {
-               unsigned short id0, id1;
-               int count;
-               first = 0;
-
-               /* first data written to the PHY will be an ID number */
-               tc_phy_write(dev, 0, tr, 0, MII_CONTROL);       /* ID:0 */
-#if 0
-               tc_phy_write(dev, MIICNTL_RESET, tr, 0, MII_CONTROL);
-               printk(KERN_INFO "%s: Resetting PHY...", dev->name);
-               while (tc_phy_read(dev, tr, 0, MII_CONTROL) & MIICNTL_RESET)
-                       ;
-               printk("\n");
-               tc_phy_write(dev, MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0,
-                            MII_CONTROL);
-#endif
-               id0 = tc_phy_read(dev, tr, 0, MII_PHY_ID0);
-               id1 = tc_phy_read(dev, tr, 0, MII_PHY_ID1);
-               printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name,
-                      id0, id1);
-               if (lp->option & TC35815_OPT_10M) {
-                       lp->linkspeed = 10;
-                       lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
-               } else if (lp->option & TC35815_OPT_100M) {
-                       lp->linkspeed = 100;
-                       lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+       int pid = lp->phy_addr;
+       unsigned short lpa, bmcr;
+       char *speed = "", *duplex = "";
+
+       lpa = tc_mdio_read(dev, pid, MII_LPA);
+       bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+       if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+               speed = "100Mb/s";
+       else
+               speed = "10Mb/s";
+       if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+               duplex = "Full Duplex";
+       else
+               duplex = "Half Duplex";
+
+       if (netif_msg_link(lp))
+               printk(KERN_INFO "%s: Link is up at %s, %s.\n",
+                      dev->name, speed, duplex);
+       printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+              dev->name,
+              bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+}
+
+static void tc35815_display_forced_link_mode(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       int pid = lp->phy_addr;
+       unsigned short bmcr;
+       char *speed = "", *duplex = "";
+
+       bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+       if (bmcr & BMCR_SPEED100)
+               speed = "100Mb/s";
+       else
+               speed = "10Mb/s";
+       if (bmcr & BMCR_FULLDPLX)
+               duplex = "Full Duplex.\n";
+       else
+               duplex = "Half Duplex.\n";
+
+       if (netif_msg_link(lp))
+               printk(KERN_INFO "%s: Link has been forced up at %s, %s",
+                      dev->name, speed, duplex);
+}
+
+static void tc35815_set_link_modes(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       int pid = lp->phy_addr;
+       unsigned short bmcr, lpa;
+       int speed;
+
+       if (lp->timer_state == arbwait) {
+               lpa = tc_mdio_read(dev, pid, MII_LPA);
+               bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+               printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+                      dev->name,
+                      bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+               if (!(lpa & (LPA_10HALF | LPA_10FULL |
+                            LPA_100HALF | LPA_100FULL))) {
+                       /* fall back to 10HALF */
+                       printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n",
+                              dev->name, lpa);
+                       lpa = LPA_10HALF;
+               }
+               if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+                       lp->fullduplex = 1;
+               else
+                       lp->fullduplex = 0;
+               if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+                       speed = 100;
+               else
+                       speed = 10;
+       } else {
+               /* Forcing a link mode. */
+               bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+               if (bmcr & BMCR_FULLDPLX)
+                       lp->fullduplex = 1;
+               else
+                       lp->fullduplex = 0;
+               if (bmcr & BMCR_SPEED100)
+                       speed = 100;
+               else
+                       speed = 10;
+       }
+
+       tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl);
+       if (lp->fullduplex) {
+               tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+       } else {
+               tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl);
+       }
+       tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl);
+
+       /* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */
+
+#ifndef NO_CHECK_CARRIER
+       /* TX4939 does not have EnLCarr */
+       if (lp->boardtype != TC35815_TX4939) {
+#ifdef WORKAROUND_LOSTCAR
+               /* WORKAROUND: enable LostCrS only if half duplex operation */
+               if (!lp->fullduplex && lp->boardtype != TC35815_TX4939)
+                       tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl);
+#endif
+       }
+#endif
+       lp->mii.full_duplex = lp->fullduplex;
+}
+
+static void tc35815_timer(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct tc35815_local *lp = dev->priv;
+       int pid = lp->phy_addr;
+       unsigned short bmsr, bmcr, lpa;
+       int restart_timer = 0;
+
+       spin_lock_irq(&lp->lock);
+
+       lp->timer_ticks++;
+       switch (lp->timer_state) {
+       case arbwait:
+               /*
+                * Only allow for 5 ticks, thats 10 seconds and much too
+                * long to wait for arbitration to complete.
+                */
+               /* TC35815 need more times... */
+               if (lp->timer_ticks >= 10) {
+                       /* Enter force mode. */
+                       if (!options.doforce) {
+                               printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+                                      " cable probblem?\n", dev->name);
+                               /* Try to restart the adaptor. */
+                               tc35815_restart(dev);
+                               goto out;
+                       }
+                       printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+                              " trying force link mode\n", dev->name);
+                       printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name,
+                              tc_mdio_read(dev, pid, MII_BMCR),
+                              tc_mdio_read(dev, pid, MII_BMSR));
+                       bmcr = BMCR_SPEED100;
+                       tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+                       /*
+                        * OK, seems we need do disable the transceiver
+                        * for the first tick to make sure we get an
+                        * accurate link state at the second tick.
+                        */
+
+                       lp->timer_state = ltrywait;
+                       lp->timer_ticks = 0;
+                       restart_timer = 1;
                } else {
-                       /* auto negotiation */
-                       unsigned long neg_result;
-                       tc_phy_write(dev, MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL);
-                       printk(KERN_INFO "%s: Auto Negotiation...", dev->name);
-                       count = 0;
-                       while (!(tc_phy_read(dev, tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) {
-                               if (count++ > 5000) {
-                                       printk(" failed. Assume 10Mbps\n");
-                                       lp->linkspeed = 10;
-                                       lp->fullduplex = 0;
-                                       goto done;
+                       /* Anything interesting happen? */
+                       bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+                       if (bmsr & BMSR_ANEGCOMPLETE) {
+                               /* Just what we've been waiting for... */
+                               tc35815_set_link_modes(dev);
+
+                               /*
+                                * Success, at least so far, advance our state
+                                * engine.
+                                */
+                               lp->timer_state = lupwait;
+                               restart_timer = 1;
+                       } else {
+                               restart_timer = 1;
+                       }
+               }
+               break;
+
+       case lupwait:
+               /*
+                * Auto negotiation was successful and we are awaiting a
+                * link up status.  I have decided to let this timer run
+                * forever until some sort of error is signalled, reporting
+                * a message to the user at 10 second intervals.
+                */
+               bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+               if (bmsr & BMSR_LSTATUS) {
+                       /*
+                        * Wheee, it's up, display the link mode in use and put
+                        * the timer to sleep.
+                        */
+                       tc35815_display_link_mode(dev);
+                       netif_carrier_on(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+                       /* delayed promiscuous enabling */
+                       if (dev->flags & IFF_PROMISC)
+                               tc35815_set_multicast_list(dev);
+#endif
+#if 1
+                       lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+                       lp->timer_state = lcheck;
+                       restart_timer = 1;
+#else
+                       lp->timer_state = asleep;
+                       restart_timer = 0;
+#endif
+               } else {
+                       if (lp->timer_ticks >= 10) {
+                               printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
+                                      "not completely up.\n", dev->name);
+                               lp->timer_ticks = 0;
+                               restart_timer = 1;
+                       } else {
+                               restart_timer = 1;
+                       }
+               }
+               break;
+
+       case ltrywait:
+               /*
+                * Making the timeout here too long can make it take
+                * annoyingly long to attempt all of the link mode
+                * permutations, but then again this is essentially
+                * error recovery code for the most part.
+                */
+               bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+               bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+               if (lp->timer_ticks == 1) {
+                       /*
+                        * Re-enable transceiver, we'll re-enable the
+                        * transceiver next tick, then check link state
+                        * on the following tick.
+                        */
+                       restart_timer = 1;
+                       break;
+               }
+               if (lp->timer_ticks == 2) {
+                       restart_timer = 1;
+                       break;
+               }
+               if (bmsr & BMSR_LSTATUS) {
+                       /* Force mode selection success. */
+                       tc35815_display_forced_link_mode(dev);
+                       netif_carrier_on(dev);
+                       tc35815_set_link_modes(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+                       /* delayed promiscuous enabling */
+                       if (dev->flags & IFF_PROMISC)
+                               tc35815_set_multicast_list(dev);
+#endif
+#if 1
+                       lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+                       lp->timer_state = lcheck;
+                       restart_timer = 1;
+#else
+                       lp->timer_state = asleep;
+                       restart_timer = 0;
+#endif
+               } else {
+                       if (lp->timer_ticks >= 4) { /* 6 seconds or so... */
+                               int ret;
+
+                               ret = tc35815_try_next_permutation(dev);
+                               if (ret == -1) {
+                                       /*
+                                        * Aieee, tried them all, reset the
+                                        * chip and try all over again.
+                                        */
+                                       printk(KERN_NOTICE "%s: Link down, "
+                                              "cable problem?\n",
+                                              dev->name);
+
+                                       /* Try to restart the adaptor. */
+                                       tc35815_restart(dev);
+                                       goto out;
                                }
-                               if (count % 512 == 0)
-                                       printk(".");
-                               mdelay(1);
+                               lp->timer_ticks = 0;
+                               restart_timer = 1;
+                       } else {
+                               restart_timer = 1;
                        }
-                       printk(" done.\n");
-                       neg_result = tc_phy_read(dev, tr, 0, MII_ANLPAR);
-                       if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX))
-                               lp->linkspeed = 100;
+               }
+               break;
+
+       case lcheck:
+               bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+               lpa = tc_mdio_read(dev, pid, MII_LPA);
+               if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) {
+                       printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name,
+                              bmcr);
+               } else if ((lp->saved_lpa ^ lpa) &
+                          (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) {
+                       printk(KERN_NOTICE "%s: link status changed"
+                              " (BMCR %x LPA %x->%x)\n", dev->name,
+                              bmcr, lp->saved_lpa, lpa);
+               } else {
+                       /* go on */
+                       restart_timer = 1;
+                       break;
+               }
+               /* Try to restart the adaptor. */
+               tc35815_restart(dev);
+               goto out;
+
+       case asleep:
+       default:
+               /* Can't happens.... */
+               printk(KERN_ERR "%s: Aieee, link timer is asleep but we got "
+                      "one anyways!\n", dev->name);
+               restart_timer = 0;
+               lp->timer_ticks = 0;
+               lp->timer_state = asleep; /* foo on you */
+               break;
+       }
+
+       if (restart_timer) {
+               lp->timer.expires = jiffies + msecs_to_jiffies(1200);
+               add_timer(&lp->timer);
+       }
+out:
+       spin_unlock_irq(&lp->lock);
+}
+
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+                                          struct ethtool_cmd *ep)
+{
+       struct tc35815_local *lp = dev->priv;
+       int pid = lp->phy_addr;
+       unsigned short bmsr, bmcr, advertize;
+       int timeout;
+
+       netif_carrier_off(dev);
+       bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+       bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+       advertize = tc_mdio_read(dev, pid, MII_ADVERTISE);
+
+       if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+               if (options.speed || options.duplex) {
+                       /* Advertise only specified configuration. */
+                       advertize &= ~(ADVERTISE_10HALF |
+                                      ADVERTISE_10FULL |
+                                      ADVERTISE_100HALF |
+                                      ADVERTISE_100FULL);
+                       if (options.speed != 10) {
+                               if (options.duplex != 1)
+                                       advertize |= ADVERTISE_100FULL;
+                               if (options.duplex != 2)
+                                       advertize |= ADVERTISE_100HALF;
+                       }
+                       if (options.speed != 100) {
+                               if (options.duplex != 1)
+                                       advertize |= ADVERTISE_10FULL;
+                               if (options.duplex != 2)
+                                       advertize |= ADVERTISE_10HALF;
+                       }
+                       if (options.speed == 100)
+                               bmcr |= BMCR_SPEED100;
+                       else if (options.speed == 10)
+                               bmcr &= ~BMCR_SPEED100;
+                       if (options.duplex == 2)
+                               bmcr |= BMCR_FULLDPLX;
+                       else if (options.duplex == 1)
+                               bmcr &= ~BMCR_FULLDPLX;
+               } else {
+                       /* Advertise everything we can support. */
+                       if (bmsr & BMSR_10HALF)
+                               advertize |= ADVERTISE_10HALF;
                        else
-                               lp->linkspeed = 10;
-                       if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX))
-                               lp->fullduplex = 1;
+                               advertize &= ~ADVERTISE_10HALF;
+                       if (bmsr & BMSR_10FULL)
+                               advertize |= ADVERTISE_10FULL;
                        else
-                               lp->fullduplex = 0;
-               done:
-                       ;
+                               advertize &= ~ADVERTISE_10FULL;
+                       if (bmsr & BMSR_100HALF)
+                               advertize |= ADVERTISE_100HALF;
+                       else
+                               advertize &= ~ADVERTISE_100HALF;
+                       if (bmsr & BMSR_100FULL)
+                               advertize |= ADVERTISE_100FULL;
+                       else
+                               advertize &= ~ADVERTISE_100FULL;
+               }
+
+               tc_mdio_write(dev, pid, MII_ADVERTISE, advertize);
+
+               /* Enable Auto-Negotiation, this is usually on already... */
+               bmcr |= BMCR_ANENABLE;
+               tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+               /* Restart it to make sure it is going. */
+               bmcr |= BMCR_ANRESTART;
+               tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+               printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr);
+
+               /* BMCR_ANRESTART self clears when the process has begun. */
+               timeout = 64;  /* More than enough. */
+               while (--timeout) {
+                       bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+                       if (!(bmcr & BMCR_ANRESTART))
+                               break; /* got it. */
+                       udelay(10);
+               }
+               if (!timeout) {
+                       printk(KERN_ERR "%s: TC35815 would not start auto "
+                              "negotiation BMCR=0x%04x\n",
+                              dev->name, bmcr);
+                       printk(KERN_NOTICE "%s: Performing force link "
+                              "detection.\n", dev->name);
+                       goto force_link;
+               } else {
+                       printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name);
+                       lp->timer_state = arbwait;
                }
+       } else {
+force_link:
+               /* Force the link up, trying first a particular mode.
+                * Either we are here at the request of ethtool or
+                * because the Happy Meal would not start to autoneg.
+                */
+
+               /* Disable auto-negotiation in BMCR, enable the duplex and
+                * speed setting, init the timer state machine, and fire it off.
+                */
+               if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+                       bmcr = BMCR_SPEED100;
+               } else {
+                       if (ep->speed == SPEED_100)
+                               bmcr = BMCR_SPEED100;
+                       else
+                               bmcr = 0;
+                       if (ep->duplex == DUPLEX_FULL)
+                               bmcr |= BMCR_FULLDPLX;
+               }
+               tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+               /* OK, seems we need do disable the transceiver for the first
+                * tick to make sure we get an accurate link state at the
+                * second tick.
+                */
+               lp->timer_state = ltrywait;
        }
 
-       ctl = 0;
-       if (lp->linkspeed == 100)
-               ctl |= MIICNTL_SPEED;
-       if (lp->fullduplex)
-               ctl |= MIICNTL_FDX;
-       tc_phy_write(dev, ctl, tr, 0, MII_CONTROL);
+       del_timer(&lp->timer);
+       lp->timer_ticks = 0;
+       lp->timer.expires = jiffies + msecs_to_jiffies(1200);
+       add_timer(&lp->timer);
+}
 
-       if (lp->fullduplex) {
-               tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+static void tc35815_find_phy(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       int pid = lp->phy_addr;
+       unsigned short id0;
+
+       /* find MII phy */
+       for (pid = 31; pid >= 0; pid--) {
+               id0 = tc_mdio_read(dev, pid, MII_BMSR);
+               if (id0 != 0xffff && id0 != 0x0000 &&
+                   (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */
+                       ) {
+                       lp->phy_addr = pid;
+                       break;
+               }
+       }
+       if (pid < 0) {
+               printk(KERN_ERR "%s: No MII Phy found.\n",
+                      dev->name);
+               lp->phy_addr = pid = 0;
        }
+
+       lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1);
+       lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2);
+       if (netif_msg_hw(lp))
+               printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name,
+                      pid, lp->mii_id[0], lp->mii_id[1]);
 }
 
-static void tc35815_chip_reset(struct net_device *dev)
+static void tc35815_phy_chip_init(struct net_device *dev)
 {
-       struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+       struct tc35815_local *lp = dev->priv;
+       int pid = lp->phy_addr;
+       unsigned short bmcr;
+       struct ethtool_cmd ecmd, *ep;
+
+       /* dis-isolate if needed. */
+       bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+       if (bmcr & BMCR_ISOLATE) {
+               int count = 32;
+               printk(KERN_DEBUG "%s: unisolating...", dev->name);
+               tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE);
+               while (--count) {
+                       if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE))
+                               break;
+                       udelay(20);
+               }
+               printk(" %s.\n", count ? "done" : "failed");
+       }
 
+       if (options.speed && options.duplex) {
+               ecmd.autoneg = AUTONEG_DISABLE;
+               ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100;
+               ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL;
+               ep = &ecmd;
+       } else {
+               ep = NULL;
+       }
+       tc35815_start_auto_negotiation(dev, ep);
+}
+
+static void tc35815_chip_reset(struct net_device *dev)
+{
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       int i;
        /* reset the controller */
        tc_writel(MAC_Reset, &tr->MAC_Ctl);
-       while (tc_readl(&tr->MAC_Ctl) & MAC_Reset)
-               ;
-
+       udelay(4); /* 3200ns */
+       i = 0;
+       while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
+               if (i++ > 100) {
+                       printk(KERN_ERR "%s: MAC reset failed.\n", dev->name);
+                       break;
+               }
+               mdelay(1);
+       }
        tc_writel(0, &tr->MAC_Ctl);
 
        /* initialize registers to default value */
@@ -1650,90 +2804,142 @@ static void tc35815_chip_reset(struct net_device *dev)
        tc_writel(0, &tr->CAM_Ena);
        (void)tc_readl(&tr->Miss_Cnt);  /* Read to clear */
 
+       /* initialize internal SRAM */
+       tc_writel(DMA_TestMode, &tr->DMA_Ctl);
+       for (i = 0; i < 0x1000; i += 4) {
+               tc_writel(i, &tr->CAM_Adr);
+               tc_writel(0, &tr->CAM_Data);
+       }
+       tc_writel(0, &tr->DMA_Ctl);
 }
 
 static void tc35815_chip_init(struct net_device *dev)
 {
        struct tc35815_local *lp = dev->priv;
-       struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-       unsigned long flags;
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
        unsigned long txctl = TX_CTL_CMD;
 
        tc35815_phy_chip_init(dev);
 
        /* load station address to CAM */
-       tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr);
+       tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr);
 
        /* Enable CAM (broadcast and unicast) */
        tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
        tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
 
-       spin_lock_irqsave(&lp->lock, flags);
-
-       tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
-
+       /* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */
+       if (HAVE_DMA_RXALIGN(lp))
+               tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl);
+       else
+               tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
+#ifdef TC35815_USE_PACKEDBUFFER
        tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize);   /* Packing */
+#else
+       tc_writel(ETH_ZLEN, &tr->RxFragSize);
+#endif
        tc_writel(0, &tr->TxPollCtr);   /* Batch mode */
        tc_writel(TX_THRESHOLD, &tr->TxThrsh);
        tc_writel(INT_EN_CMD, &tr->Int_En);
 
        /* set queues */
-       tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas);
+       tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas);
        tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
                  &tr->FDA_Lim);
        /*
         * Activation method:
-        * First, enable eht MAC Transmitter and the DMA Receive circuits.
+        * First, enable the MAC Transmitter and the DMA Receive circuits.
         * Then enable the DMA Transmitter and the MAC Receive circuits.
         */
-       tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr);     /* start DMA receiver */
+       tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr);      /* start DMA receiver */
        tc_writel(RX_CTL_CMD, &tr->Rx_Ctl);     /* start MAC receiver */
+
        /* start MAC transmitter */
+#ifndef NO_CHECK_CARRIER
+       /* TX4939 does not have EnLCarr */
+       if (lp->boardtype == TC35815_TX4939)
+               txctl &= ~Tx_EnLCarr;
+#ifdef WORKAROUND_LOSTCAR
        /* WORKAROUND: ignore LostCrS in full duplex operation */
-       if (lp->fullduplex)
-               txctl = TX_CTL_CMD & ~Tx_EnLCarr;
+       if ((lp->timer_state != asleep && lp->timer_state != lcheck) ||
+           lp->fullduplex)
+               txctl &= ~Tx_EnLCarr;
+#endif
+#endif /* !NO_CHECK_CARRIER */
 #ifdef GATHER_TXINT
        txctl &= ~Tx_EnComp;    /* disable global tx completion int. */
 #endif
        tc_writel(txctl, &tr->Tx_Ctl);
-#if 0  /* No need to polling */
-       tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr);    /* start DMA transmitter */
-#endif
+}
+
+#ifdef CONFIG_PM
+static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct tc35815_local *lp = dev->priv;
+       unsigned long flags;
+
+       pci_save_state(pdev);
+       if (!netif_running(dev))
+               return 0;
+       netif_device_detach(dev);
+       spin_lock_irqsave(&lp->lock, flags);
+       del_timer(&lp->timer);          /* Kill if running      */
+       tc35815_chip_reset(dev);
        spin_unlock_irqrestore(&lp->lock, flags);
+       pci_set_power_state(pdev, PCI_D3hot);
+       return 0;
 }
 
-static struct pci_driver tc35815_driver = {
-       .name = TC35815_MODULE_NAME,
-       .probe = tc35815_probe,
-       .remove = NULL,
-       .id_table = tc35815_pci_tbl,
+static int tc35815_resume(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct tc35815_local *lp = dev->priv;
+       unsigned long flags;
+
+       pci_restore_state(pdev);
+       if (!netif_running(dev))
+               return 0;
+       pci_set_power_state(pdev, PCI_D0);
+       spin_lock_irqsave(&lp->lock, flags);
+       tc35815_restart(dev);
+       spin_unlock_irqrestore(&lp->lock, flags);
+       netif_device_attach(dev);
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct pci_driver tc35815_pci_driver = {
+       .name           = MODNAME,
+       .id_table       = tc35815_pci_tbl,
+       .probe          = tc35815_init_one,
+       .remove         = __devexit_p(tc35815_remove_one),
+#ifdef CONFIG_PM
+       .suspend        = tc35815_suspend,
+       .resume         = tc35815_resume,
+#endif
 };
 
+module_param_named(speed, options.speed, int, 0);
+MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps");
+module_param_named(duplex, options.duplex, int, 0);
+MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full");
+module_param_named(doforce, options.doforce, int, 0);
+MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed");
+
 static int __init tc35815_init_module(void)
 {
-       return pci_register_driver(&tc35815_driver);
+       return pci_register_driver(&tc35815_pci_driver);
 }
 
 static void __exit tc35815_cleanup_module(void)
 {
-       struct net_device *next_dev;
-
-       /*
-        * TODO: implement a tc35815_driver.remove hook, and
-        * move this code into that function.  Then, delete
-        * all root_tc35815_dev list handling code.
-        */
-       while (root_tc35815_dev) {
-               struct net_device *dev = root_tc35815_dev;
-               next_dev = ((struct tc35815_local *)dev->priv)->next_module;
-               iounmap((void *)(dev->base_addr));
-               unregister_netdev(dev);
-               free_netdev(dev);
-               root_tc35815_dev = next_dev;
-       }
-
-       pci_unregister_driver(&tc35815_driver);
+       pci_unregister_driver(&tc35815_pci_driver);
 }
 
 module_init(tc35815_init_module);
 module_exit(tc35815_cleanup_module);
+
+MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver");
+MODULE_LICENSE("GPL");
index b3a64ca9863447d9dffbad5c39383d7c9676d123..4ed67ff0e81ef9b8329ba922e9015e0f582645e3 100644 (file)
@@ -55,9 +55,6 @@
 
     TODO
 
-    Implement pci_driver::suspend() and pci_driver::resume()
-    power management methods.
-
     Check on 64 bit boxes.
     Check and fix on big endian boxes.
 
 #define DM9801_NOISE_FLOOR 8
 #define DM9802_NOISE_FLOOR 5
 
+#define DMFE_WOL_LINKCHANGE    0x20000000
+#define DMFE_WOL_SAMPLEPACKET  0x10000000
+#define DMFE_WOL_MAGICPACKET   0x08000000
+
+
 #define DMFE_10MHF      0
 #define DMFE_100MHF     1
 #define DMFE_10MFD      4
@@ -251,6 +253,7 @@ struct dmfe_board_info {
        u8 wait_reset;                  /* Hardware failed, need to reset */
        u8 dm910x_chk_mode;             /* Operating mode check */
        u8 first_in_callback;           /* Flag to record state */
+       u8 wol_mode;                    /* user WOL settings */
        struct timer_list timer;
 
        /* System defined statistic counter */
@@ -431,6 +434,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
        db->chip_id = ent->driver_data;
        db->ioaddr = pci_resource_start(pdev, 0);
        db->chip_revision = dev_rev;
+       db->wol_mode = 0;
 
        db->pdev = pdev;
 
@@ -1065,7 +1069,11 @@ static void dmfe_set_filter_mode(struct DEVICE * dev)
        spin_unlock_irqrestore(&db->lock, flags);
 }
 
-static void netdev_get_drvinfo(struct net_device *dev,
+/*
+ *     Ethtool interace
+ */
+
+static void dmfe_ethtool_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
        struct dmfe_board_info *np = netdev_priv(dev);
@@ -1079,9 +1087,35 @@ static void netdev_get_drvinfo(struct net_device *dev,
                        dev->base_addr, dev->irq);
 }
 
+static int dmfe_ethtool_set_wol(struct net_device *dev,
+                               struct ethtool_wolinfo *wolinfo)
+{
+       struct dmfe_board_info *db = netdev_priv(dev);
+
+       if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST |
+                               WAKE_ARP | WAKE_MAGICSECURE))
+                  return -EOPNOTSUPP;
+
+       db->wol_mode = wolinfo->wolopts;
+       return 0;
+}
+
+static void dmfe_ethtool_get_wol(struct net_device *dev,
+                                struct ethtool_wolinfo *wolinfo)
+{
+       struct dmfe_board_info *db = netdev_priv(dev);
+
+       wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
+       wolinfo->wolopts = db->wol_mode;
+       return;
+}
+
+
 static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
+       .get_drvinfo            = dmfe_ethtool_get_drvinfo,
        .get_link               = ethtool_op_get_link,
+       .set_wol                = dmfe_ethtool_set_wol,
+       .get_wol                = dmfe_ethtool_get_wol,
 };
 
 /*
@@ -2050,11 +2084,85 @@ static struct pci_device_id dmfe_pci_tbl[] = {
 MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
 
 
+#ifdef CONFIG_PM
+static int dmfe_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pci_dev);
+       struct dmfe_board_info *db = netdev_priv(dev);
+       u32 tmp;
+
+       /* Disable upper layer interface */
+       netif_device_detach(dev);
+
+       /* Disable Tx/Rx */
+       db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);
+       update_cr6(db->cr6_data, dev->base_addr);
+
+       /* Disable Interrupt */
+       outl(0, dev->base_addr + DCR7);
+       outl(inl (dev->base_addr + DCR5), dev->base_addr + DCR5);
+
+       /* Fre RX buffers */
+       dmfe_free_rxbuffer(db);
+
+       /* Enable WOL */
+       pci_read_config_dword(pci_dev, 0x40, &tmp);
+       tmp &= ~(DMFE_WOL_LINKCHANGE|DMFE_WOL_MAGICPACKET);
+
+       if (db->wol_mode & WAKE_PHY)
+               tmp |= DMFE_WOL_LINKCHANGE;
+       if (db->wol_mode & WAKE_MAGIC)
+               tmp |= DMFE_WOL_MAGICPACKET;
+
+       pci_write_config_dword(pci_dev, 0x40, tmp);
+
+       pci_enable_wake(pci_dev, PCI_D3hot, 1);
+       pci_enable_wake(pci_dev, PCI_D3cold, 1);
+
+       /* Power down device*/
+       pci_set_power_state(pci_dev, pci_choose_state (pci_dev,state));
+       pci_save_state(pci_dev);
+
+       return 0;
+}
+
+static int dmfe_resume(struct pci_dev *pci_dev)
+{
+       struct net_device *dev = pci_get_drvdata(pci_dev);
+       u32 tmp;
+
+       pci_restore_state(pci_dev);
+       pci_set_power_state(pci_dev, PCI_D0);
+
+       /* Re-initilize DM910X board */
+       dmfe_init_dm910x(dev);
+
+       /* Disable WOL */
+       pci_read_config_dword(pci_dev, 0x40, &tmp);
+
+       tmp &= ~(DMFE_WOL_LINKCHANGE | DMFE_WOL_MAGICPACKET);
+       pci_write_config_dword(pci_dev, 0x40, tmp);
+
+       pci_enable_wake(pci_dev, PCI_D3hot, 0);
+       pci_enable_wake(pci_dev, PCI_D3cold, 0);
+
+       /* Restart upper layer interface */
+       netif_device_attach(dev);
+
+       return 0;
+}
+#else
+#define dmfe_suspend NULL
+#define dmfe_resume NULL
+#endif
+
 static struct pci_driver dmfe_driver = {
        .name           = "dmfe",
        .id_table       = dmfe_pci_tbl,
        .probe          = dmfe_init_one,
        .remove         = __devexit_p(dmfe_remove_one),
+       .suspend        = dmfe_suspend,
+       .resume         = dmfe_resume
 };
 
 MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
index e86df07769a1efce7d7790987732fc5578163757..9b08afbd1f65e245648c4e7f3fc84531e9b7069e 100644 (file)
@@ -673,7 +673,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
                                if (tp->link_change)
                                        (tp->link_change)(dev, csr5);
                        }
-                       if (csr5 & SytemError) {
+                       if (csr5 & SystemError) {
                                int error = (csr5 >> 23) & 7;
                                /* oops, we hit a PCI error.  The code produced corresponds
                                 * to the reason:
@@ -743,7 +743,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
                          TxFIFOUnderflow |
                          TxJabber |
                          TPLnkFail |
-                         SytemError )) != 0);
+                         SystemError )) != 0);
 #else
        } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0);
 
index 20bd52b869937e5691e3118d210fcd3ae9c1418e..b56256636543f0685f38ab0cd30023335194367b 100644 (file)
@@ -44,8 +44,10 @@ static const unsigned char comet_miireg2offset[32] = {
 
 /* MII transceiver control section.
    Read and write the MII registers using software-generated serial
-   MDIO protocol.  See the MII specifications or DP83840A data sheet
-   for details. */
+   MDIO protocol.
+   See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions")
+   or DP83840A data sheet for more details.
+   */
 
 int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
 {
@@ -261,24 +263,56 @@ void tulip_select_media(struct net_device *dev, int startup)
                                u16 *reset_sequence = &((u16*)(p+3))[init_length];
                                int reset_length = p[2 + init_length*2];
                                misc_info = reset_sequence + reset_length;
-                               if (startup)
+                               if (startup) {
+                                       int timeout = 10;       /* max 1 ms */
                                        for (i = 0; i < reset_length; i++)
                                                iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+
+                                       /* flush posted writes */
+                                       ioread32(ioaddr + CSR15);
+
+                                       /* Sect 3.10.3 in DP83840A.pdf (p39) */
+                                       udelay(500);
+
+                                       /* Section 4.2 in DP83840A.pdf (p43) */
+                                       /* and IEEE 802.3 "22.2.4.1.1 Reset" */
+                                       while (timeout-- &&
+                                               (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
+                                               udelay(100);
+                               }
                                for (i = 0; i < init_length; i++)
                                        iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+
+                               ioread32(ioaddr + CSR15);       /* flush posted writes */
                        } else {
                                u8 *init_sequence = p + 2;
                                u8 *reset_sequence = p + 3 + init_length;
                                int reset_length = p[2 + init_length];
                                misc_info = (u16*)(reset_sequence + reset_length);
                                if (startup) {
+                                       int timeout = 10;       /* max 1 ms */
                                        iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
                                        for (i = 0; i < reset_length; i++)
                                                iowrite32(reset_sequence[i], ioaddr + CSR12);
+
+                                       /* flush posted writes */
+                                       ioread32(ioaddr + CSR12);
+
+                                       /* Sect 3.10.3 in DP83840A.pdf (p39) */
+                                       udelay(500);
+
+                                       /* Section 4.2 in DP83840A.pdf (p43) */
+                                       /* and IEEE 802.3 "22.2.4.1.1 Reset" */
+                                       while (timeout-- &&
+                                               (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
+                                               udelay(100);
                                }
                                for (i = 0; i < init_length; i++)
                                        iowrite32(init_sequence[i], ioaddr + CSR12);
+
+                               ioread32(ioaddr + CSR12);       /* flush posted writes */
                        }
+
                        tmp_info = get_u16(&misc_info[1]);
                        if (tmp_info)
                                tp->advertising[phy_num] = tmp_info | 1;
index 25f25da7691714f881073404dc71e8500b8fc758..c840d2e67b23d25d302f744abaa1b7eedd8406b8 100644 (file)
@@ -132,7 +132,7 @@ enum pci_cfg_driver_reg {
 /* The bits in the CSR5 status registers, mostly interrupt sources. */
 enum status_bits {
        TimerInt = 0x800,
-       SytemError = 0x2000,
+       SystemError = 0x2000,
        TPLnkFail = 0x1000,
        TPLnkPass = 0x10,
        NormalIntr = 0x10000,
@@ -482,8 +482,11 @@ static inline void tulip_stop_rxtx(struct tulip_private *tp)
                        udelay(10);
 
                if (!i)
-                       printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed\n",
-                                       pci_name(tp->pdev));
+                       printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed"
+                                       " (CSR5 0x%x CSR6 0x%x)\n",
+                                       pci_name(tp->pdev),
+                                       ioread32(ioaddr + CSR5),
+                                       ioread32(ioaddr + CSR6));
        }
 }
 
index e9bf526ec53499ec2a0bbf0406fd19eb5f0c43a1..041af63f2811c4cb35ddf7f63a6dcea2c8b33412 100644 (file)
 
 #define DRV_NAME       "tulip"
 #ifdef CONFIG_TULIP_NAPI
-#define DRV_VERSION    "1.1.14-NAPI" /* Keep at least for test */
+#define DRV_VERSION    "1.1.15-NAPI" /* Keep at least for test */
 #else
-#define DRV_VERSION    "1.1.14"
+#define DRV_VERSION    "1.1.15"
 #endif
-#define DRV_RELDATE    "May 11, 2002"
+#define DRV_RELDATE    "Feb 27, 2007"
 
 
 #include <linux/module.h>
index 5b71ac78bca2e4f9f85183990318696e52cc8a42..fa440706fb4aa28f2d7b285439aa2f10a0853f36 100644 (file)
@@ -1147,7 +1147,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
                }
 
                /* Abnormal error summary/uncommon events handlers. */
-               if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SytemError |
+               if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SystemError |
                                                   TimerInt | TxDied))
                        netdev_error(dev, intr_status);
 
index 639e1e6913bfd573e560613bd0b060bb1146ed4c..16b9acdabbe8205af3d98f3c2b93ca25f0a133b6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/fsl_devices.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/phy.h>
 #include <linux/workqueue.h>
 
 #include <asm/of_platform.h>
 #include <asm/ucc_fast.h>
 
 #include "ucc_geth.h"
-#include "ucc_geth_phy.h"
+#include "ucc_geth_mii.h"
 
 #undef DEBUG
 
-#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:Sept 11, 2006"
+#define DRV_DESC "QE UCC Gigabit Ethernet Controller"
 #define DRV_NAME "ucc_geth"
+#define DRV_VERSION "1.1"
 
 #define ugeth_printk(level, format, arg...)  \
         printk(level format "\n", ## arg)
@@ -73,22 +75,13 @@ static struct ucc_geth_info ugeth_primary_info = {
                    .bd_mem_part = MEM_PART_SYSTEM,
                    .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES,
                    .max_rx_buf_length = 1536,
-/* FIXME: should be changed in run time for 1G and 100M */
-#ifdef CONFIG_UGETH_HAS_GIGA
-                   .urfs = UCC_GETH_URFS_GIGA_INIT,
-                   .urfet = UCC_GETH_URFET_GIGA_INIT,
-                   .urfset = UCC_GETH_URFSET_GIGA_INIT,
-                   .utfs = UCC_GETH_UTFS_GIGA_INIT,
-                   .utfet = UCC_GETH_UTFET_GIGA_INIT,
-                   .utftt = UCC_GETH_UTFTT_GIGA_INIT,
-#else
+                   /* adjusted at startup if max-speed 1000 */
                    .urfs = UCC_GETH_URFS_INIT,
                    .urfet = UCC_GETH_URFET_INIT,
                    .urfset = UCC_GETH_URFSET_INIT,
                    .utfs = UCC_GETH_UTFS_INIT,
                    .utfet = UCC_GETH_UTFET_INIT,
                    .utftt = UCC_GETH_UTFTT_INIT,
-#endif
                    .ufpt = 256,
                    .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET,
                    .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL,
@@ -217,70 +210,6 @@ static struct list_head *dequeue(struct list_head *lh)
        }
 }
 
-static int get_interface_details(enum enet_interface enet_interface,
-                                enum enet_speed *speed,
-                                int *r10m,
-                                int *rmm,
-                                int *rpm,
-                                int *tbi, int *limited_to_full_duplex)
-{
-       /* Analyze enet_interface according to Interface Mode
-       Configuration table */
-       switch (enet_interface) {
-       case ENET_10_MII:
-               *speed = ENET_SPEED_10BT;
-               break;
-       case ENET_10_RMII:
-               *speed = ENET_SPEED_10BT;
-               *r10m = 1;
-               *rmm = 1;
-               break;
-       case ENET_10_RGMII:
-               *speed = ENET_SPEED_10BT;
-               *rpm = 1;
-               *r10m = 1;
-               *limited_to_full_duplex = 1;
-               break;
-       case ENET_100_MII:
-               *speed = ENET_SPEED_100BT;
-               break;
-       case ENET_100_RMII:
-               *speed = ENET_SPEED_100BT;
-               *rmm = 1;
-               break;
-       case ENET_100_RGMII:
-               *speed = ENET_SPEED_100BT;
-               *rpm = 1;
-               *limited_to_full_duplex = 1;
-               break;
-       case ENET_1000_GMII:
-               *speed = ENET_SPEED_1000BT;
-               *limited_to_full_duplex = 1;
-               break;
-       case ENET_1000_RGMII:
-               *speed = ENET_SPEED_1000BT;
-               *rpm = 1;
-               *limited_to_full_duplex = 1;
-               break;
-       case ENET_1000_TBI:
-               *speed = ENET_SPEED_1000BT;
-               *tbi = 1;
-               *limited_to_full_duplex = 1;
-               break;
-       case ENET_1000_RTBI:
-               *speed = ENET_SPEED_1000BT;
-               *rpm = 1;
-               *tbi = 1;
-               *limited_to_full_duplex = 1;
-               break;
-       default:
-               return -EINVAL;
-               break;
-       }
-
-       return 0;
-}
-
 static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd)
 {
        struct sk_buff *skb = NULL;
@@ -758,24 +687,6 @@ static void dump_regs(struct ucc_geth_private *ugeth)
        ugeth_info("hafdup     : addr - 0x%08x, val - 0x%08x",
                   (u32) & ugeth->ug_regs->hafdup,
                   in_be32(&ugeth->ug_regs->hafdup));
-       ugeth_info("miimcfg    : addr - 0x%08x, val - 0x%08x",
-                  (u32) & ugeth->ug_regs->miimng.miimcfg,
-                  in_be32(&ugeth->ug_regs->miimng.miimcfg));
-       ugeth_info("miimcom    : addr - 0x%08x, val - 0x%08x",
-                  (u32) & ugeth->ug_regs->miimng.miimcom,
-                  in_be32(&ugeth->ug_regs->miimng.miimcom));
-       ugeth_info("miimadd    : addr - 0x%08x, val - 0x%08x",
-                  (u32) & ugeth->ug_regs->miimng.miimadd,
-                  in_be32(&ugeth->ug_regs->miimng.miimadd));
-       ugeth_info("miimcon    : addr - 0x%08x, val - 0x%08x",
-                  (u32) & ugeth->ug_regs->miimng.miimcon,
-                  in_be32(&ugeth->ug_regs->miimng.miimcon));
-       ugeth_info("miimstat   : addr - 0x%08x, val - 0x%08x",
-                  (u32) & ugeth->ug_regs->miimng.miimstat,
-                  in_be32(&ugeth->ug_regs->miimng.miimstat));
-       ugeth_info("miimmind   : addr - 0x%08x, val - 0x%08x",
-                  (u32) & ugeth->ug_regs->miimng.miimind,
-                  in_be32(&ugeth->ug_regs->miimng.miimind));
        ugeth_info("ifctl      : addr - 0x%08x, val - 0x%08x",
                   (u32) & ugeth->ug_regs->ifctl,
                   in_be32(&ugeth->ug_regs->ifctl));
@@ -1425,27 +1336,6 @@ static int init_mac_station_addr_regs(u8 address_byte_0,
        return 0;
 }
 
-static int init_mac_duplex_mode(int full_duplex,
-                               int limited_to_full_duplex,
-                               volatile u32 *maccfg2_register)
-{
-       u32 value = 0;
-
-       /* some interfaces must work in full duplex mode */
-       if ((full_duplex == 0) && (limited_to_full_duplex == 1))
-               return -EINVAL;
-
-       value = in_be32(maccfg2_register);
-
-       if (full_duplex)
-               value |= MACCFG2_FDX;
-       else
-               value &= ~MACCFG2_FDX;
-
-       out_be32(maccfg2_register, value);
-       return 0;
-}
-
 static int init_check_frame_length_mode(int length_check,
                                        volatile u32 *maccfg2_register)
 {
@@ -1477,40 +1367,6 @@ static int init_preamble_length(u8 preamble_length,
        return 0;
 }
 
-static int init_mii_management_configuration(int reset_mgmt,
-                                            int preamble_supress,
-                                            volatile u32 *miimcfg_register,
-                                            volatile u32 *miimind_register)
-{
-       unsigned int timeout = PHY_INIT_TIMEOUT;
-       u32 value = 0;
-
-       value = in_be32(miimcfg_register);
-       if (reset_mgmt) {
-               value |= MIIMCFG_RESET_MANAGEMENT;
-               out_be32(miimcfg_register, value);
-       }
-
-       value = 0;
-
-       if (preamble_supress)
-               value |= MIIMCFG_NO_PREAMBLE;
-
-       value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT;
-       out_be32(miimcfg_register, value);
-
-       /* Wait until the bus is free */
-       while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--)
-               cpu_relax();
-
-       if (timeout <= 0) {
-               ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__);
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
 static int init_rx_parameters(int reject_broadcast,
                              int receive_short_frames,
                              int promiscuous, volatile u32 *upsmr_register)
@@ -1570,10 +1426,8 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
        struct ucc_geth_info *ug_info;
        struct ucc_geth *ug_regs;
        struct ucc_fast *uf_regs;
-       enum enet_speed speed;
-       int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm =
-           0, limited_to_full_duplex = 0;
-       u32 upsmr, maccfg2, utbipar, tbiBaseAddress;
+       int ret_val;
+       u32 upsmr, maccfg2, tbiBaseAddress;
        u16 value;
 
        ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -1582,24 +1436,13 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
        ug_regs = ugeth->ug_regs;
        uf_regs = ugeth->uccf->uf_regs;
 
-       /* Analyze enet_interface according to Interface Mode Configuration
-       table */
-       ret_val =
-           get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm,
-                                 &rpm, &tbi, &limited_to_full_duplex);
-       if (ret_val != 0) {
-               ugeth_err
-                 ("%s: half duplex not supported in requested configuration.",
-                    __FUNCTION__);
-               return ret_val;
-       }
-
        /*                    Set MACCFG2                    */
        maccfg2 = in_be32(&ug_regs->maccfg2);
        maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
-       if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT))
+       if ((ugeth->max_speed == SPEED_10) ||
+           (ugeth->max_speed == SPEED_100))
                maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
-       else if (speed == ENET_SPEED_1000BT)
+       else if (ugeth->max_speed == SPEED_1000)
                maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
        maccfg2 |= ug_info->padAndCrc;
        out_be32(&ug_regs->maccfg2, maccfg2);
@@ -1607,54 +1450,39 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
        /*                    Set UPSMR                      */
        upsmr = in_be32(&uf_regs->upsmr);
        upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM);
-       if (rpm)
+       if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+           (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+           (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+           (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
                upsmr |= UPSMR_RPM;
-       if (r10m)
-               upsmr |= UPSMR_R10M;
-       if (tbi)
+               switch (ugeth->max_speed) {
+               case SPEED_10:
+                       upsmr |= UPSMR_R10M;
+                       /* FALLTHROUGH */
+               case SPEED_100:
+                       if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI)
+                               upsmr |= UPSMR_RMM;
+               }
+       }
+       if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
+           (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
                upsmr |= UPSMR_TBIM;
-       if (rmm)
-               upsmr |= UPSMR_RMM;
+       }
        out_be32(&uf_regs->upsmr, upsmr);
 
-       /*                    Set UTBIPAR                    */
-       utbipar = in_be32(&ug_regs->utbipar);
-       utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK;
-       if (tbi)
-               utbipar |=
-                   (ug_info->phy_address +
-                    ugeth->ug_info->uf_info.
-                    ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
-       else
-               utbipar |=
-                   (0x10 +
-                    ugeth->ug_info->uf_info.
-                    ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
-       out_be32(&ug_regs->utbipar, utbipar);
-
        /* Disable autonegotiation in tbi mode, because by default it
        comes up in autonegotiation mode. */
        /* Note that this depends on proper setting in utbipar register. */
-       if (tbi) {
+       if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
+           (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
                tbiBaseAddress = in_be32(&ug_regs->utbipar);
                tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK;
                tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT;
-               value =
-                   ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress,
-                                              ENET_TBI_MII_CR);
+               value = ugeth->phydev->bus->read(ugeth->phydev->bus,
+                               (u8) tbiBaseAddress, ENET_TBI_MII_CR);
                value &= ~0x1000;       /* Turn off autonegotiation */
-               ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress,
-                                           ENET_TBI_MII_CR, value);
-       }
-
-       ret_val = init_mac_duplex_mode(1,
-                                      limited_to_full_duplex,
-                                      &ug_regs->maccfg2);
-       if (ret_val != 0) {
-               ugeth_err
-               ("%s: half duplex not supported in requested configuration.",
-                    __FUNCTION__);
-               return ret_val;
+               ugeth->phydev->bus->write(ugeth->phydev->bus,
+                               (u8) tbiBaseAddress, ENET_TBI_MII_CR, value);
        }
 
        init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2);
@@ -1676,76 +1504,88 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
  * function converts those variables into the appropriate
  * register values, and can bring down the device if needed.
  */
+
 static void adjust_link(struct net_device *dev)
 {
        struct ucc_geth_private *ugeth = netdev_priv(dev);
        struct ucc_geth *ug_regs;
-       u32 tempval;
-       struct ugeth_mii_info *mii_info = ugeth->mii_info;
+       struct ucc_fast *uf_regs;
+       struct phy_device *phydev = ugeth->phydev;
+       unsigned long flags;
+       int new_state = 0;
 
        ug_regs = ugeth->ug_regs;
+       uf_regs = ugeth->uccf->uf_regs;
 
-       if (mii_info->link) {
+       spin_lock_irqsave(&ugeth->lock, flags);
+
+       if (phydev->link) {
+               u32 tempval = in_be32(&ug_regs->maccfg2);
+               u32 upsmr = in_be32(&uf_regs->upsmr);
                /* Now we make sure that we can be in full duplex mode.
                 * If not, we operate in half-duplex mode. */
-               if (mii_info->duplex != ugeth->oldduplex) {
-                       if (!(mii_info->duplex)) {
-                               tempval = in_be32(&ug_regs->maccfg2);
+               if (phydev->duplex != ugeth->oldduplex) {
+                       new_state = 1;
+                       if (!(phydev->duplex))
                                tempval &= ~(MACCFG2_FDX);
-                               out_be32(&ug_regs->maccfg2, tempval);
-
-                               ugeth_info("%s: Half Duplex", dev->name);
-                       } else {
-                               tempval = in_be32(&ug_regs->maccfg2);
+                       else
                                tempval |= MACCFG2_FDX;
-                               out_be32(&ug_regs->maccfg2, tempval);
-
-                               ugeth_info("%s: Full Duplex", dev->name);
-                       }
-
-                       ugeth->oldduplex = mii_info->duplex;
+                       ugeth->oldduplex = phydev->duplex;
                }
 
-               if (mii_info->speed != ugeth->oldspeed) {
-                       switch (mii_info->speed) {
-                       case 1000:
-                               ugeth->ug_info->enet_interface = ENET_1000_RGMII;
+               if (phydev->speed != ugeth->oldspeed) {
+                       new_state = 1;
+                       switch (phydev->speed) {
+                       case SPEED_1000:
+                               tempval = ((tempval &
+                                           ~(MACCFG2_INTERFACE_MODE_MASK)) |
+                                           MACCFG2_INTERFACE_MODE_BYTE);
                                break;
-                       case 100:
-                               ugeth->ug_info->enet_interface = ENET_100_RGMII;
-                               break;
-                       case 10:
-                               ugeth->ug_info->enet_interface = ENET_10_RGMII;
+                       case SPEED_100:
+                       case SPEED_10:
+                               tempval = ((tempval &
+                                           ~(MACCFG2_INTERFACE_MODE_MASK)) |
+                                           MACCFG2_INTERFACE_MODE_NIBBLE);
+                               /* if reduced mode, re-set UPSMR.R10M */
+                               if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
+                                       if (phydev->speed == SPEED_10)
+                                               upsmr |= UPSMR_R10M;
+                                       else
+                                               upsmr &= ~(UPSMR_R10M);
+                               }
                                break;
                        default:
-                               ugeth_warn
-                                   ("%s: Ack!  Speed (%d) is not 10/100/1000!",
-                                    dev->name, mii_info->speed);
+                               if (netif_msg_link(ugeth))
+                                       ugeth_warn(
+                                               "%s: Ack!  Speed (%d) is not 10/100/1000!",
+                                               dev->name, phydev->speed);
                                break;
                        }
-                       adjust_enet_interface(ugeth);
-
-                       ugeth_info("%s: Speed %dBT", dev->name,
-                                  mii_info->speed);
-
-                       ugeth->oldspeed = mii_info->speed;
+                       ugeth->oldspeed = phydev->speed;
                }
 
+               out_be32(&ug_regs->maccfg2, tempval);
+               out_be32(&uf_regs->upsmr, upsmr);
+
                if (!ugeth->oldlink) {
-                       ugeth_info("%s: Link is up", dev->name);
+                       new_state = 1;
                        ugeth->oldlink = 1;
-                       netif_carrier_on(dev);
                        netif_schedule(dev);
                }
-       } else {
-               if (ugeth->oldlink) {
-                       ugeth_info("%s: Link is down", dev->name);
+       } else if (ugeth->oldlink) {
+                       new_state = 1;
                        ugeth->oldlink = 0;
                        ugeth->oldspeed = 0;
                        ugeth->oldduplex = -1;
-                       netif_carrier_off(dev);
-               }
        }
+
+       if (new_state && netif_msg_link(ugeth))
+               phy_print_status(phydev);
+
+       spin_unlock_irqrestore(&ugeth->lock, flags);
 }
 
 /* Configure the PHY for dev.
@@ -1753,102 +1593,40 @@ static void adjust_link(struct net_device *dev)
  */
 static int init_phy(struct net_device *dev)
 {
-       struct ucc_geth_private *ugeth = netdev_priv(dev);
-       struct phy_info *curphy;
-       struct ucc_mii_mng *mii_regs;
-       struct ugeth_mii_info *mii_info;
-       int err;
+       struct ucc_geth_private *priv = netdev_priv(dev);
+       struct phy_device *phydev;
+       char phy_id[BUS_ID_SIZE];
 
-       mii_regs = &ugeth->ug_regs->miimng;
+       priv->oldlink = 0;
+       priv->oldspeed = 0;
+       priv->oldduplex = -1;
 
-       ugeth->oldlink = 0;
-       ugeth->oldspeed = 0;
-       ugeth->oldduplex = -1;
+       snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus,
+                       priv->ug_info->phy_address);
 
-       mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL);
+       phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface);
 
-       if (NULL == mii_info) {
-               ugeth_err("%s: Could not allocate mii_info", dev->name);
-               return -ENOMEM;
+       if (IS_ERR(phydev)) {
+               printk("%s: Could not attach to PHY\n", dev->name);
+               return PTR_ERR(phydev);
        }
 
-       mii_info->mii_regs = mii_regs;
-       mii_info->speed = SPEED_1000;
-       mii_info->duplex = DUPLEX_FULL;
-       mii_info->pause = 0;
-       mii_info->link = 0;
-
-       mii_info->advertising = (ADVERTISED_10baseT_Half |
+       phydev->supported &= (ADVERTISED_10baseT_Half |
                                 ADVERTISED_10baseT_Full |
                                 ADVERTISED_100baseT_Half |
-                                ADVERTISED_100baseT_Full |
-                                ADVERTISED_1000baseT_Full);
-       mii_info->autoneg = 1;
+                                ADVERTISED_100baseT_Full);
 
-       mii_info->mii_id = ugeth->ug_info->phy_address;
+       if (priv->max_speed == SPEED_1000)
+               phydev->supported |= ADVERTISED_1000baseT_Full;
 
-       mii_info->dev = dev;
+       phydev->advertising = phydev->supported;
 
-       mii_info->mdio_read = &read_phy_reg;
-       mii_info->mdio_write = &write_phy_reg;
-
-       spin_lock_init(&mii_info->mdio_lock);
-
-       ugeth->mii_info = mii_info;
-
-       spin_lock_irq(&ugeth->lock);
-
-       /* Set this UCC to be the master of the MII managment */
-       ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
-
-       if (init_mii_management_configuration(1,
-                                             ugeth->ug_info->
-                                             miiPreambleSupress,
-                                             &mii_regs->miimcfg,
-                                             &mii_regs->miimind)) {
-               ugeth_err("%s: The MII Bus is stuck!", dev->name);
-               err = -1;
-               goto bus_fail;
-       }
-
-       spin_unlock_irq(&ugeth->lock);
-
-       /* get info for this PHY */
-       curphy = get_phy_info(ugeth->mii_info);
-
-       if (curphy == NULL) {
-               ugeth_err("%s: No PHY found", dev->name);
-               err = -1;
-               goto no_phy;
-       }
-
-       mii_info->phyinfo = curphy;
-
-       /* Run the commands which initialize the PHY */
-       if (curphy->init) {
-               err = curphy->init(ugeth->mii_info);
-               if (err)
-                       goto phy_init_fail;
-       }
+       priv->phydev = phydev;
 
        return 0;
-
-      phy_init_fail:
-      no_phy:
-      bus_fail:
-       kfree(mii_info);
-
-       return err;
 }
 
-#ifdef CONFIG_UGETH_TX_ON_DEMOND
-static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth)
-{
-       struct ucc_fastransmit_on_demand(ugeth->uccf);
 
-       return 0;
-}
-#endif
 
 static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
 {
@@ -2356,6 +2134,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
        }
        for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
                bd = ugeth->p_tx_bd_ring[i];
+               if (!bd)
+                       continue;
                for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
                        if (ugeth->tx_skbuff[i][j]) {
                                dma_unmap_single(NULL,
@@ -2487,6 +2267,7 @@ static void ucc_geth_set_multi(struct net_device *dev)
 static void ucc_geth_stop(struct ucc_geth_private *ugeth)
 {
        struct ucc_geth *ug_regs = ugeth->ug_regs;
+       struct phy_device *phydev = ugeth->phydev;
        u32 tempval;
 
        ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -2495,8 +2276,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
        ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
 
        /* Tell the kernel the link is down */
-       ugeth->mii_info->link = 0;
-       adjust_link(ugeth->dev);
+       phy_stop(phydev);
 
        /* Mask all interrupts */
        out_be32(ugeth->uccf->p_ucce, 0x00000000);
@@ -2509,50 +2289,24 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
        tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
        out_be32(&ug_regs->maccfg1, tempval);
 
-       if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
-               /* Clear any pending interrupts */
-               mii_clear_phy_interrupt(ugeth->mii_info);
-
-               /* Disable PHY Interrupts */
-               mii_configure_phy_interrupt(ugeth->mii_info,
-                                           MII_INTERRUPT_DISABLED);
-       }
-
        free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
 
-       if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
-               free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev);
-       } else {
-               del_timer_sync(&ugeth->phy_info_timer);
-       }
-
        ucc_geth_memclean(ugeth);
 }
 
-static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+static int ucc_struct_init(struct ucc_geth_private *ugeth)
 {
-       struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
-       struct ucc_geth_init_pram *p_init_enet_pram;
-       struct ucc_fast_private *uccf;
        struct ucc_geth_info *ug_info;
        struct ucc_fast_info *uf_info;
-       struct ucc_fast *uf_regs;
-       struct ucc_geth *ug_regs;
-       int ret_val = -EINVAL;
-       u32 remoder = UCC_GETH_REMODER_INIT;
-       u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
-       u32 ifstat, i, j, size, l2qt, l3qt, length;
-       u16 temoder = UCC_GETH_TEMODER_INIT;
-       u16 test;
-       u8 function_code = 0;
-       u8 *bd, *endOfRing;
-       u8 numThreadsRxNumerical, numThreadsTxNumerical;
-
-       ugeth_vdbg("%s: IN", __FUNCTION__);
+       int i;
 
        ug_info = ugeth->ug_info;
        uf_info = &ug_info->uf_info;
 
+       /* Create CQs for hash tables */
+       INIT_LIST_HEAD(&ugeth->group_hash_q);
+       INIT_LIST_HEAD(&ugeth->ind_hash_q);
+
        if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) ||
              (uf_info->bd_mem_part == MEM_PART_MURAM))) {
                ugeth_err("%s: Bad memory partition value.", __FUNCTION__);
@@ -2647,12 +2401,42 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
        for (i = 0; i < ug_info->numQueuesTx; i++)
                uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i);
        /* Initialize the general fast UCC block. */
-       if (ucc_fast_init(uf_info, &uccf)) {
+       if (ucc_fast_init(uf_info, &ugeth->uccf)) {
                ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
                ucc_geth_memclean(ugeth);
                return -ENOMEM;
        }
-       ugeth->uccf = uccf;
+
+       ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth));
+
+       return 0;
+}
+
+static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+{
+       struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+       struct ucc_geth_init_pram *p_init_enet_pram;
+       struct ucc_fast_private *uccf;
+       struct ucc_geth_info *ug_info;
+       struct ucc_fast_info *uf_info;
+       struct ucc_fast *uf_regs;
+       struct ucc_geth *ug_regs;
+       int ret_val = -EINVAL;
+       u32 remoder = UCC_GETH_REMODER_INIT;
+       u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
+       u32 ifstat, i, j, size, l2qt, l3qt, length;
+       u16 temoder = UCC_GETH_TEMODER_INIT;
+       u16 test;
+       u8 function_code = 0;
+       u8 *bd, *endOfRing;
+       u8 numThreadsRxNumerical, numThreadsTxNumerical;
+
+       ugeth_vdbg("%s: IN", __FUNCTION__);
+       uccf = ugeth->uccf;
+       ug_info = ugeth->ug_info;
+       uf_info = &ug_info->uf_info;
+       uf_regs = uccf->uf_regs;
+       ug_regs = ugeth->ug_regs;
 
        switch (ug_info->numThreadsRx) {
        case UCC_GETH_NUM_OF_THREADS_1:
@@ -2711,10 +2495,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
            || (ug_info->vlanOperationNonTagged !=
                UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP);
 
-       uf_regs = uccf->uf_regs;
-       ug_regs = (struct ucc_geth *) (uccf->uf_regs);
-       ugeth->ug_regs = ug_regs;
-
        init_default_reg_vals(&uf_regs->upsmr,
                              &ug_regs->maccfg1, &ug_regs->maccfg2);
 
@@ -3177,8 +2957,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
        /* Size varies with number of Rx queues */
        ugeth->rx_irq_coalescing_tbl_offset =
            qe_muram_alloc(ug_info->numQueuesRx *
-                          sizeof(struct ucc_geth_rx_interrupt_coalescing_entry),
-                          UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
+                          sizeof(struct ucc_geth_rx_interrupt_coalescing_entry)
+                          + 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
        if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) {
                ugeth_err
                    ("%s: Can not allocate DPRAM memory for"
@@ -3359,13 +3139,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                for (j = 0; j < NUM_OF_PADDRS; j++)
                        ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j);
 
-               /* Create CQs for hash tables */
-               if (ug_info->maxGroupAddrInHash > 0) {
-                       INIT_LIST_HEAD(&ugeth->group_hash_q);
-               }
-               if (ug_info->maxIndAddrInHash > 0) {
-                       INIT_LIST_HEAD(&ugeth->ind_hash_q);
-               }
                p_82xx_addr_filt =
                    (struct ucc_geth_82xx_address_filtering_pram *) ugeth->
                    p_rx_glbl_pram->addressfiltering;
@@ -3562,6 +3335,9 @@ static void ucc_geth_timeout(struct net_device *dev)
 static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ucc_geth_private *ugeth = netdev_priv(dev);
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+       struct ucc_fast_private *uccf;
+#endif
        u8 *bd;                 /* BD pointer */
        u32 bd_status;
        u8 txQ = 0;
@@ -3620,6 +3396,10 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
                out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]);
        }
 
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+       uccf = ugeth->uccf;
+       out_be16(uccf->p_utodr, UCC_FAST_TOD);
+#endif
        spin_unlock_irq(&ugeth->lock);
 
        return 0;
@@ -3635,7 +3415,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
 
        ugeth_vdbg("%s: IN", __FUNCTION__);
 
-       spin_lock(&ugeth->lock);
        /* collect received buffers */
        bd = ugeth->rxBd[rxQ];
 
@@ -3683,7 +3462,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
                skb = get_new_skb(ugeth, bd);
                if (!skb) {
                        ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
-                       spin_unlock(&ugeth->lock);
                        ugeth->stats.rx_dropped++;
                        break;
                }
@@ -3704,7 +3482,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
        }
 
        ugeth->rxBd[rxQ] = bd;
-       spin_unlock(&ugeth->lock);
        return howmany;
 }
 
@@ -3756,23 +3533,38 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
 static int ucc_geth_poll(struct net_device *dev, int *budget)
 {
        struct ucc_geth_private *ugeth = netdev_priv(dev);
+       struct ucc_geth_info *ug_info;
+       struct ucc_fast_private *uccf;
        int howmany;
-       int rx_work_limit = *budget;
-       u8 rxQ = 0;
+       u8 i;
+       int rx_work_limit;
+       register u32 uccm;
+
+       ug_info = ugeth->ug_info;
 
+       rx_work_limit = *budget;
        if (rx_work_limit > dev->quota)
                rx_work_limit = dev->quota;
 
-       howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit);
+       howmany = 0;
+
+       for (i = 0; i < ug_info->numQueuesRx; i++) {
+               howmany += ucc_geth_rx(ugeth, i, rx_work_limit);
+       }
 
        dev->quota -= howmany;
        rx_work_limit -= howmany;
        *budget -= howmany;
 
-       if (rx_work_limit >= 0)
+       if (rx_work_limit > 0) {
                netif_rx_complete(dev);
+               uccf = ugeth->uccf;
+               uccm = in_be32(uccf->p_uccm);
+               uccm |= UCCE_RX_EVENTS;
+               out_be32(uccf->p_uccm, uccm);
+       }
 
-       return (rx_work_limit < 0) ? 1 : 0;
+       return (rx_work_limit > 0) ? 0 : 1;
 }
 #endif                         /* CONFIG_UGETH_NAPI */
 
@@ -3782,10 +3574,13 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
        struct ucc_geth_private *ugeth = netdev_priv(dev);
        struct ucc_fast_private *uccf;
        struct ucc_geth_info *ug_info;
-       register u32 ucce = 0;
-       register u32 bit_mask = UCCE_RXBF_SINGLE_MASK;
-       register u32 tx_mask = UCCE_TXBF_SINGLE_MASK;
-       register u8 i;
+       register u32 ucce;
+       register u32 uccm;
+#ifndef CONFIG_UGETH_NAPI
+       register u32 rx_mask;
+#endif
+       register u32 tx_mask;
+       u8 i;
 
        ugeth_vdbg("%s: IN", __FUNCTION__);
 
@@ -3795,174 +3590,57 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
        uccf = ugeth->uccf;
        ug_info = ugeth->ug_info;
 
-       do {
-               ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm));
-
-               /* clear event bits for next time */
-               /* Side effect here is to mask ucce variable
-               for future processing below. */
-               out_be32(uccf->p_ucce, ucce);   /* Clear with ones,
-                                               but only bits in UCCM */
-
-               /* We ignore Tx interrupts because Tx confirmation is
-               done inside Tx routine */
+       /* read and clear events */
+       ucce = (u32) in_be32(uccf->p_ucce);
+       uccm = (u32) in_be32(uccf->p_uccm);
+       ucce &= uccm;
+       out_be32(uccf->p_ucce, ucce);
 
+       /* check for receive events that require processing */
+       if (ucce & UCCE_RX_EVENTS) {
+#ifdef CONFIG_UGETH_NAPI
+               if (netif_rx_schedule_prep(dev)) {
+               uccm &= ~UCCE_RX_EVENTS;
+                       out_be32(uccf->p_uccm, uccm);
+                       __netif_rx_schedule(dev);
+               }
+#else
+               rx_mask = UCCE_RXBF_SINGLE_MASK;
                for (i = 0; i < ug_info->numQueuesRx; i++) {
-                       if (ucce & bit_mask)
-                               ucc_geth_rx(ugeth, i,
-                                           (int)ugeth->ug_info->
-                                           bdRingLenRx[i]);
-                       ucce &= ~bit_mask;
-                       bit_mask <<= 1;
+                       if (ucce & rx_mask)
+                               ucc_geth_rx(ugeth, i, (int)ugeth->ug_info->bdRingLenRx[i]);
+                       ucce &= ~rx_mask;
+                       rx_mask <<= 1;
                }
+#endif /* CONFIG_UGETH_NAPI */
+       }
 
+       /* Tx event processing */
+       if (ucce & UCCE_TX_EVENTS) {
+               spin_lock(&ugeth->lock);
+               tx_mask = UCCE_TXBF_SINGLE_MASK;
                for (i = 0; i < ug_info->numQueuesTx; i++) {
                        if (ucce & tx_mask)
                                ucc_geth_tx(dev, i);
                        ucce &= ~tx_mask;
                        tx_mask <<= 1;
                }
+               spin_unlock(&ugeth->lock);
+       }
 
-               /* Exceptions */
+       /* Errors and other events */
+       if (ucce & UCCE_OTHER) {
                if (ucce & UCCE_BSY) {
-                       ugeth_vdbg("Got BUSY irq!!!!");
                        ugeth->stats.rx_errors++;
-                       ucce &= ~UCCE_BSY;
                }
-               if (ucce & UCCE_OTHER) {
-                       ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!",
-                                  ucce);
-                       ugeth->stats.rx_errors++;
-                       ucce &= ~ucce;
+               if (ucce & UCCE_TXE) {
+                       ugeth->stats.tx_errors++;
                }
        }
-       while (ucce);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t phy_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = (struct net_device *)dev_id;
-       struct ucc_geth_private *ugeth = netdev_priv(dev);
-
-       ugeth_vdbg("%s: IN", __FUNCTION__);
-
-       /* Clear the interrupt */
-       mii_clear_phy_interrupt(ugeth->mii_info);
-
-       /* Disable PHY interrupts */
-       mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED);
-
-       /* Schedule the phy change */
-       schedule_work(&ugeth->tq);
 
        return IRQ_HANDLED;
 }
 
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
-static void ugeth_phy_change(struct work_struct *work)
-{
-       struct ucc_geth_private *ugeth =
-               container_of(work, struct ucc_geth_private, tq);
-       struct net_device *dev = ugeth->dev;
-       struct ucc_geth *ug_regs;
-       int result = 0;
-
-       ugeth_vdbg("%s: IN", __FUNCTION__);
-
-       ug_regs = ugeth->ug_regs;
-
-       /* Delay to give the PHY a chance to change the
-        * register state */
-       msleep(1);
-
-       /* Update the link, speed, duplex */
-       result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info);
-
-       /* Adjust the known status as long as the link
-        * isn't still coming up */
-       if ((0 == result) || (ugeth->mii_info->link == 0))
-               adjust_link(dev);
-
-       /* Reenable interrupts, if needed */
-       if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR)
-               mii_configure_phy_interrupt(ugeth->mii_info,
-                                           MII_INTERRUPT_ENABLED);
-}
-
-/* Called every so often on systems that don't interrupt
- * the core for PHY changes */
-static void ugeth_phy_timer(unsigned long data)
-{
-       struct net_device *dev = (struct net_device *)data;
-       struct ucc_geth_private *ugeth = netdev_priv(dev);
-
-       schedule_work(&ugeth->tq);
-
-       mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
-/* Keep trying aneg for some time
- * If, after GFAR_AN_TIMEOUT seconds, it has not
- * finished, we switch to forced.
- * Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to
- * using ugeth_phy_timer to check status */
-static void ugeth_phy_startup_timer(unsigned long data)
-{
-       struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
-       struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev);
-       static int secondary = UGETH_AN_TIMEOUT;
-       int result;
-
-       /* Configure the Auto-negotiation */
-       result = mii_info->phyinfo->config_aneg(mii_info);
-
-       /* If autonegotiation failed to start, and
-        * we haven't timed out, reset the timer, and return */
-       if (result && secondary--) {
-               mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
-               return;
-       } else if (result) {
-               /* Couldn't start autonegotiation.
-                * Try switching to forced */
-               mii_info->autoneg = 0;
-               result = mii_info->phyinfo->config_aneg(mii_info);
-
-               /* Forcing failed!  Give up */
-               if (result) {
-                       ugeth_err("%s: Forcing failed!", mii_info->dev->name);
-                       return;
-               }
-       }
-
-       /* Kill the timer so it can be restarted */
-       del_timer_sync(&ugeth->phy_info_timer);
-
-       /* Grab the PHY interrupt, if necessary/possible */
-       if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
-               if (request_irq(ugeth->ug_info->phy_interrupt,
-                               phy_interrupt, IRQF_SHARED,
-                               "phy_interrupt", mii_info->dev) < 0) {
-                       ugeth_err("%s: Can't get IRQ %d (PHY)",
-                                 mii_info->dev->name,
-                                 ugeth->ug_info->phy_interrupt);
-               } else {
-                       mii_configure_phy_interrupt(ugeth->mii_info,
-                                                   MII_INTERRUPT_ENABLED);
-                       return;
-               }
-       }
-
-       /* Start the timer again, this time in order to
-        * handle a change in status */
-       init_timer(&ugeth->phy_info_timer);
-       ugeth->phy_info_timer.function = &ugeth_phy_timer;
-       ugeth->phy_info_timer.data = (unsigned long)mii_info->dev;
-       mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
 /* Called when something needs to use the ethernet device */
 /* Returns 0 for success. */
 static int ucc_geth_open(struct net_device *dev)
@@ -3979,6 +3657,12 @@ static int ucc_geth_open(struct net_device *dev)
                return -EINVAL;
        }
 
+       err = ucc_struct_init(ugeth);
+       if (err) {
+               ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
+               return err;
+       }
+
        err = ucc_geth_startup(ugeth);
        if (err) {
                ugeth_err("%s: Cannot configure net device, aborting.",
@@ -4006,10 +3690,12 @@ static int ucc_geth_open(struct net_device *dev)
 
        err = init_phy(dev);
        if (err) {
-               ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name);
+               ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
                return err;
        }
-#ifndef CONFIG_UGETH_NAPI
+
+       phy_start(ugeth->phydev);
+
        err =
            request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
                        "UCC Geth", dev);
@@ -4019,15 +3705,6 @@ static int ucc_geth_open(struct net_device *dev)
                ucc_geth_stop(ugeth);
                return err;
        }
-#endif                         /* CONFIG_UGETH_NAPI */
-
-       /* Set up the PHY change work queue */
-       INIT_WORK(&ugeth->tq, ugeth_phy_change);
-
-       init_timer(&ugeth->phy_info_timer);
-       ugeth->phy_info_timer.function = &ugeth_phy_startup_timer;
-       ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info;
-       mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
 
        err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
        if (err) {
@@ -4050,11 +3727,8 @@ static int ucc_geth_close(struct net_device *dev)
 
        ucc_geth_stop(ugeth);
 
-       /* Shutdown the PHY */
-       if (ugeth->mii_info->phyinfo->close)
-               ugeth->mii_info->phyinfo->close(ugeth->mii_info);
-
-       kfree(ugeth->mii_info);
+       phy_disconnect(ugeth->phydev);
+       ugeth->phydev = NULL;
 
        netif_stop_queue(dev);
 
@@ -4063,20 +3737,53 @@ static int ucc_geth_close(struct net_device *dev)
 
 const struct ethtool_ops ucc_geth_ethtool_ops = { };
 
+static phy_interface_t to_phy_interface(const char *interface_type)
+{
+       if (strcasecmp(interface_type, "mii") == 0)
+               return PHY_INTERFACE_MODE_MII;
+       if (strcasecmp(interface_type, "gmii") == 0)
+               return PHY_INTERFACE_MODE_GMII;
+       if (strcasecmp(interface_type, "tbi") == 0)
+               return PHY_INTERFACE_MODE_TBI;
+       if (strcasecmp(interface_type, "rmii") == 0)
+               return PHY_INTERFACE_MODE_RMII;
+       if (strcasecmp(interface_type, "rgmii") == 0)
+               return PHY_INTERFACE_MODE_RGMII;
+       if (strcasecmp(interface_type, "rgmii-id") == 0)
+               return PHY_INTERFACE_MODE_RGMII_ID;
+       if (strcasecmp(interface_type, "rtbi") == 0)
+               return PHY_INTERFACE_MODE_RTBI;
+
+       return PHY_INTERFACE_MODE_MII;
+}
+
 static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match)
 {
        struct device *device = &ofdev->dev;
        struct device_node *np = ofdev->node;
+       struct device_node *mdio;
        struct net_device *dev = NULL;
        struct ucc_geth_private *ugeth = NULL;
        struct ucc_geth_info *ug_info;
        struct resource res;
        struct device_node *phy;
-       int err, ucc_num, phy_interface;
-       static int mii_mng_configured = 0;
+       int err, ucc_num, max_speed = 0;
        const phandle *ph;
        const unsigned int *prop;
        const void *mac_addr;
+       phy_interface_t phy_interface;
+       static const int enet_to_speed[] = {
+               SPEED_10, SPEED_10, SPEED_10,
+               SPEED_100, SPEED_100, SPEED_100,
+               SPEED_1000, SPEED_1000, SPEED_1000, SPEED_1000,
+       };
+       static const phy_interface_t enet_to_phy_interface[] = {
+               PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_RMII,
+               PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_MII,
+               PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII,
+               PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII,
+               PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI,
+       };
 
        ugeth_vdbg("%s: IN", __FUNCTION__);
 
@@ -4087,6 +3794,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
 
        ug_info = &ugeth_info[ucc_num];
        ug_info->uf_info.ucc_num = ucc_num;
+
        prop = get_property(np, "rx-clock", NULL);
        ug_info->uf_info.rx_clock = *prop;
        prop = get_property(np, "tx-clock", NULL);
@@ -4104,13 +3812,72 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
        if (phy == NULL)
                return -ENODEV;
 
+       /* set the PHY address */
        prop = get_property(phy, "reg", NULL);
+       if (prop == NULL)
+               return -1;
        ug_info->phy_address = *prop;
-       prop = get_property(phy, "interface", NULL);
-       ug_info->enet_interface = *prop;
-       ug_info->phy_interrupt = irq_of_parse_and_map(phy, 0);
-       ug_info->board_flags = (ug_info->phy_interrupt == NO_IRQ)?
-                       0:FSL_UGETH_BRD_HAS_PHY_INTR;
+
+       /* get the phy interface type, or default to MII */
+       prop = get_property(np, "interface-type", NULL);
+       if (!prop) {
+               /* handle interface property present in old trees */
+               prop = get_property(phy, "interface", NULL);
+               if (prop != NULL)
+                       phy_interface = enet_to_phy_interface[*prop];
+               else
+                       phy_interface = PHY_INTERFACE_MODE_MII;
+       } else {
+               phy_interface = to_phy_interface((const char *)prop);
+       }
+
+       /* get speed, or derive from interface */
+       prop = get_property(np, "max-speed", NULL);
+       if (!prop) {
+               /* handle interface property present in old trees */
+               prop = get_property(phy, "interface", NULL);
+               if (prop != NULL)
+                       max_speed = enet_to_speed[*prop];
+       } else {
+               max_speed = *prop;
+       }
+       if (!max_speed) {
+               switch (phy_interface) {
+               case PHY_INTERFACE_MODE_GMII:
+               case PHY_INTERFACE_MODE_RGMII:
+               case PHY_INTERFACE_MODE_RGMII_ID:
+               case PHY_INTERFACE_MODE_TBI:
+               case PHY_INTERFACE_MODE_RTBI:
+                       max_speed = SPEED_1000;
+                       break;
+               default:
+                       max_speed = SPEED_100;
+                       break;
+               }
+       }
+
+       if (max_speed == SPEED_1000) {
+               ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT;
+               ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT;
+               ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT;
+               ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT;
+               ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT;
+               ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT;
+       }
+
+       /* Set the bus id */
+       mdio = of_get_parent(phy);
+
+       if (mdio == NULL)
+               return -1;
+
+       err = of_address_to_resource(mdio, 0, &res);
+       of_node_put(mdio);
+
+       if (err)
+               return -1;
+
+       ug_info->mdio_bus = res.start;
 
        printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
                ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
@@ -4122,43 +3889,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                return -ENODEV;
        }
 
-       /* FIXME: Work around for early chip rev.               */
-       /* There's a bug in initial chip rev(s) in the RGMII ac */
-       /* timing.                                              */
-       /* The following compensates by writing to the reserved */
-       /* QE Port Output Hold Registers (CPOH1?).              */
-       prop = get_property(phy, "interface", NULL);
-       phy_interface = *prop;
-       if ((phy_interface == ENET_1000_RGMII) ||
-                       (phy_interface == ENET_100_RGMII) ||
-                       (phy_interface == ENET_10_RGMII)) {
-               struct device_node *soc;
-               phys_addr_t immrbase = -1;
-               u32 *tmp_reg;
-               u32 tmp_val;
-
-               soc = of_find_node_by_type(NULL, "soc");
-               if (soc) {
-                       unsigned int size;
-                       const void *prop = get_property(soc, "reg", &size);
-                       immrbase = of_translate_address(soc, prop);
-                       of_node_put(soc);
-               };
-
-               tmp_reg = (u32 *) ioremap(immrbase + 0x14A8, 0x4);
-               tmp_val = in_be32(tmp_reg);
-               if (ucc_num == 1)
-                       out_be32(tmp_reg, tmp_val | 0x00003000);
-               else if (ucc_num == 2)
-                       out_be32(tmp_reg, tmp_val | 0x0c000000);
-               iounmap(tmp_reg);
-       }
-
-       if (!mii_mng_configured) {
-               ucc_set_qe_mux_mii_mng(ucc_num);
-               mii_mng_configured = 1;
-       }
-
        /* Create an ethernet device instance */
        dev = alloc_etherdev(sizeof(*ugeth));
 
@@ -4192,6 +3922,10 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
        dev->set_multicast_list = ucc_geth_set_multi;
        dev->ethtool_ops = &ucc_geth_ethtool_ops;
 
+       ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+       ugeth->phy_interface = phy_interface;
+       ugeth->max_speed = max_speed;
+
        err = register_netdev(dev);
        if (err) {
                ugeth_err("%s: Cannot register net device, aborting.",
@@ -4200,13 +3934,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                return err;
        }
 
-       ugeth->ug_info = ug_info;
-       ugeth->dev = dev;
-
        mac_addr = of_get_mac_address(np);
        if (mac_addr)
                memcpy(dev->dev_addr, mac_addr, 6);
 
+       ugeth->ug_info = ug_info;
+       ugeth->dev = dev;
+
        return 0;
 }
 
@@ -4242,19 +3976,30 @@ static struct of_platform_driver ucc_geth_driver = {
 
 static int __init ucc_geth_init(void)
 {
-       int i;
+       int i, ret;
+
+       ret = uec_mdio_init();
+
+       if (ret)
+               return ret;
 
        printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
        for (i = 0; i < 8; i++)
                memcpy(&(ugeth_info[i]), &ugeth_primary_info,
                       sizeof(ugeth_primary_info));
 
-       return of_register_platform_driver(&ucc_geth_driver);
+       ret = of_register_platform_driver(&ucc_geth_driver);
+
+       if (ret)
+               uec_mdio_exit();
+
+       return ret;
 }
 
 static void __exit ucc_geth_exit(void)
 {
        of_unregister_platform_driver(&ucc_geth_driver);
+       uec_mdio_exit();
 }
 
 module_init(ucc_geth_init);
@@ -4262,4 +4007,5 @@ module_exit(ucc_geth_exit);
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
 MODULE_LICENSE("GPL");
index a66561253593c3a43ac6c6b8727f739c0918b042..a29e1c3ca4b798ee293d4774a8df3c67a75d694f 100644 (file)
@@ -28,6 +28,8 @@
 #include <asm/ucc.h>
 #include <asm/ucc_fast.h>
 
+#include "ucc_geth_mii.h"
+
 #define NUM_TX_QUEUES                   8
 #define NUM_RX_QUEUES                   8
 #define NUM_BDS_IN_PREFETCHED_BDS       4
 #define ENET_INIT_PARAM_MAX_ENTRIES_RX  9
 #define ENET_INIT_PARAM_MAX_ENTRIES_TX  8
 
-struct ucc_mii_mng {
-       u32 miimcfg;            /* MII management configuration reg */
-       u32 miimcom;            /* MII management command reg */
-       u32 miimadd;            /* MII management address reg */
-       u32 miimcon;            /* MII management control reg */
-       u32 miimstat;           /* MII management status reg */
-       u32 miimind;            /* MII management indication reg */
-} __attribute__ ((packed));
-
 struct ucc_geth {
        struct ucc_fast uccf;
 
@@ -53,7 +46,7 @@ struct ucc_geth {
        u32 ipgifg;             /* interframe gap reg.  */
        u32 hafdup;             /* half-duplex reg.  */
        u8 res1[0x10];
-       struct ucc_mii_mng miimng;      /* MII management structure */
+       u8 miimng[0x18];        /* MII management structure moved to _mii.h */
        u32 ifctl;              /* interface control reg */
        u32 ifstat;             /* interface statux reg */
        u32 macstnaddr1;        /* mac station address part 1 reg */
@@ -212,6 +205,9 @@ struct ucc_geth {
 #define UCCE_OTHER       (UCCE_SCAR | UCCE_GRA  | UCCE_CBPR | UCCE_BSY  |\
                        UCCE_RXC  | UCCE_TXC  | UCCE_TXE)
 
+#define UCCE_RX_EVENTS                                                 (UCCE_RXF | UCCE_BSY)
+#define UCCE_TX_EVENTS                                                 (UCCE_TXB | UCCE_TXE)
+
 /* UCC GETH UPSMR (Protocol Specific Mode Register) */
 #define UPSMR_ECM                               0x04000000     /* Enable CAM
                                                                   Miss or
@@ -381,66 +377,6 @@ struct ucc_geth {
 #define UCCS_MPD                                0x01   /* Magic Packet
                                                           Detected */
 
-/* UCC GETH MIIMCFG (MII Management Configuration Register) */
-#define MIIMCFG_RESET_MANAGEMENT                0x80000000     /* Reset
-                                                                  management */
-#define MIIMCFG_NO_PREAMBLE                     0x00000010     /* Preamble
-                                                                  suppress */
-#define MIIMCFG_CLOCK_DIVIDE_SHIFT              (31 - 31)      /* clock divide
-                                                                  << shift */
-#define MIIMCFG_CLOCK_DIVIDE_MAX                0xf    /* clock divide max val
-                                                        */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2    0x00000000     /* divide by 2 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4    0x00000001     /* divide by 4 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6    0x00000002     /* divide by 6 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8    0x00000003     /* divide by 8 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10   0x00000004     /* divide by 10
-                                                                */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14   0x00000005     /* divide by 14
-                                                                */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16   0x00000008     /* divide by 16
-                                                                */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20   0x00000006     /* divide by 20
-                                                                */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28   0x00000007     /* divide by 28
-                                                                */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32   0x00000009     /* divide by 32
-                                                                */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48   0x0000000a     /* divide by 48
-                                                                */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64   0x0000000b     /* divide by 64
-                                                                */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80   0x0000000c     /* divide by 80
-                                                                */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112  0x0000000d     /* divide by
-                                                                  112 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160  0x0000000e     /* divide by
-                                                                  160 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224  0x0000000f     /* divide by
-                                                                  224 */
-
-/* UCC GETH MIIMCOM (MII Management Command Register) */
-#define MIIMCOM_SCAN_CYCLE                      0x00000002     /* Scan cycle */
-#define MIIMCOM_READ_CYCLE                      0x00000001     /* Read cycle */
-
-/* UCC GETH MIIMADD (MII Management Address Register) */
-#define MIIMADD_PHY_ADDRESS_SHIFT               (31 - 23)      /* PHY Address
-                                                                  << shift */
-#define MIIMADD_PHY_REGISTER_SHIFT              (31 - 31)      /* PHY Register
-                                                                  << shift */
-
-/* UCC GETH MIIMCON (MII Management Control Register) */
-#define MIIMCON_PHY_CONTROL_SHIFT               (31 - 31)      /* PHY Control
-                                                                  << shift */
-#define MIIMCON_PHY_STATUS_SHIFT                (31 - 31)      /* PHY Status
-                                                                  << shift */
-
-/* UCC GETH MIIMIND (MII Management Indicator Register) */
-#define MIIMIND_NOT_VALID                       0x00000004     /* Not valid */
-#define MIIMIND_SCAN                            0x00000002     /* Scan in
-                                                                  progress */
-#define MIIMIND_BUSY                            0x00000001
-
 /* UCC GETH IFSTAT (Interface Status Register) */
 #define IFSTAT_EXCESS_DEFER                     0x00000200     /* Excessive
                                                                   transmission
@@ -931,8 +867,7 @@ struct ucc_geth_hardware_statistics {
 #define UCC_GETH_SCHEDULER_ALIGNMENT           4       /* This is a guess */
 #define UCC_GETH_TX_STATISTICS_ALIGNMENT       4       /* This is a guess */
 #define UCC_GETH_RX_STATISTICS_ALIGNMENT       4       /* This is a guess */
-#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT     4       /* This is a
-                                                                  guess */
+#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT     64
 #define UCC_GETH_RX_BD_QUEUES_ALIGNMENT                8       /* This is a guess */
 #define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT   128     /* This is a guess */
 #define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4   /* This
@@ -1009,15 +944,6 @@ struct ucc_geth_hardware_statistics {
                                                                   register */
 #define UCC_GETH_MACCFG1_INIT                   0
 #define UCC_GETH_MACCFG2_INIT                   (MACCFG2_RESERVED_1)
-#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT    \
-                               (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112)
-
-/* Ethernet speed */
-enum enet_speed {
-       ENET_SPEED_10BT,        /* 10 Base T */
-       ENET_SPEED_100BT,       /* 100 Base T */
-       ENET_SPEED_1000BT       /* 1000 Base T */
-};
 
 /* Ethernet Address Type. */
 enum enet_addr_type {
@@ -1026,22 +952,6 @@ enum enet_addr_type {
        ENET_ADDR_TYPE_BROADCAST
 };
 
-/* TBI / MII Set Register */
-enum enet_tbi_mii_reg {
-       ENET_TBI_MII_CR = 0x00, /* Control (CR ) */
-       ENET_TBI_MII_SR = 0x01, /* Status (SR ) */
-       ENET_TBI_MII_ANA = 0x04,        /* AN advertisement (ANA ) */
-       ENET_TBI_MII_ANLPBPA = 0x05,    /* AN link partner base page ability
-                                          (ANLPBPA) */
-       ENET_TBI_MII_ANEX = 0x06,       /* AN expansion (ANEX ) */
-       ENET_TBI_MII_ANNPT = 0x07,      /* AN next page transmit (ANNPT ) */
-       ENET_TBI_MII_ANLPANP = 0x08,    /* AN link partner ability next page
-                                          (ANLPANP) */
-       ENET_TBI_MII_EXST = 0x0F,       /* Extended status (EXST ) */
-       ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */
-       ENET_TBI_MII_TBICON = 0x11      /* TBI control (TBICON ) */
-};
-
 /* UCC GETH 82xx Ethernet Address Recognition Location */
 enum ucc_geth_enet_address_recognition_location {
        UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station
@@ -1239,8 +1149,7 @@ struct ucc_geth_info {
        u16 pausePeriod;
        u16 extensionField;
        u8 phy_address;
-       u32 board_flags;
-       u32 phy_interrupt;
+       u32 mdio_bus;
        u8 weightfactor[NUM_TX_QUEUES];
        u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
        u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];
@@ -1249,7 +1158,6 @@ struct ucc_geth_info {
        u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX];
        u16 bdRingLenTx[NUM_TX_QUEUES];
        u16 bdRingLenRx[NUM_RX_QUEUES];
-       enum enet_interface enet_interface;
        enum ucc_geth_num_of_station_addresses numStationAddresses;
        enum qe_fltr_largest_external_tbl_lookup_key_size
            largestexternallookupkeysize;
@@ -1326,9 +1234,11 @@ struct ucc_geth_private {
        /* index of the first skb which hasn't been transmitted yet. */
        u16 skb_dirtytx[NUM_TX_QUEUES];
 
-       struct work_struct tq;
-       struct timer_list phy_info_timer;
        struct ugeth_mii_info *mii_info;
+       struct phy_device *phydev;
+       phy_interface_t phy_interface;
+       int max_speed;
+       uint32_t msg_enable;
        int oldspeed;
        int oldduplex;
        int oldlink;
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
new file mode 100644 (file)
index 0000000..73b5a53
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * drivers/net/ucc_geth_mii.c
+ *
+ * Gianfar Ethernet Driver -- MIIM bus implementation
+ * Provides Bus interface for MIIM regs
+ *
+ * Author: Li Yang
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <asm/ocp.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/of_platform.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/ucc.h>
+
+#include "ucc_geth_mii.h"
+#include "ucc_geth.h"
+
+#define DEBUG
+#ifdef DEBUG
+#define vdbg(format, arg...) printk(KERN_DEBUG , format "\n" , ## arg)
+#else
+#define vdbg(format, arg...) do {} while(0)
+#endif
+
+#define DRV_DESC "QE UCC Ethernet Controller MII Bus"
+#define DRV_NAME "fsl-uec_mdio"
+
+/* Write value to the PHY for this device to the register at regnum, */
+/* waiting until the write is done before it returns.  All PHY */
+/* configuration has to be done through the master UEC MIIM regs */
+int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+{
+       struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+
+       /* Setting up the MII Mangement Address Register */
+       out_be32(&regs->miimadd,
+                (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum);
+
+       /* Setting up the MII Mangement Control Register with the value */
+       out_be32(&regs->miimcon, value);
+
+       /* Wait till MII management write is complete */
+       while ((in_be32(&regs->miimind)) & MIIMIND_BUSY)
+               cpu_relax();
+
+       return 0;
+}
+
+/* Reads from register regnum in the PHY for device dev, */
+/* returning the value.  Clears miimcom first.  All PHY */
+/* configuration has to be done through the TSEC1 MIIM regs */
+int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+       struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+       u16 value;
+
+       /* Setting up the MII Mangement Address Register */
+       out_be32(&regs->miimadd,
+                (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum);
+
+       /* Clear miimcom, perform an MII management read cycle */
+       out_be32(&regs->miimcom, 0);
+       out_be32(&regs->miimcom, MIIMCOM_READ_CYCLE);
+
+       /* Wait till MII management write is complete */
+       while ((in_be32(&regs->miimind)) & (MIIMIND_BUSY | MIIMIND_NOT_VALID))
+               cpu_relax();
+
+       /* Read MII management status  */
+       value = in_be32(&regs->miimstat);
+
+       return value;
+}
+
+/* Reset the MIIM registers, and wait for the bus to free */
+int uec_mdio_reset(struct mii_bus *bus)
+{
+       struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+       unsigned int timeout = PHY_INIT_TIMEOUT;
+
+       spin_lock_bh(&bus->mdio_lock);
+
+       /* Reset the management interface */
+       out_be32(&regs->miimcfg, MIIMCFG_RESET_MANAGEMENT);
+
+       /* Setup the MII Mgmt clock speed */
+       out_be32(&regs->miimcfg, MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112);
+
+       /* Wait until the bus is free */
+       while ((in_be32(&regs->miimind) & MIIMIND_BUSY) && timeout--)
+               cpu_relax();
+
+       spin_unlock_bh(&bus->mdio_lock);
+
+       if (timeout <= 0) {
+               printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *match)
+{
+       struct device *device = &ofdev->dev;
+       struct device_node *np = ofdev->node, *tempnp = NULL;
+       struct device_node *child = NULL;
+       struct ucc_mii_mng __iomem *regs;
+       struct mii_bus *new_bus;
+       struct resource res;
+       int k, err = 0;
+
+       new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+       if (NULL == new_bus)
+               return -ENOMEM;
+
+       new_bus->name = "UCC Ethernet Controller MII Bus";
+       new_bus->read = &uec_mdio_read;
+       new_bus->write = &uec_mdio_write;
+       new_bus->reset = &uec_mdio_reset;
+
+       memset(&res, 0, sizeof(res));
+
+       err = of_address_to_resource(np, 0, &res);
+       if (err)
+               goto reg_map_fail;
+
+       new_bus->id = res.start;
+
+       new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL);
+
+       if (NULL == new_bus->irq) {
+               err = -ENOMEM;
+               goto reg_map_fail;
+       }
+
+       for (k = 0; k < 32; k++)
+               new_bus->irq[k] = PHY_POLL;
+
+       while ((child = of_get_next_child(np, child)) != NULL) {
+               int irq = irq_of_parse_and_map(child, 0);
+               if (irq != NO_IRQ) {
+                       const u32 *id = get_property(child, "reg", NULL);
+                       new_bus->irq[*id] = irq;
+               }
+       }
+
+       /* Set the base address */
+       regs = ioremap(res.start, sizeof(struct ucc_mii_mng));
+
+       if (NULL == regs) {
+               err = -ENOMEM;
+               goto ioremap_fail;
+       }
+
+       new_bus->priv = (void __force *)regs;
+
+       new_bus->dev = device;
+       dev_set_drvdata(device, new_bus);
+
+       /* Read MII management master from device tree */
+       while ((tempnp = of_find_compatible_node(tempnp, "network", "ucc_geth"))
+              != NULL) {
+               struct resource tempres;
+
+               err = of_address_to_resource(tempnp, 0, &tempres);
+               if (err)
+                       goto bus_register_fail;
+
+               /* if our mdio regs fall within this UCC regs range */
+               if ((res.start >= tempres.start) &&
+                   (res.end <= tempres.end)) {
+                       /* set this UCC to be the MII master */
+                       const u32 *id = get_property(tempnp, "device-id", NULL);
+                       if (id == NULL)
+                               goto bus_register_fail;
+
+                       ucc_set_qe_mux_mii_mng(*id - 1);
+
+                       /* assign the TBI an address which won't
+                        * conflict with the PHYs */
+                       out_be32(&regs->utbipar, UTBIPAR_INIT_TBIPA);
+                       break;
+               }
+       }
+
+       err = mdiobus_register(new_bus);
+       if (0 != err) {
+               printk(KERN_ERR "%s: Cannot register as MDIO bus\n",
+                      new_bus->name);
+               goto bus_register_fail;
+       }
+
+       return 0;
+
+bus_register_fail:
+       iounmap(regs);
+ioremap_fail:
+       kfree(new_bus->irq);
+reg_map_fail:
+       kfree(new_bus);
+
+       return err;
+}
+
+int uec_mdio_remove(struct of_device *ofdev)
+{
+       struct device *device = &ofdev->dev;
+       struct mii_bus *bus = dev_get_drvdata(device);
+
+       mdiobus_unregister(bus);
+
+       dev_set_drvdata(device, NULL);
+
+       iounmap((void __iomem *)bus->priv);
+       bus->priv = NULL;
+       kfree(bus);
+
+       return 0;
+}
+
+static struct of_device_id uec_mdio_match[] = {
+       {
+               .type = "mdio",
+               .compatible = "ucc_geth_phy",
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, uec_mdio_match);
+
+static struct of_platform_driver uec_mdio_driver = {
+       .name   = DRV_NAME,
+       .probe  = uec_mdio_probe,
+       .remove = uec_mdio_remove,
+       .match_table    = uec_mdio_match,
+};
+
+int __init uec_mdio_init(void)
+{
+       return of_register_platform_driver(&uec_mdio_driver);
+}
+
+void __exit uec_mdio_exit(void)
+{
+       of_unregister_platform_driver(&uec_mdio_driver);
+}
diff --git a/drivers/net/ucc_geth_mii.h b/drivers/net/ucc_geth_mii.h
new file mode 100644 (file)
index 0000000..98430fe
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * drivers/net/ucc_geth_mii.h
+ *
+ * Gianfar Ethernet Driver -- MII Management Bus Implementation
+ * Driver for the MDIO bus controller in the Gianfar register space
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __UEC_MII_H
+#define __UEC_MII_H
+
+/* UCC GETH MIIMCFG (MII Management Configuration Register) */
+#define MIIMCFG_RESET_MANAGEMENT                0x80000000     /* Reset
+                                                                  management */
+#define MIIMCFG_NO_PREAMBLE                     0x00000010     /* Preamble
+                                                                  suppress */
+#define MIIMCFG_CLOCK_DIVIDE_SHIFT              (31 - 31)      /* clock divide
+                                                                  << shift */
+#define MIIMCFG_CLOCK_DIVIDE_MAX                0xf    /* max clock divide */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2    0x00000000
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4    0x00000001
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6    0x00000002
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8    0x00000003
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10   0x00000004
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14   0x00000005
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16   0x00000008
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20   0x00000006
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28   0x00000007
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32   0x00000009
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48   0x0000000a
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64   0x0000000b
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80   0x0000000c
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112  0x0000000d
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160  0x0000000e
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224  0x0000000f
+
+/* UCC GETH MIIMCOM (MII Management Command Register) */
+#define MIIMCOM_SCAN_CYCLE                      0x00000002     /* Scan cycle */
+#define MIIMCOM_READ_CYCLE                      0x00000001     /* Read cycle */
+
+/* UCC GETH MIIMADD (MII Management Address Register) */
+#define MIIMADD_PHY_ADDRESS_SHIFT               (31 - 23)      /* PHY Address
+                                                                  << shift */
+#define MIIMADD_PHY_REGISTER_SHIFT              (31 - 31)      /* PHY Register
+                                                                  << shift */
+
+/* UCC GETH MIIMCON (MII Management Control Register) */
+#define MIIMCON_PHY_CONTROL_SHIFT               (31 - 31)      /* PHY Control
+                                                                  << shift */
+#define MIIMCON_PHY_STATUS_SHIFT                (31 - 31)      /* PHY Status
+                                                                  << shift */
+
+/* UCC GETH MIIMIND (MII Management Indicator Register) */
+#define MIIMIND_NOT_VALID                       0x00000004     /* Not valid */
+#define MIIMIND_SCAN                            0x00000002     /* Scan in
+                                                                  progress */
+#define MIIMIND_BUSY                            0x00000001
+
+/* Initial TBI Physical Address */
+#define UTBIPAR_INIT_TBIPA                     0x1f
+
+struct ucc_mii_mng {
+       u32 miimcfg;            /* MII management configuration reg */
+       u32 miimcom;            /* MII management command reg */
+       u32 miimadd;            /* MII management address reg */
+       u32 miimcon;            /* MII management control reg */
+       u32 miimstat;           /* MII management status reg */
+       u32 miimind;            /* MII management indication reg */
+       u8 notcare[28];         /* Space holder */
+       u32 utbipar;            /* TBI phy address reg */
+} __attribute__ ((packed));
+
+/* TBI / MII Set Register */
+enum enet_tbi_mii_reg {
+       ENET_TBI_MII_CR = 0x00, /* Control */
+       ENET_TBI_MII_SR = 0x01, /* Status */
+       ENET_TBI_MII_ANA = 0x04,        /* AN advertisement */
+       ENET_TBI_MII_ANLPBPA = 0x05,    /* AN link partner base page ability */
+       ENET_TBI_MII_ANEX = 0x06,       /* AN expansion */
+       ENET_TBI_MII_ANNPT = 0x07,      /* AN next page transmit */
+       ENET_TBI_MII_ANLPANP = 0x08,    /* AN link partner ability next page */
+       ENET_TBI_MII_EXST = 0x0F,       /* Extended status */
+       ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics */
+       ENET_TBI_MII_TBICON = 0x11      /* TBI control */
+};
+
+int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
+int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int __init uec_mdio_init(void);
+void __exit uec_mdio_exit(void);
+#endif                         /* __UEC_MII_H */
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
deleted file mode 100644 (file)
index 9373d89..0000000
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Author: Shlomi Gridish <gridish@freescale.com>
- *
- * Description:
- * UCC GETH Driver -- PHY handling
- *
- * Changelog:
- * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
- * - Rearrange code and style fixes
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "ucc_geth.h"
-#include "ucc_geth_phy.h"
-
-#define ugphy_printk(level, format, arg...)  \
-        printk(level format "\n", ## arg)
-
-#define ugphy_dbg(format, arg...)            \
-        ugphy_printk(KERN_DEBUG, format , ## arg)
-#define ugphy_err(format, arg...)            \
-        ugphy_printk(KERN_ERR, format , ## arg)
-#define ugphy_info(format, arg...)           \
-        ugphy_printk(KERN_INFO, format , ## arg)
-#define ugphy_warn(format, arg...)           \
-        ugphy_printk(KERN_WARNING, format , ## arg)
-
-#ifdef UGETH_VERBOSE_DEBUG
-#define ugphy_vdbg ugphy_dbg
-#else
-#define ugphy_vdbg(fmt, args...) do { } while (0)
-#endif                         /* UGETH_VERBOSE_DEBUG */
-
-static void config_genmii_advert(struct ugeth_mii_info *mii_info);
-static void genmii_setup_forced(struct ugeth_mii_info *mii_info);
-static void genmii_restart_aneg(struct ugeth_mii_info *mii_info);
-static int gbit_config_aneg(struct ugeth_mii_info *mii_info);
-static int genmii_config_aneg(struct ugeth_mii_info *mii_info);
-static int genmii_update_link(struct ugeth_mii_info *mii_info);
-static int genmii_read_status(struct ugeth_mii_info *mii_info);
-
-static u16 ucc_geth_phy_read(struct ugeth_mii_info *mii_info, u16 regnum)
-{
-       u16 retval;
-       unsigned long flags;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       spin_lock_irqsave(&mii_info->mdio_lock, flags);
-       retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
-       spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-
-       return retval;
-}
-
-static void ucc_geth_phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val)
-{
-       unsigned long flags;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       spin_lock_irqsave(&mii_info->mdio_lock, flags);
-       mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val);
-       spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-}
-
-/* Write value to the PHY for this device to the register at regnum, */
-/* waiting until the write is done before it returns.  All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value)
-{
-       struct ucc_geth_private *ugeth = netdev_priv(dev);
-       struct ucc_mii_mng *mii_regs;
-       enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum;
-       u32 tmp_reg;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       spin_lock_irq(&ugeth->lock);
-
-       mii_regs = ugeth->mii_info->mii_regs;
-
-       /* Set this UCC to be the master of the MII managment */
-       ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
-
-       /* Stop the MII management read cycle */
-       out_be32(&mii_regs->miimcom, 0);
-       /* Setting up the MII Mangement Address Register */
-       tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
-       out_be32(&mii_regs->miimadd, tmp_reg);
-
-       /* Setting up the MII Mangement Control Register with the value */
-       out_be32(&mii_regs->miimcon, (u32) value);
-
-       /* Wait till MII management write is complete */
-       while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
-               cpu_relax();
-
-       spin_unlock_irq(&ugeth->lock);
-
-       udelay(10000);
-}
-
-/* Reads from register regnum in the PHY for device dev, */
-/* returning the value.  Clears miimcom first.  All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum)
-{
-       struct ucc_geth_private *ugeth = netdev_priv(dev);
-       struct ucc_mii_mng *mii_regs;
-       enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum;
-       u32 tmp_reg;
-       u16 value;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       spin_lock_irq(&ugeth->lock);
-
-       mii_regs = ugeth->mii_info->mii_regs;
-
-       /* Setting up the MII Mangement Address Register */
-       tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
-       out_be32(&mii_regs->miimadd, tmp_reg);
-
-       /* Perform an MII management read cycle */
-       out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE);
-
-       /* Wait till MII management write is complete */
-       while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
-               cpu_relax();
-
-       udelay(10000);
-
-       /* Read MII management status  */
-       value = (u16) in_be32(&mii_regs->miimstat);
-       out_be32(&mii_regs->miimcom, 0);
-       if (value == 0xffff)
-               ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x",
-                          mii_id, mii_reg, (u32) & (mii_regs->miimcfg));
-
-       spin_unlock_irq(&ugeth->lock);
-
-       return (value);
-}
-
-void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       if (mii_info->phyinfo->ack_interrupt)
-               mii_info->phyinfo->ack_interrupt(mii_info);
-}
-
-void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
-                                u32 interrupts)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       mii_info->interrupts = interrupts;
-       if (mii_info->phyinfo->config_intr)
-               mii_info->phyinfo->config_intr(mii_info);
-}
-
-/* Writes MII_ADVERTISE with the appropriate values, after
- * sanitizing advertise to make sure only supported features
- * are advertised
- */
-static void config_genmii_advert(struct ugeth_mii_info *mii_info)
-{
-       u32 advertise;
-       u16 adv;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* Only allow advertising what this PHY supports */
-       mii_info->advertising &= mii_info->phyinfo->features;
-       advertise = mii_info->advertising;
-
-       /* Setup standard advertisement */
-       adv = ucc_geth_phy_read(mii_info, MII_ADVERTISE);
-       adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
-       if (advertise & ADVERTISED_10baseT_Half)
-               adv |= ADVERTISE_10HALF;
-       if (advertise & ADVERTISED_10baseT_Full)
-               adv |= ADVERTISE_10FULL;
-       if (advertise & ADVERTISED_100baseT_Half)
-               adv |= ADVERTISE_100HALF;
-       if (advertise & ADVERTISED_100baseT_Full)
-               adv |= ADVERTISE_100FULL;
-       ucc_geth_phy_write(mii_info, MII_ADVERTISE, adv);
-}
-
-static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
-{
-       u16 ctrl;
-       u32 features = mii_info->phyinfo->features;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       ctrl = ucc_geth_phy_read(mii_info, MII_BMCR);
-
-       ctrl &=
-           ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
-       ctrl |= BMCR_RESET;
-
-       switch (mii_info->speed) {
-       case SPEED_1000:
-               if (features & (SUPPORTED_1000baseT_Half
-                               | SUPPORTED_1000baseT_Full)) {
-                       ctrl |= BMCR_SPEED1000;
-                       break;
-               }
-               mii_info->speed = SPEED_100;
-       case SPEED_100:
-               if (features & (SUPPORTED_100baseT_Half
-                               | SUPPORTED_100baseT_Full)) {
-                       ctrl |= BMCR_SPEED100;
-                       break;
-               }
-               mii_info->speed = SPEED_10;
-       case SPEED_10:
-               if (features & (SUPPORTED_10baseT_Half
-                               | SUPPORTED_10baseT_Full))
-                       break;
-       default:                /* Unsupported speed! */
-               ugphy_err("%s: Bad speed!", mii_info->dev->name);
-               break;
-       }
-
-       ucc_geth_phy_write(mii_info, MII_BMCR, ctrl);
-}
-
-/* Enable and Restart Autonegotiation */
-static void genmii_restart_aneg(struct ugeth_mii_info *mii_info)
-{
-       u16 ctl;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       ctl = ucc_geth_phy_read(mii_info, MII_BMCR);
-       ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
-       ucc_geth_phy_write(mii_info, MII_BMCR, ctl);
-}
-
-static int gbit_config_aneg(struct ugeth_mii_info *mii_info)
-{
-       u16 adv;
-       u32 advertise;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       if (mii_info->autoneg) {
-               /* Configure the ADVERTISE register */
-               config_genmii_advert(mii_info);
-               advertise = mii_info->advertising;
-
-               adv = ucc_geth_phy_read(mii_info, MII_1000BASETCONTROL);
-               adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
-                        MII_1000BASETCONTROL_HALFDUPLEXCAP);
-               if (advertise & SUPPORTED_1000baseT_Half)
-                       adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
-               if (advertise & SUPPORTED_1000baseT_Full)
-                       adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
-               ucc_geth_phy_write(mii_info, MII_1000BASETCONTROL, adv);
-
-               /* Start/Restart aneg */
-               genmii_restart_aneg(mii_info);
-       } else
-               genmii_setup_forced(mii_info);
-
-       return 0;
-}
-
-static int genmii_config_aneg(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       if (mii_info->autoneg) {
-               config_genmii_advert(mii_info);
-               genmii_restart_aneg(mii_info);
-       } else
-               genmii_setup_forced(mii_info);
-
-       return 0;
-}
-
-static int genmii_update_link(struct ugeth_mii_info *mii_info)
-{
-       u16 status;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* Do a fake read */
-       ucc_geth_phy_read(mii_info, MII_BMSR);
-
-       /* Read link and autonegotiation status */
-       status = ucc_geth_phy_read(mii_info, MII_BMSR);
-       if ((status & BMSR_LSTATUS) == 0)
-               mii_info->link = 0;
-       else
-               mii_info->link = 1;
-
-       /* If we are autonegotiating, and not done,
-        * return an error */
-       if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE))
-               return -EAGAIN;
-
-       return 0;
-}
-
-static int genmii_read_status(struct ugeth_mii_info *mii_info)
-{
-       u16 status;
-       int err;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* Update the link, but return if there
-        * was an error */
-       err = genmii_update_link(mii_info);
-       if (err)
-               return err;
-
-       if (mii_info->autoneg) {
-               status = ucc_geth_phy_read(mii_info, MII_LPA);
-
-               if (status & (LPA_10FULL | LPA_100FULL))
-                       mii_info->duplex = DUPLEX_FULL;
-               else
-                       mii_info->duplex = DUPLEX_HALF;
-               if (status & (LPA_100FULL | LPA_100HALF))
-                       mii_info->speed = SPEED_100;
-               else
-                       mii_info->speed = SPEED_10;
-               mii_info->pause = 0;
-       }
-       /* On non-aneg, we assume what we put in BMCR is the speed,
-        * though magic-aneg shouldn't prevent this case from occurring
-        */
-
-       return 0;
-}
-
-static int marvell_init(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       ucc_geth_phy_write(mii_info, 0x14, 0x0cd2);
-       ucc_geth_phy_write(mii_info, 0x1b,
-               (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b);
-       ucc_geth_phy_write(mii_info, MII_BMCR,
-                 ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
-       msleep(4000);
-
-       return 0;
-}
-
-static int marvell_config_aneg(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* The Marvell PHY has an errata which requires
-        * that certain registers get written in order
-        * to restart autonegotiation */
-       ucc_geth_phy_write(mii_info, MII_BMCR, BMCR_RESET);
-
-       ucc_geth_phy_write(mii_info, 0x1d, 0x1f);
-       ucc_geth_phy_write(mii_info, 0x1e, 0x200c);
-       ucc_geth_phy_write(mii_info, 0x1d, 0x5);
-       ucc_geth_phy_write(mii_info, 0x1e, 0);
-       ucc_geth_phy_write(mii_info, 0x1e, 0x100);
-
-       gbit_config_aneg(mii_info);
-
-       return 0;
-}
-
-static int marvell_read_status(struct ugeth_mii_info *mii_info)
-{
-       u16 status;
-       int err;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* Update the link, but return if there
-        * was an error */
-       err = genmii_update_link(mii_info);
-       if (err)
-               return err;
-
-       /* If the link is up, read the speed and duplex */
-       /* If we aren't autonegotiating, assume speeds
-        * are as set */
-       if (mii_info->autoneg && mii_info->link) {
-               int speed;
-               status = ucc_geth_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
-
-               /* Get the duplexity */
-               if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
-                       mii_info->duplex = DUPLEX_FULL;
-               else
-                       mii_info->duplex = DUPLEX_HALF;
-
-               /* Get the speed */
-               speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
-               switch (speed) {
-               case MII_M1011_PHY_SPEC_STATUS_1000:
-                       mii_info->speed = SPEED_1000;
-                       break;
-               case MII_M1011_PHY_SPEC_STATUS_100:
-                       mii_info->speed = SPEED_100;
-                       break;
-               default:
-                       mii_info->speed = SPEED_10;
-                       break;
-               }
-               mii_info->pause = 0;
-       }
-
-       return 0;
-}
-
-static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* Clear the interrupts by reading the reg */
-       ucc_geth_phy_read(mii_info, MII_M1011_IEVENT);
-
-       return 0;
-}
-
-static int marvell_config_intr(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
-               ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
-       else
-               ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
-
-       return 0;
-}
-
-static int cis820x_init(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       ucc_geth_phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
-                 MII_CIS8201_AUXCONSTAT_INIT);
-       ucc_geth_phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT);
-
-       return 0;
-}
-
-static int cis820x_read_status(struct ugeth_mii_info *mii_info)
-{
-       u16 status;
-       int err;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* Update the link, but return if there
-        * was an error */
-       err = genmii_update_link(mii_info);
-       if (err)
-               return err;
-
-       /* If the link is up, read the speed and duplex */
-       /* If we aren't autonegotiating, assume speeds
-        * are as set */
-       if (mii_info->autoneg && mii_info->link) {
-               int speed;
-
-               status = ucc_geth_phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
-               if (status & MII_CIS8201_AUXCONSTAT_DUPLEX)
-                       mii_info->duplex = DUPLEX_FULL;
-               else
-                       mii_info->duplex = DUPLEX_HALF;
-
-               speed = status & MII_CIS8201_AUXCONSTAT_SPEED;
-
-               switch (speed) {
-               case MII_CIS8201_AUXCONSTAT_GBIT:
-                       mii_info->speed = SPEED_1000;
-                       break;
-               case MII_CIS8201_AUXCONSTAT_100:
-                       mii_info->speed = SPEED_100;
-                       break;
-               default:
-                       mii_info->speed = SPEED_10;
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       ucc_geth_phy_read(mii_info, MII_CIS8201_ISTAT);
-
-       return 0;
-}
-
-static int cis820x_config_intr(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
-               ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK);
-       else
-               ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, 0);
-
-       return 0;
-}
-
-#define DM9161_DELAY 10
-
-static int dm9161_read_status(struct ugeth_mii_info *mii_info)
-{
-       u16 status;
-       int err;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* Update the link, but return if there
-        * was an error */
-       err = genmii_update_link(mii_info);
-       if (err)
-               return err;
-
-       /* If the link is up, read the speed and duplex */
-       /* If we aren't autonegotiating, assume speeds
-        * are as set */
-       if (mii_info->autoneg && mii_info->link) {
-               status = ucc_geth_phy_read(mii_info, MII_DM9161_SCSR);
-               if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
-                       mii_info->speed = SPEED_100;
-               else
-                       mii_info->speed = SPEED_10;
-
-               if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
-                       mii_info->duplex = DUPLEX_FULL;
-               else
-                       mii_info->duplex = DUPLEX_HALF;
-       }
-
-       return 0;
-}
-
-static int dm9161_config_aneg(struct ugeth_mii_info *mii_info)
-{
-       struct dm9161_private *priv = mii_info->priv;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       if (0 == priv->resetdone)
-               return -EAGAIN;
-
-       return 0;
-}
-
-static void dm9161_timer(unsigned long data)
-{
-       struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
-       struct dm9161_private *priv = mii_info->priv;
-       u16 status = ucc_geth_phy_read(mii_info, MII_BMSR);
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       if (status & BMSR_ANEGCOMPLETE) {
-               priv->resetdone = 1;
-       } else
-               mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-}
-
-static int dm9161_init(struct ugeth_mii_info *mii_info)
-{
-       struct dm9161_private *priv;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* Allocate the private data structure */
-       priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL);
-
-       if (NULL == priv)
-               return -ENOMEM;
-
-       mii_info->priv = priv;
-
-       /* Reset is not done yet */
-       priv->resetdone = 0;
-
-       ucc_geth_phy_write(mii_info, MII_BMCR,
-                 ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
-
-       ucc_geth_phy_write(mii_info, MII_BMCR,
-                 ucc_geth_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE);
-
-       config_genmii_advert(mii_info);
-       /* Start/Restart aneg */
-       genmii_config_aneg(mii_info);
-
-       /* Start a timer for DM9161_DELAY seconds to wait
-        * for the PHY to be ready */
-       init_timer(&priv->timer);
-       priv->timer.function = &dm9161_timer;
-       priv->timer.data = (unsigned long)mii_info;
-       mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-
-       return 0;
-}
-
-static void dm9161_close(struct ugeth_mii_info *mii_info)
-{
-       struct dm9161_private *priv = mii_info->priv;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       del_timer_sync(&priv->timer);
-       kfree(priv);
-}
-
-static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* Clear the interrupts by reading the reg */
-       ucc_geth_phy_read(mii_info, MII_DM9161_INTR);
-
-
-       return 0;
-}
-
-static int dm9161_config_intr(struct ugeth_mii_info *mii_info)
-{
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
-               ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
-       else
-               ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
-
-       return 0;
-}
-
-/* Cicada 820x */
-static struct phy_info phy_info_cis820x = {
-       .phy_id = 0x000fc440,
-       .name = "Cicada Cis8204",
-       .phy_id_mask = 0x000fffc0,
-       .features = MII_GBIT_FEATURES,
-       .init = &cis820x_init,
-       .config_aneg = &gbit_config_aneg,
-       .read_status = &cis820x_read_status,
-       .ack_interrupt = &cis820x_ack_interrupt,
-       .config_intr = &cis820x_config_intr,
-};
-
-static struct phy_info phy_info_dm9161 = {
-       .phy_id = 0x0181b880,
-       .phy_id_mask = 0x0ffffff0,
-       .name = "Davicom DM9161E",
-       .init = dm9161_init,
-       .config_aneg = dm9161_config_aneg,
-       .read_status = dm9161_read_status,
-       .close = dm9161_close,
-};
-
-static struct phy_info phy_info_dm9161a = {
-       .phy_id = 0x0181b8a0,
-       .phy_id_mask = 0x0ffffff0,
-       .name = "Davicom DM9161A",
-       .features = MII_BASIC_FEATURES,
-       .init = dm9161_init,
-       .config_aneg = dm9161_config_aneg,
-       .read_status = dm9161_read_status,
-       .ack_interrupt = dm9161_ack_interrupt,
-       .config_intr = dm9161_config_intr,
-       .close = dm9161_close,
-};
-
-static struct phy_info phy_info_marvell = {
-       .phy_id = 0x01410c00,
-       .phy_id_mask = 0xffffff00,
-       .name = "Marvell 88E11x1",
-       .features = MII_GBIT_FEATURES,
-       .init = &marvell_init,
-       .config_aneg = &marvell_config_aneg,
-       .read_status = &marvell_read_status,
-       .ack_interrupt = &marvell_ack_interrupt,
-       .config_intr = &marvell_config_intr,
-};
-
-static struct phy_info phy_info_genmii = {
-       .phy_id = 0x00000000,
-       .phy_id_mask = 0x00000000,
-       .name = "Generic MII",
-       .features = MII_BASIC_FEATURES,
-       .config_aneg = genmii_config_aneg,
-       .read_status = genmii_read_status,
-};
-
-static struct phy_info *phy_info[] = {
-       &phy_info_cis820x,
-       &phy_info_marvell,
-       &phy_info_dm9161,
-       &phy_info_dm9161a,
-       &phy_info_genmii,
-       NULL
-};
-
-/* Use the PHY ID registers to determine what type of PHY is attached
- * to device dev.  return a struct phy_info structure describing that PHY
- */
-struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info)
-{
-       u16 phy_reg;
-       u32 phy_ID;
-       int i;
-       struct phy_info *theInfo = NULL;
-       struct net_device *dev = mii_info->dev;
-
-       ugphy_vdbg("%s: IN", __FUNCTION__);
-
-       /* Grab the bits from PHYIR1, and put them in the upper half */
-       phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID1);
-       phy_ID = (phy_reg & 0xffff) << 16;
-
-       /* Grab the bits from PHYIR2, and put them in the lower half */
-       phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID2);
-       phy_ID |= (phy_reg & 0xffff);
-
-       /* loop through all the known PHY types, and find one that */
-       /* matches the ID we read from the PHY. */
-       for (i = 0; phy_info[i]; i++)
-               if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){
-                       theInfo = phy_info[i];
-                       break;
-               }
-
-       /* This shouldn't happen, as we have generic PHY support */
-       if (theInfo == NULL) {
-               ugphy_info("%s: PHY id %x is not supported!", dev->name,
-                          phy_ID);
-               return NULL;
-       } else {
-               ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name,
-                          phy_ID);
-       }
-
-       return theInfo;
-}
diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h
deleted file mode 100644 (file)
index f574078..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Author: Shlomi Gridish <gridish@freescale.com>
- *
- * Description:
- * UCC GETH Driver -- PHY handling
- *
- * Changelog:
- * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
- * - Rearrange code and style fixes
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-#ifndef __UCC_GETH_PHY_H__
-#define __UCC_GETH_PHY_H__
-
-#define MII_end ((u32)-2)
-#define MII_read ((u32)-1)
-
-#define MIIMIND_BUSY            0x00000001
-#define MIIMIND_NOTVALID        0x00000004
-
-#define UGETH_AN_TIMEOUT        2000
-
-/* 1000BT control (Marvell & BCM54xx at least) */
-#define MII_1000BASETCONTROL                  0x09
-#define MII_1000BASETCONTROL_FULLDUPLEXCAP    0x0200
-#define MII_1000BASETCONTROL_HALFDUPLEXCAP    0x0100
-
-/* Cicada Extended Control Register 1 */
-#define MII_CIS8201_EXT_CON1        0x17
-#define MII_CIS8201_EXTCON1_INIT    0x0000
-
-/* Cicada Interrupt Mask Register */
-#define MII_CIS8201_IMASK           0x19
-#define MII_CIS8201_IMASK_IEN       0x8000
-#define MII_CIS8201_IMASK_SPEED     0x4000
-#define MII_CIS8201_IMASK_LINK      0x2000
-#define MII_CIS8201_IMASK_DUPLEX    0x1000
-#define MII_CIS8201_IMASK_MASK      0xf000
-
-/* Cicada Interrupt Status Register */
-#define MII_CIS8201_ISTAT           0x1a
-#define MII_CIS8201_ISTAT_STATUS    0x8000
-#define MII_CIS8201_ISTAT_SPEED     0x4000
-#define MII_CIS8201_ISTAT_LINK      0x2000
-#define MII_CIS8201_ISTAT_DUPLEX    0x1000
-
-/* Cicada Auxiliary Control/Status Register */
-#define MII_CIS8201_AUX_CONSTAT        0x1c
-#define MII_CIS8201_AUXCONSTAT_INIT    0x0004
-#define MII_CIS8201_AUXCONSTAT_DUPLEX  0x0020
-#define MII_CIS8201_AUXCONSTAT_SPEED   0x0018
-#define MII_CIS8201_AUXCONSTAT_GBIT    0x0010
-#define MII_CIS8201_AUXCONSTAT_100     0x0008
-
-/* 88E1011 PHY Status Register */
-#define MII_M1011_PHY_SPEC_STATUS               0x11
-#define MII_M1011_PHY_SPEC_STATUS_1000          0x8000
-#define MII_M1011_PHY_SPEC_STATUS_100           0x4000
-#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK      0xc000
-#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX    0x2000
-#define MII_M1011_PHY_SPEC_STATUS_RESOLVED      0x0800
-#define MII_M1011_PHY_SPEC_STATUS_LINK          0x0400
-
-#define MII_M1011_IEVENT                0x13
-#define MII_M1011_IEVENT_CLEAR          0x0000
-
-#define MII_M1011_IMASK                 0x12
-#define MII_M1011_IMASK_INIT            0x6400
-#define MII_M1011_IMASK_CLEAR           0x0000
-
-#define MII_DM9161_SCR                  0x10
-#define MII_DM9161_SCR_INIT             0x0610
-
-/* DM9161 Specified Configuration and Status Register */
-#define MII_DM9161_SCSR                 0x11
-#define MII_DM9161_SCSR_100F            0x8000
-#define MII_DM9161_SCSR_100H            0x4000
-#define MII_DM9161_SCSR_10F             0x2000
-#define MII_DM9161_SCSR_10H             0x1000
-
-/* DM9161 Interrupt Register */
-#define MII_DM9161_INTR                 0x15
-#define MII_DM9161_INTR_PEND            0x8000
-#define MII_DM9161_INTR_DPLX_MASK       0x0800
-#define MII_DM9161_INTR_SPD_MASK        0x0400
-#define MII_DM9161_INTR_LINK_MASK       0x0200
-#define MII_DM9161_INTR_MASK            0x0100
-#define MII_DM9161_INTR_DPLX_CHANGE     0x0010
-#define MII_DM9161_INTR_SPD_CHANGE      0x0008
-#define MII_DM9161_INTR_LINK_CHANGE     0x0004
-#define MII_DM9161_INTR_INIT            0x0000
-#define MII_DM9161_INTR_STOP    \
-(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
- | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
-
-/* DM9161 10BT Configuration/Status */
-#define MII_DM9161_10BTCSR              0x12
-#define MII_DM9161_10BTCSR_INIT         0x7800
-
-#define MII_BASIC_FEATURES    (SUPPORTED_10baseT_Half | \
-                 SUPPORTED_10baseT_Full | \
-                 SUPPORTED_100baseT_Half | \
-                 SUPPORTED_100baseT_Full | \
-                 SUPPORTED_Autoneg | \
-                 SUPPORTED_TP | \
-                 SUPPORTED_MII)
-
-#define MII_GBIT_FEATURES    (MII_BASIC_FEATURES | \
-                 SUPPORTED_1000baseT_Half | \
-                 SUPPORTED_1000baseT_Full)
-
-#define MII_READ_COMMAND                0x00000001
-
-#define MII_INTERRUPT_DISABLED          0x0
-#define MII_INTERRUPT_ENABLED           0x1
-/* Taken from mii_if_info and sungem_phy.h */
-struct ugeth_mii_info {
-       /* Information about the PHY type */
-       /* And management functions */
-       struct phy_info *phyinfo;
-
-       struct ucc_mii_mng *mii_regs;
-
-       /* forced speed & duplex (no autoneg)
-        * partner speed & duplex & pause (autoneg)
-        */
-       int speed;
-       int duplex;
-       int pause;
-
-       /* The most recently read link state */
-       int link;
-
-       /* Enabled Interrupts */
-       u32 interrupts;
-
-       u32 advertising;
-       int autoneg;
-       int mii_id;
-
-       /* private data pointer */
-       /* For use by PHYs to maintain extra state */
-       void *priv;
-
-       /* Provided by host chip */
-       struct net_device *dev;
-
-       /* A lock to ensure that only one thing can read/write
-        * the MDIO bus at a time */
-       spinlock_t mdio_lock;
-
-       /* Provided by ethernet driver */
-       int (*mdio_read) (struct net_device * dev, int mii_id, int reg);
-       void (*mdio_write) (struct net_device * dev, int mii_id, int reg,
-                           int val);
-};
-
-/* struct phy_info: a structure which defines attributes for a PHY
- *
- * id will contain a number which represents the PHY.  During
- * startup, the driver will poll the PHY to find out what its
- * UID--as defined by registers 2 and 3--is.  The 32-bit result
- * gotten from the PHY will be ANDed with phy_id_mask to
- * discard any bits which may change based on revision numbers
- * unimportant to functionality
- *
- * There are 6 commands which take a ugeth_mii_info structure.
- * Each PHY must declare config_aneg, and read_status.
- */
-struct phy_info {
-       u32 phy_id;
-       char *name;
-       unsigned int phy_id_mask;
-       u32 features;
-
-       /* Called to initialize the PHY */
-       int (*init) (struct ugeth_mii_info * mii_info);
-
-       /* Called to suspend the PHY for power */
-       int (*suspend) (struct ugeth_mii_info * mii_info);
-
-       /* Reconfigures autonegotiation (or disables it) */
-       int (*config_aneg) (struct ugeth_mii_info * mii_info);
-
-       /* Determines the negotiated speed and duplex */
-       int (*read_status) (struct ugeth_mii_info * mii_info);
-
-       /* Clears any pending interrupts */
-       int (*ack_interrupt) (struct ugeth_mii_info * mii_info);
-
-       /* Enables or disables interrupts */
-       int (*config_intr) (struct ugeth_mii_info * mii_info);
-
-       /* Clears up any memory if needed */
-       void (*close) (struct ugeth_mii_info * mii_info);
-};
-
-struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info);
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value);
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum);
-void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info);
-void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
-                                u32 interrupts);
-
-struct dm9161_private {
-       struct timer_list timer;
-       int resetdone;
-};
-
-#endif                         /* __UCC_GETH_PHY_H__ */
index 00e0aaadabccd326ead25b186ca03b0334636a47..9ec6cf2e510ee32510fd3002f762476efe183031 100644 (file)
 struct hdlc_header {
        u8 address;
        u8 control;
-       u16 protocol;
+       __be16 protocol;
 }__attribute__ ((packed));
 
 
 struct cisco_packet {
-       u32 type;               /* code */
-       u32 par1;
-       u32 par2;
-       u16 rel;                /* reliability */
-       u32 time;
+       __be32 type;            /* code */
+       __be32 par1;
+       __be32 par2;
+       __be16 rel;             /* reliability */
+       __be32 time;
 }__attribute__ ((packed));
 #define        CISCO_PACKET_LEN        18
 #define        CISCO_BIG_PACKET_LEN    20
@@ -97,7 +97,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
 
 
 static void cisco_keepalive_send(struct net_device *dev, u32 type,
-                                u32 par1, u32 par2)
+                                __be32 par1, __be32 par2)
 {
        struct sk_buff *skb;
        struct cisco_packet *data;
@@ -115,9 +115,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
        data = (struct cisco_packet*)(skb->data + 4);
 
        data->type = htonl(type);
-       data->par1 = htonl(par1);
-       data->par2 = htonl(par2);
-       data->rel = 0xFFFF;
+       data->par1 = par1;
+       data->par2 = par2;
+       data->rel = __constant_htons(0xFFFF);
        /* we will need do_div here if 1000 % HZ != 0 */
        data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
 
@@ -193,7 +193,7 @@ static int cisco_rx(struct sk_buff *skb)
                case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
                        in_dev = dev->ip_ptr;
                        addr = 0;
-                       mask = ~0; /* is the mask correct? */
+                       mask = __constant_htonl(~0); /* is the mask correct? */
 
                        if (in_dev != NULL) {
                                struct in_ifaddr **ifap = &in_dev->ifa_list;
@@ -245,7 +245,7 @@ static int cisco_rx(struct sk_buff *skb)
        } /* switch(protocol) */
 
        printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name,
-              data->protocol);
+              ntohs(data->protocol));
        dev_kfree_skb_any(skb);
        return NET_RX_DROP;
 
@@ -270,8 +270,9 @@ static void cisco_timer(unsigned long arg)
                netif_dormant_on(dev);
        }
 
-       cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq,
-                            state(hdlc)->rxseq);
+       cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
+                            htonl(++state(hdlc)->txseq),
+                            htonl(state(hdlc)->rxseq));
        state(hdlc)->request_sent = 1;
        state(hdlc)->timer.expires = jiffies +
                state(hdlc)->settings.interval * HZ;
index aeb2789adf264f8c8126ececc7bed28e5ee37628..15b6e07a4382020a4d8fc9aaeb721c3dd0953732 100644 (file)
@@ -288,31 +288,31 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
        struct sk_buff *skb = *skb_p;
 
        switch (skb->protocol) {
-       case __constant_ntohs(NLPID_CCITT_ANSI_LMI):
+       case __constant_htons(NLPID_CCITT_ANSI_LMI):
                head_len = 4;
                skb_push(skb, head_len);
                skb->data[3] = NLPID_CCITT_ANSI_LMI;
                break;
 
-       case __constant_ntohs(NLPID_CISCO_LMI):
+       case __constant_htons(NLPID_CISCO_LMI):
                head_len = 4;
                skb_push(skb, head_len);
                skb->data[3] = NLPID_CISCO_LMI;
                break;
 
-       case __constant_ntohs(ETH_P_IP):
+       case __constant_htons(ETH_P_IP):
                head_len = 4;
                skb_push(skb, head_len);
                skb->data[3] = NLPID_IP;
                break;
 
-       case __constant_ntohs(ETH_P_IPV6):
+       case __constant_htons(ETH_P_IPV6):
                head_len = 4;
                skb_push(skb, head_len);
                skb->data[3] = NLPID_IPV6;
                break;
 
-       case __constant_ntohs(ETH_P_802_3):
+       case __constant_htons(ETH_P_802_3):
                head_len = 10;
                if (skb_headroom(skb) < head_len) {
                        struct sk_buff *skb2 = skb_realloc_headroom(skb,
@@ -340,7 +340,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
                skb->data[5] = FR_PAD;
                skb->data[6] = FR_PAD;
                skb->data[7] = FR_PAD;
-               *(u16*)(skb->data + 8) = skb->protocol;
+               *(__be16*)(skb->data + 8) = skb->protocol;
        }
 
        dlci_to_q922(skb->data, dlci);
@@ -974,8 +974,8 @@ static int fr_rx(struct sk_buff *skb)
 
        } else if (skb->len > 10 && data[3] == FR_PAD &&
                   data[4] == NLPID_SNAP && data[5] == FR_PAD) {
-               u16 oui = ntohs(*(u16*)(data + 6));
-               u16 pid = ntohs(*(u16*)(data + 8));
+               u16 oui = ntohs(*(__be16*)(data + 6));
+               u16 pid = ntohs(*(__be16*)(data + 8));
                skb_pull(skb, 10);
 
                switch ((((u32)oui) << 16) | pid) {
@@ -1127,7 +1127,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
                memcpy(dev->dev_addr, "\x00\x01", 2);
                 get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
        } else {
-               *(u16*)dev->dev_addr = htons(dlci);
+               *(__be16*)dev->dev_addr = htons(dlci);
                dlci_to_q922(dev->broadcast, dlci);
        }
        dev->hard_start_xmit = pvc_xmit;
index 4426841b2be68e0be492dfa4ea5613307d9bac0a..c4b3dc291a5a11898c95c38917b892cbb835e499 100644 (file)
@@ -265,6 +265,19 @@ config IPW2200_DEBUG
 
          If you are not sure, say N here.
 
+config LIBERTAS_USB
+       tristate "Marvell Libertas 8388 802.11a/b/g cards"
+       depends on NET_RADIO && USB
+       select FW_LOADER
+       ---help---
+         A driver for Marvell Libertas 8388 USB devices.
+
+config LIBERTAS_USB_DEBUG
+       bool "Enable full debugging output in the Libertas USB module."
+       depends on LIBERTAS_USB
+       ---help---
+         Debugging support.
+
 config AIRO
        tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
        depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN)
index c613af17a159b62269c7460d24066bceae15e7a5..d2124602263bf8f193d575428f1fc3b11825cece 100644 (file)
@@ -43,3 +43,4 @@ obj-$(CONFIG_PCMCIA_RAYCS)    += ray_cs.o
 obj-$(CONFIG_PCMCIA_WL3501)    += wl3501_cs.o
 
 obj-$(CONFIG_USB_ZD1201)       += zd1201.o
+obj-$(CONFIG_LIBERTAS_USB)     += libertas/
diff --git a/drivers/net/wireless/README b/drivers/net/wireless/README
deleted file mode 100644 (file)
index 0c274bf..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-       README
-       ------
-
-       This directory is mostly for Wireless LAN drivers, in their
-various incarnations (ISA, PCI, Pcmcia...).
-       This separate directory is needed because a lot of driver work
-on different bus (typically PCI + Pcmcia) and share 95% of the
-code. This allow the code and the config options to be in one single
-place instead of scattered all over the driver tree, which is never
-100% satisfactory.
-
-       Note : if you want more info on the topic of Wireless LANs,
-you are kindly invited to have a look at the Wireless Howto :
-               http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
-       Some Wireless LAN drivers, like orinoco_cs, require the use of
-Wireless Tools to be configured :
-               http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html
-
-       Special notes for distribution maintainers :
-       1) wvlan_cs will be discontinued soon in favor of orinoco_cs
-       2) Please add Wireless Tools support in your scripts
-
-       Have fun...
-
-       Jean
index 7fe0a61091a65bd33665e4df2943caddd325692a..f21bbafcb7288d3b79ba058c9276ec3a092de2d4 100644 (file)
@@ -1145,6 +1145,7 @@ static void airo_networks_free(struct airo_info *ai);
 struct airo_info {
        struct net_device_stats stats;
        struct net_device             *dev;
+       struct list_head              dev_list;
        /* Note, we can have MAX_FIDS outstanding.  FIDs are 16-bits, so we
           use the high bit to mark whether it is in use. */
 #define MAX_FIDS 6
@@ -2360,6 +2361,21 @@ static int airo_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
+static LIST_HEAD(airo_devices);
+
+static void add_airo_dev(struct airo_info *ai)
+{
+       /* Upper layers already keep track of PCI devices,
+        * so we only need to remember our non-PCI cards. */
+       if (!ai->pci)
+               list_add_tail(&ai->dev_list, &airo_devices);
+}
+
+static void del_airo_dev(struct airo_info *ai)
+{
+       if (!ai->pci)
+               list_del(&ai->dev_list);
+}
 
 static int airo_close(struct net_device *dev) {
        struct airo_info *ai = dev->priv;
@@ -2381,8 +2397,6 @@ static int airo_close(struct net_device *dev) {
        return 0;
 }
 
-static void del_airo_dev( struct net_device *dev );
-
 void stop_airo_card( struct net_device *dev, int freeres )
 {
        struct airo_info *ai = dev->priv;
@@ -2434,14 +2448,12 @@ void stop_airo_card( struct net_device *dev, int freeres )
                }
         }
        crypto_free_cipher(ai->tfm);
-       del_airo_dev( dev );
+       del_airo_dev(ai);
        free_netdev( dev );
 }
 
 EXPORT_SYMBOL(stop_airo_card);
 
-static int add_airo_dev( struct net_device *dev );
-
 static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
 {
        memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
@@ -2740,8 +2752,6 @@ static int airo_networks_allocate(struct airo_info *ai)
 
 static void airo_networks_free(struct airo_info *ai)
 {
-       if (!ai->networks)
-               return;
        kfree(ai->networks);
        ai->networks = NULL;
 }
@@ -2816,12 +2826,10 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
        if (IS_ERR(ai->airo_thread_task))
                goto err_out_free;
        ai->tfm = NULL;
-       rc = add_airo_dev( dev );
-       if (rc)
-               goto err_out_thr;
+       add_airo_dev(ai);
 
        if (airo_networks_allocate (ai))
-               goto err_out_unlink;
+               goto err_out_thr;
        airo_networks_initialize (ai);
 
        /* The Airo-specific entries in the device structure. */
@@ -2937,9 +2945,8 @@ err_out_irq:
        free_irq(dev->irq, dev);
 err_out_nets:
        airo_networks_free(ai);
-err_out_unlink:
-       del_airo_dev(dev);
 err_out_thr:
+       del_airo_dev(ai);
        set_bit(JOB_DIE, &ai->jobs);
        kthread_stop(ai->airo_thread_task);
 err_out_free:
@@ -5535,11 +5542,6 @@ static int proc_close( struct inode *inode, struct file *file )
        return 0;
 }
 
-static struct net_device_list {
-       struct net_device *dev;
-       struct net_device_list *next;
-} *airo_devices;
-
 /* Since the card doesn't automatically switch to the right WEP mode,
    we will make it do it.  If the card isn't associated, every secs we
    will switch WEP modes to see if that will help.  If the card is
@@ -5582,26 +5584,6 @@ static void timer_func( struct net_device *dev ) {
        apriv->expires = RUN_AT(HZ*3);
 }
 
-static int add_airo_dev( struct net_device *dev ) {
-       struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL );
-       if ( !node )
-               return -ENOMEM;
-
-       node->dev = dev;
-       node->next = airo_devices;
-       airo_devices = node;
-
-       return 0;
-}
-
-static void del_airo_dev( struct net_device *dev ) {
-       struct net_device_list **p = &airo_devices;
-       while( *p && ( (*p)->dev != dev ) )
-               p = &(*p)->next;
-       if ( *p && (*p)->dev == dev )
-               *p = (*p)->next;
-}
-
 #ifdef CONFIG_PCI
 static int __devinit airo_pci_probe(struct pci_dev *pdev,
                                    const struct pci_device_id *pent)
@@ -5625,6 +5607,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
 
 static void __devexit airo_pci_remove(struct pci_dev *pdev)
 {
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       airo_print_info(dev->name, "Unregistering...");
+       stop_airo_card(dev, 1);
 }
 
 static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -5750,9 +5736,11 @@ static int __init airo_init_module( void )
 
 static void __exit airo_cleanup_module( void )
 {
-       while( airo_devices ) {
-               airo_print_info(airo_devices->dev->name, "Unregistering...\n");
-               stop_airo_card( airo_devices->dev, 1 );
+       struct airo_info *ai;
+       while(!list_empty(&airo_devices)) {
+               ai = list_entry(airo_devices.next, struct airo_info, dev_list);
+               airo_print_info(ai->dev->name, "Unregistering...");
+               stop_airo_card(ai->dev, 1);
        }
 #ifdef CONFIG_PCI
        pci_unregister_driver(&airo_driver);
index 95ff175d8f334227485ee75e995c8993f290f9eb..f8483c179e4c9d4a1c6dcaf23bab05da0423e9ac 100644 (file)
 #define BCM43xx_SBTMSTATELOW_REJECT            0x02
 #define BCM43xx_SBTMSTATELOW_CLOCK             0x10000
 #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK  0x20000
+#define BCM43xx_SBTMSTATELOW_G_MODE_ENABLE     0x20000000
 
 /* sbtmstatehigh state flags */
 #define BCM43xx_SBTMSTATEHIGH_SERROR           0x00000001
 #define BCM43xx_SBTMSTATEHIGH_BUSY             0x00000004
 #define BCM43xx_SBTMSTATEHIGH_TIMEOUT          0x00000020
+#define BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL      0x00010000
+#define BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL      0x00020000
 #define BCM43xx_SBTMSTATEHIGH_COREFLAGS                0x1FFF0000
 #define BCM43xx_SBTMSTATEHIGH_DMA64BIT         0x10000000
 #define BCM43xx_SBTMSTATEHIGH_GATEDCLK         0x20000000
index c947025d655f6e9e3c9bd809c8f716bde2215555..d2df6a0100a18d2b42f36e90481c06f8ff481cf6 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/netdevice.h>
 #include <linux/pci.h>
 #include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <linux/utsname.h>
 
 
 static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -40,7 +40,7 @@ static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *
        struct bcm43xx_private *bcm = bcm43xx_priv(dev);
 
        strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
-       strncpy(info->version, UTS_RELEASE, sizeof(info->version));
+       strncpy(info->version, utsname()->release, sizeof(info->version));
        strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
 }
 
index a38e7eec0e62174e0005a0971ae6fa6137b61058..5e96bca6730a470df027e7f10a62899f1c331cf5 100644 (file)
@@ -1407,7 +1407,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
                                & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
        } else {
                if (connect_phy)
-                       flags |= 0x20000000;
+                       flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
                bcm43xx_phy_connect(bcm, connect_phy);
                bcm43xx_core_enable(bcm, flags);
                bcm43xx_write16(bcm, 0x03E6, 0x0000);
@@ -3604,7 +3604,7 @@ int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
                u32 sbtmstatelow;
 
                sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-               sbtmstatelow |= 0x20000000;
+               sbtmstatelow |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
                bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
        }
        err = wireless_core_up(bcm, 1);
index 72529a440f15eab7c47177fd23e96e9cdc7de5e8..b37f1e348700c9c775dce61695bd2bde12101b6e 100644 (file)
@@ -168,16 +168,16 @@ int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect)
 
        flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
        if (connect) {
-               if (!(flags & 0x00010000))
+               if (!(flags & BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL))
                        return -ENODEV;
                flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-               flags |= (0x800 << 18);
+               flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
                bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
        } else {
-               if (!(flags & 0x00020000))
+               if (!(flags & BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL))
                        return -ENODEV;
                flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-               flags &= ~(0x800 << 18);
+               flags &= ~BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
                bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
        }
 out:
@@ -300,16 +300,20 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm)
 
        if (phy->rev > 2) {
                bcm43xx_phy_write(bcm, 0x0422, 0x287A);
-               bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); 
+               bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420)
+                                 & 0x0FFF) | 0x3000);
        }
                
-       bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874);
+       bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080)
+                                       | 0x7874);
        bcm43xx_phy_write(bcm, 0x048E, 0x1C00);
 
        if (phy->rev == 1) {
-               bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600);
+               bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB)
+                                 & 0xF0FF) | 0x0600);
                bcm43xx_phy_write(bcm, 0x048B, 0x005E);
-               bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E);
+               bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C)
+                                 & 0xFF00) | 0x001E);
                bcm43xx_phy_write(bcm, 0x048D, 0x0002);
        }
 
@@ -335,7 +339,8 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
        if (phy->rev == 1) {
                bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
                bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
-                                 (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340);
+                                 (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+                                 & 0xFC3F) | 0x0340);
                bcm43xx_phy_write(bcm, 0x042C, 0x005A);
                bcm43xx_phy_write(bcm, 0x0427, 0x001A);
 
index 1f321ef42be8d50438f71bee3d78d358b4e3bd77..73118364b55270ec902345aedb387744636dc9c1 100644 (file)
@@ -48,6 +48,10 @@ void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm);
                local_irq_restore(flags);       \
        } while (0)
 
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+        (((phy)->rev > 1) || ((phy)->connected))
+
 u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset);
 void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
 
index 4025dd0089d2dad6041bf096f75ff14acdd92b50..6a109f4a1b719ca4aaab645f127f2f91b5eb5e25 100644 (file)
@@ -1343,11 +1343,110 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
        return ret;
 }
 
+#define LPD(L, P, D)    (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd)
+{
+       struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+       struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+       u16 loop_or = 0;
+       u16 adj_loopback_gain = phy->loopback_gain[0];
+       u8 loop;
+       u16 extern_lna_control;
+
+       if (!phy->connected)
+               return 0;
+       if (!has_loopback_gain(phy)) {
+               if (phy->rev < 7 || !(bcm->sprom.boardflags
+                   & BCM43xx_BFL_EXTLNA)) {
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x0FB2;
+                       case LPD(0, 0, 1):
+                               return 0x00B2;
+                       case LPD(1, 0, 1):
+                               return 0x30B2;
+                       case LPD(1, 0, 0):
+                               return 0x30B3;
+                       default:
+                               assert(0);
+                       }
+               } else {
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x8FB2;
+                       case LPD(0, 0, 1):
+                               return 0x80B2;
+                       case LPD(1, 0, 1):
+                               return 0x20B2;
+                       case LPD(1, 0, 0):
+                               return 0x20B3;
+                       default:
+                               assert(0);
+                       }
+               }
+       } else {
+               if (radio->revision == 8)
+                       adj_loopback_gain += 0x003E;
+               else
+                       adj_loopback_gain += 0x0026;
+               if (adj_loopback_gain >= 0x46) {
+                       adj_loopback_gain -= 0x46;
+                       extern_lna_control = 0x3000;
+               } else if (adj_loopback_gain >= 0x3A) {
+                       adj_loopback_gain -= 0x3A;
+                       extern_lna_control = 0x2000;
+               } else if (adj_loopback_gain >= 0x2E) {
+                       adj_loopback_gain -= 0x2E;
+                       extern_lna_control = 0x1000;
+               } else {
+                       adj_loopback_gain -= 0x10;
+                       extern_lna_control = 0x0000;
+               }
+               for (loop = 0; loop < 16; loop++) {
+                       u16 tmp = adj_loopback_gain - 6 * loop;
+                       if (tmp < 6)
+                               break;
+               }
+
+               loop_or = (loop << 8) | extern_lna_control;
+               if (phy->rev >= 7 && bcm->sprom.boardflags
+                   & BCM43xx_BFL_EXTLNA) {
+                       if (extern_lna_control)
+                               loop_or |= 0x8000;
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x8F92;
+                       case LPD(0, 0, 1):
+                               return (0x8092 | loop_or);
+                       case LPD(1, 0, 1):
+                               return (0x2092 | loop_or);
+                       case LPD(1, 0, 0):
+                               return (0x2093 | loop_or);
+                       default:
+                               assert(0);
+                       }
+               } else {
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x0F92;
+                       case LPD(0, 0, 1):
+                       case LPD(1, 0, 1):
+                               return (0x0092 | loop_or);
+                       case LPD(1, 0, 0):
+                               return (0x0093 | loop_or);
+                       default:
+                               assert(0);
+                       }
+               }
+       }
+       return 0;
+}
+
 u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
 {
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
        struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
-       u16 backup[19] = { 0 };
+       u16 backup[21] = { 0 };
        u16 ret;
        u16 i, j;
        u32 tmp1 = 0, tmp2 = 0;
@@ -1373,19 +1472,36 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                        backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
                        backup[9] = bcm43xx_phy_read(bcm, 0x0802);
                        bcm43xx_phy_write(bcm, 0x0814,
-                                         (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
+                                         (bcm43xx_phy_read(bcm, 0x0814)
+                                         | 0x0003));
                        bcm43xx_phy_write(bcm, 0x0815,
-                                         (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));    
+                                         (bcm43xx_phy_read(bcm, 0x0815)
+                                         & 0xFFFC));
                        bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
-                                         (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
+                                         (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+                                         & 0x7FFF));
                        bcm43xx_phy_write(bcm, 0x0802,
                                          (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
-                       bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
-                       bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
+                       if (phy->rev > 1) { /* loopback gain enabled */
+                               backup[19] = bcm43xx_phy_read(bcm, 0x080F);
+                               backup[20] = bcm43xx_phy_read(bcm, 0x0810);
+                               if (phy->rev >= 3)
+                                       bcm43xx_phy_write(bcm, 0x080F, 0xC020);
+                               else
+                                       bcm43xx_phy_write(bcm, 0x080F, 0x8020);
+                               bcm43xx_phy_write(bcm, 0x0810, 0x0000);
+                       }
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
+                       if (phy->rev < 7 || !(bcm->sprom.boardflags
+                           & BCM43xx_BFL_EXTLNA))
+                               bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
+                       else
+                               bcm43xx_phy_write(bcm, 0x0811, 0x09B3);
                }
-               bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
-                               (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
        }
+       bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+                       (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
        backup[10] = bcm43xx_phy_read(bcm, 0x0035);
        bcm43xx_phy_write(bcm, 0x0035,
                          (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
@@ -1397,10 +1513,12 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                bcm43xx_write16(bcm, 0x03E6, 0x0122);
        } else {
                if (phy->analog >= 2)
-                       bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003)
-                                       & 0xFFBF) | 0x0040);
+                       bcm43xx_phy_write(bcm, 0x0003,
+                                         (bcm43xx_phy_read(bcm, 0x0003)
+                                         & 0xFFBF) | 0x0040);
                bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
-                               (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
+                               (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+                               | 0x2000));
        }
 
        ret = bcm43xx_radio_calibrationvalue(bcm);
@@ -1408,16 +1526,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
        if (phy->type == BCM43xx_PHYTYPE_B)
                bcm43xx_radio_write16(bcm, 0x0078, 0x0026);
 
+       if (phy->connected)
+               bcm43xx_phy_write(bcm, 0x0812,
+                                 bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
        bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
        bcm43xx_phy_write(bcm, 0x002B, 0x1403);
        if (phy->connected)
-               bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
+               bcm43xx_phy_write(bcm, 0x0812,
+                                 bcm43xx_get_812_value(bcm, LPD(0, 0, 1)));
        bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
        bcm43xx_radio_write16(bcm, 0x0051,
                              (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
-       bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
-       bcm43xx_radio_write16(bcm, 0x0043,
-                             (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009);
+       if (radio->revision == 8)
+               bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
+       else {
+               bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+               bcm43xx_radio_write16(bcm, 0x0043,
+                                     (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0)
+                                     | 0x0009);
+       }
        bcm43xx_phy_write(bcm, 0x0058, 0x0000);
 
        for (i = 0; i < 16; i++) {
@@ -1425,21 +1552,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                bcm43xx_phy_write(bcm, 0x0059, 0xC810);
                bcm43xx_phy_write(bcm, 0x0058, 0x000D);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
                bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
                udelay(10);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
                bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
                udelay(10);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 0)));
                bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
-               udelay(10);
+               udelay(20);
                tmp1 += bcm43xx_phy_read(bcm, 0x002D);
                bcm43xx_phy_write(bcm, 0x0058, 0x0000);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
                bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
        }
 
@@ -1457,21 +1588,29 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                        bcm43xx_phy_write(bcm, 0x0059, 0xC810);
                        bcm43xx_phy_write(bcm, 0x0058, 0x000D);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 1)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
                        udelay(10);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 1)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
                        udelay(10);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 0)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
                        udelay(10);
                        tmp2 += bcm43xx_phy_read(bcm, 0x002D);
                        bcm43xx_phy_write(bcm, 0x0058, 0x0000);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 1)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
                }
                tmp2++;
@@ -1497,15 +1636,20 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                bcm43xx_phy_write(bcm, 0x0030, backup[2]);
                bcm43xx_write16(bcm, 0x03EC, backup[3]);
        } else {
-               bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
-                               (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
                if (phy->connected) {
+                       bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+                                       (bcm43xx_read16(bcm,
+                                       BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
                        bcm43xx_phy_write(bcm, 0x0811, backup[4]);
                        bcm43xx_phy_write(bcm, 0x0812, backup[5]);
                        bcm43xx_phy_write(bcm, 0x0814, backup[6]);
                        bcm43xx_phy_write(bcm, 0x0815, backup[7]);
                        bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
                        bcm43xx_phy_write(bcm, 0x0802, backup[9]);
+                       if (phy->rev > 1) {
+                               bcm43xx_phy_write(bcm, 0x080F, backup[19]);
+                               bcm43xx_phy_write(bcm, 0x0810, backup[20]);
+                       }
                }
        }
        if (i >= 15)
index 4ca8a27b8c55bdf773c5edcbda979e02fe4c8ee8..5b3abd54d0e504a03b22ff1e9f33ff46a3b17207 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Intersil Prism2 driver with Host AP (software access point) support
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
  * This file is to be included into hostap.c when S/W AP functionality is
  * compiled.
index 01624005d808f541ae30f762ab5e4dad1785ff8e..b31e6a05f23cc5a97a5b35fa448a12896eed1ed9 100644 (file)
@@ -368,9 +368,9 @@ enum {
 
 #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
 #define PRISM2_HOSTAPD_RID_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+offsetof(struct prism2_hostapd_param, u.rid.data)
 #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+offsetof(struct prism2_hostapd_param, u.generic_elem.data)
 
 /* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
  */
index 8d8f4b9b8b07a032ef3c04ac1b928ca4187c289e..ee1532b62e42e1c8d74075cdc86f7faab09984e4 100644 (file)
@@ -22,7 +22,7 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static dev_info_t dev_info = "hostap_cs";
 
 MODULE_AUTHOR("Jouni Malinen");
@@ -838,6 +838,8 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
        PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
        PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF",
+                                        0x2d858104),
        PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
                                         0x74c5e40d),
        PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
@@ -848,6 +850,11 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
                "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P",
                "Eval-RevA",
                0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e),
+       /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */
+       PCMCIA_DEVICE_PROD_ID1234(
+               "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10",
+               "A3",
+               0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52),
        PCMCIA_DEVICE_PROD_ID123(
                "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
                0xe6ec52ce, 0x08649af2, 0x4b74baa0),
index fb01fb95a9f041e285a9cfa48a41d5bc4b67657e..959887b70ca7bf1d7fc8b7cc8295054a52410db3 100644 (file)
@@ -3,8 +3,8 @@
  * Intersil Prism2/2.5/3.
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
index 1f9edd91565d26c8304d2f18872c8e1ebf2894f3..4743426cf6add721905919080ff5ab477c9542bb 100644 (file)
@@ -3,8 +3,8 @@
  * Intersil Prism2/2.5/3 - hostap.o module, common routines
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
index c4f6020baa9ee7d12bde7e27ab3aebac4bc9f842..db4899ed4bb1211d4b4a9b0386f32a794638a041 100644 (file)
@@ -20,7 +20,7 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static char *dev_info = "hostap_pci";
 
 
index e235e06478970d2e240986be13e96930981942db..f0fd5ecdb24dceb0f2ac8316afbbcbf17a875b85 100644 (file)
@@ -23,7 +23,7 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static char *dev_info = "hostap_plx";
 
 
index 9137a4dd02ebb4507f66f0d95237c171c9ac74a3..d51daf87450f4e81711dbbedb588f9dd70cce8bf 100644 (file)
@@ -28,8 +28,8 @@
 
   Portions of this file are based on the Host AP project,
   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
-    <jkmaline@cc.hut.fi>
-  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+    <j@w1.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
 
   Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
   ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
index 4839a45098cbc0e9cc759551ef0951d96011fd1d..7cb2052a55a5e085d73605c40fa8db4f78e91c72 100644 (file)
@@ -1847,6 +1847,52 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr,
 static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO,
                   show_net_stats, store_net_stats);
 
+static ssize_t show_channels(struct device *d,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       struct ipw_priv *priv = dev_get_drvdata(d);
+       const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
+       int len = 0, i;
+
+       len = sprintf(&buf[len],
+                     "Displaying %d channels in 2.4Ghz band "
+                     "(802.11bg):\n", geo->bg_channels);
+
+       for (i = 0; i < geo->bg_channels; i++) {
+               len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n",
+                              geo->bg[i].channel,
+                              geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ?
+                              " (radar spectrum)" : "",
+                              ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) ||
+                               (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT))
+                              ? "" : ", IBSS",
+                              geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+                              "passive only" : "active/passive",
+                              geo->bg[i].flags & IEEE80211_CH_B_ONLY ?
+                              "B" : "B/G");
+       }
+
+       len += sprintf(&buf[len],
+                      "Displaying %d channels in 5.2Ghz band "
+                      "(802.11a):\n", geo->a_channels);
+       for (i = 0; i < geo->a_channels; i++) {
+               len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n",
+                              geo->a[i].channel,
+                              geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ?
+                              " (radar spectrum)" : "",
+                              ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) ||
+                               (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT))
+                              ? "" : ", IBSS",
+                              geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+                              "passive only" : "active/passive");
+       }
+
+       return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
 static void notify_wx_assoc_event(struct ipw_priv *priv)
 {
        union iwreq_data wrqu;
@@ -11383,6 +11429,7 @@ static struct attribute *ipw_sysfs_entries[] = {
        &dev_attr_led.attr,
        &dev_attr_speed_scan.attr,
        &dev_attr_net_stats.attr,
+       &dev_attr_channels.attr,
 #ifdef CONFIG_IPW2200_PROMISCUOUS
        &dev_attr_rtap_iface.attr,
        &dev_attr_rtap_filter.attr,
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
new file mode 100644 (file)
index 0000000..e0ecc4d
--- /dev/null
@@ -0,0 +1,754 @@
+/**
+  * This file contains functions for 802.11D.
+  */
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/wireless.h>
+
+#include "host.h"
+#include "decl.h"
+#include "11d.h"
+#include "dev.h"
+#include "wext.h"
+
+#define TX_PWR_DEFAULT 10
+
+static struct region_code_mapping region_code_mapping[] = {
+       {"US ", 0x10},          /* US FCC      */
+       {"CA ", 0x10},          /* IC Canada   */
+       {"SG ", 0x10},          /* Singapore   */
+       {"EU ", 0x30},          /* ETSI        */
+       {"AU ", 0x30},          /* Australia   */
+       {"KR ", 0x30},          /* Republic Of Korea */
+       {"ES ", 0x31},          /* Spain       */
+       {"FR ", 0x32},          /* France      */
+       {"JP ", 0x40},          /* Japan       */
+};
+
+/* Following 2 structure defines the supported channels */
+static struct chan_freq_power channel_freq_power_UN_BG[] = {
+       {1, 2412, TX_PWR_DEFAULT},
+       {2, 2417, TX_PWR_DEFAULT},
+       {3, 2422, TX_PWR_DEFAULT},
+       {4, 2427, TX_PWR_DEFAULT},
+       {5, 2432, TX_PWR_DEFAULT},
+       {6, 2437, TX_PWR_DEFAULT},
+       {7, 2442, TX_PWR_DEFAULT},
+       {8, 2447, TX_PWR_DEFAULT},
+       {9, 2452, TX_PWR_DEFAULT},
+       {10, 2457, TX_PWR_DEFAULT},
+       {11, 2462, TX_PWR_DEFAULT},
+       {12, 2467, TX_PWR_DEFAULT},
+       {13, 2472, TX_PWR_DEFAULT},
+       {14, 2484, TX_PWR_DEFAULT}
+};
+
+static u8 wlan_region_2_code(u8 * region)
+{
+       u8 i;
+       u8 size = sizeof(region_code_mapping)/
+                 sizeof(struct region_code_mapping);
+
+       for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
+               region[i] = toupper(region[i]);
+
+       for (i = 0; i < size; i++) {
+               if (!memcmp(region, region_code_mapping[i].region,
+                           COUNTRY_CODE_LEN))
+                       return (region_code_mapping[i].code);
+       }
+
+       /* default is US */
+       return (region_code_mapping[0].code);
+}
+
+static u8 *wlan_code_2_region(u8 code)
+{
+       u8 i;
+       u8 size = sizeof(region_code_mapping)
+                 / sizeof(struct region_code_mapping);
+       for (i = 0; i < size; i++) {
+               if (region_code_mapping[i].code == code)
+                       return (region_code_mapping[i].region);
+       }
+       /* default is US */
+       return (region_code_mapping[0].region);
+}
+
+/**
+ *  @brief This function finds the nrchan-th chan after the firstchan
+ *  @param band       band
+ *  @param firstchan  first channel number
+ *  @param nrchan   number of channels
+ *  @return          the nrchan-th chan number
+*/
+static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
+/*find the nrchan-th chan after the firstchan*/
+{
+       u8 i;
+       struct chan_freq_power *cfp;
+       u8 cfp_no;
+
+       cfp = channel_freq_power_UN_BG;
+       cfp_no = sizeof(channel_freq_power_UN_BG) /
+           sizeof(struct chan_freq_power);
+
+       for (i = 0; i < cfp_no; i++) {
+               if ((cfp + i)->channel == firstchan) {
+                       lbs_pr_debug(1, "firstchan found\n");
+                       break;
+               }
+       }
+
+       if (i < cfp_no) {
+               /*if beyond the boundary */
+               if (i + nrchan < cfp_no) {
+                       *chan = (cfp + i + nrchan)->channel;
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ *  @brief This function Checks if chan txpwr is learned from AP/IBSS
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d
+ *  @return                    TRUE; FALSE
+*/
+static u8 wlan_channel_known_11d(u8 chan,
+                         struct parsed_region_chan_11d * parsed_region_chan)
+{
+       struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
+       u8 nr_chan = parsed_region_chan->nr_chan;
+       u8 i = 0;
+
+       lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr,
+               sizeof(struct chan_power_11d) * nr_chan);
+
+       for (i = 0; i < nr_chan; i++) {
+               if (chan == chanpwr[i].chan) {
+                       lbs_pr_debug(1, "11D: Found Chan:%d\n", chan);
+                       return 1;
+               }
+       }
+
+       lbs_pr_debug(1, "11D: Not Find Chan:%d\n", chan);
+       return 0;
+}
+
+u32 libertas_chan_2_freq(u8 chan, u8 band)
+{
+       struct chan_freq_power *cf;
+       u16 cnt;
+       u16 i;
+       u32 freq = 0;
+
+       cf = channel_freq_power_UN_BG;
+       cnt =
+           sizeof(channel_freq_power_UN_BG) /
+           sizeof(struct chan_freq_power);
+
+       for (i = 0; i < cnt; i++) {
+               if (chan == cf[i].channel)
+                       freq = cf[i].freq;
+       }
+
+       return freq;
+}
+
+static int generate_domain_info_11d(struct parsed_region_chan_11d
+                                 *parsed_region_chan,
+                                 struct wlan_802_11d_domain_reg * domaininfo)
+{
+       u8 nr_subband = 0;
+
+       u8 nr_chan = parsed_region_chan->nr_chan;
+       u8 nr_parsedchan = 0;
+
+       u8 firstchan = 0, nextchan = 0, maxpwr = 0;
+
+       u8 i, flag = 0;
+
+       memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
+              COUNTRY_CODE_LEN);
+
+       lbs_pr_debug(1, "11D:nrchan=%d\n", nr_chan);
+       lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan,
+               sizeof(struct parsed_region_chan_11d));
+
+       for (i = 0; i < nr_chan; i++) {
+               if (!flag) {
+                       flag = 1;
+                       nextchan = firstchan =
+                           parsed_region_chan->chanpwr[i].chan;
+                       maxpwr = parsed_region_chan->chanpwr[i].pwr;
+                       nr_parsedchan = 1;
+                       continue;
+               }
+
+               if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
+                   parsed_region_chan->chanpwr[i].pwr == maxpwr) {
+                       nextchan++;
+                       nr_parsedchan++;
+               } else {
+                       domaininfo->subband[nr_subband].firstchan = firstchan;
+                       domaininfo->subband[nr_subband].nrchan =
+                           nr_parsedchan;
+                       domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
+                       nr_subband++;
+                       nextchan = firstchan =
+                           parsed_region_chan->chanpwr[i].chan;
+                       maxpwr = parsed_region_chan->chanpwr[i].pwr;
+               }
+       }
+
+       if (flag) {
+               domaininfo->subband[nr_subband].firstchan = firstchan;
+               domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
+               domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
+               nr_subband++;
+       }
+       domaininfo->nr_subband = nr_subband;
+
+       lbs_pr_debug(1, "nr_subband=%x\n", domaininfo->nr_subband);
+       lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo,
+               COUNTRY_CODE_LEN + 1 +
+               sizeof(struct ieeetypes_subbandset) * nr_subband);
+       return 0;
+}
+
+/**
+ *  @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
+ *  @param region_chan          pointer to struct region_channel
+ *  @param *parsed_region_chan  pointer to parsed_region_chan_11d
+ *  @return                    N/A
+*/
+static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan,
+                                         struct parsed_region_chan_11d *
+                                         parsed_region_chan)
+{
+       u8 i;
+       struct chan_freq_power *cfp;
+
+       if (region_chan == NULL) {
+               lbs_pr_debug(1, "11D: region_chan is NULL\n");
+               return;
+       }
+
+       cfp = region_chan->CFP;
+       if (cfp == NULL) {
+               lbs_pr_debug(1, "11D: cfp equal NULL \n");
+               return;
+       }
+
+       parsed_region_chan->band = region_chan->band;
+       parsed_region_chan->region = region_chan->region;
+       memcpy(parsed_region_chan->countrycode,
+              wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
+
+       lbs_pr_debug(1, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
+              parsed_region_chan->band);
+
+       for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
+               parsed_region_chan->chanpwr[i].chan = cfp->channel;
+               parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
+               lbs_pr_debug(1, "11D: Chan[%d] Pwr[%d]\n",
+                      parsed_region_chan->chanpwr[i].chan,
+                      parsed_region_chan->chanpwr[i].pwr);
+       }
+       parsed_region_chan->nr_chan = region_chan->nrcfp;
+
+       lbs_pr_debug(1, "11D: nrchan[%d]\n", parsed_region_chan->nr_chan);
+
+       return;
+}
+
+/**
+ *  @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
+ *  @param region               region ID
+ *  @param band                 band
+ *  @param chan                 chan
+ *  @return                    TRUE;FALSE
+*/
+static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
+{
+       struct chan_freq_power *cfp;
+       int cfp_no;
+       u8 idx;
+
+       ENTER();
+
+       cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
+       if (cfp == NULL)
+               return 0;
+
+       for (idx = 0; idx < cfp_no; idx++) {
+               if (chan == (cfp + idx)->channel) {
+                       /* If Mrvl Chip Supported? */
+                       if ((cfp + idx)->unsupported) {
+                               return 0;
+                       } else {
+                               return 1;
+                       }
+               }
+       }
+
+       /*chan is not in the region table */
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief This function checks if chan txpwr is learned from AP/IBSS
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d
+ *  @return                    0
+*/
+static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
+                                countryinfo,
+                                u8 band,
+                                struct parsed_region_chan_11d *
+                                parsed_region_chan)
+{
+       u8 nr_subband, nrchan;
+       u8 lastchan, firstchan;
+       u8 region;
+       u8 curchan = 0;
+
+       u8 idx = 0;             /*chan index in parsed_region_chan */
+
+       u8 j, i;
+
+       ENTER();
+
+       /*validation Rules:
+          1. valid region Code
+          2. First Chan increment
+          3. channel range no overlap
+          4. channel is valid?
+          5. channel is supported by region?
+          6. Others
+        */
+
+       lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30);
+
+       if ((*(countryinfo->countrycode)) == 0
+           || (countryinfo->len <= COUNTRY_CODE_LEN)) {
+               /* No region Info or Wrong region info: treat as No 11D info */
+               LEAVE();
+               return 0;
+       }
+
+       /*Step1: check region_code */
+       parsed_region_chan->region = region =
+           wlan_region_2_code(countryinfo->countrycode);
+
+       lbs_pr_debug(1, "regioncode=%x\n", (u8) parsed_region_chan->region);
+       lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
+               COUNTRY_CODE_LEN);
+
+       parsed_region_chan->band = band;
+
+       memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
+              COUNTRY_CODE_LEN);
+
+       nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
+           sizeof(struct ieeetypes_subbandset);
+
+       for (j = 0, lastchan = 0; j < nr_subband; j++) {
+
+               if (countryinfo->subband[j].firstchan <= lastchan) {
+                       /*Step2&3. Check First Chan Num increment and no overlap */
+                       lbs_pr_debug(1, "11D: Chan[%d>%d] Overlap\n",
+                              countryinfo->subband[j].firstchan, lastchan);
+                       continue;
+               }
+
+               firstchan = countryinfo->subband[j].firstchan;
+               nrchan = countryinfo->subband[j].nrchan;
+
+               for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
+                       /*step4: channel is supported? */
+
+                       if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
+                               /* Chan is not found in UN table */
+                               lbs_pr_debug(1, "chan is not supported: %d \n", i);
+                               break;
+                       }
+
+                       lastchan = curchan;
+
+                       if (wlan_region_chan_supported_11d
+                           (region, band, curchan)) {
+                               /*step5: Check if curchan is supported by mrvl in region */
+                               parsed_region_chan->chanpwr[idx].chan = curchan;
+                               parsed_region_chan->chanpwr[idx].pwr =
+                                   countryinfo->subband[j].maxtxpwr;
+                               idx++;
+                       } else {
+                               /*not supported and ignore the chan */
+                               lbs_pr_debug(1,
+                                      "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n",
+                                      i, curchan, region, band);
+                       }
+               }
+
+               /*Step6: Add other checking if any */
+
+       }
+
+       parsed_region_chan->nr_chan = idx;
+
+       lbs_pr_debug(1, "nrchan=%x\n", parsed_region_chan->nr_chan);
+       lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan,
+               2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief This function calculates the scan type for channels
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d
+ *  @return                    PASSIVE if chan is unknown; ACTIVE if chan is known
+*/
+u8 libertas_get_scan_type_11d(u8 chan,
+                         struct parsed_region_chan_11d * parsed_region_chan)
+{
+       u8 scan_type = cmd_scan_type_passive;
+
+       ENTER();
+
+       if (wlan_channel_known_11d(chan, parsed_region_chan)) {
+               lbs_pr_debug(1, "11D: Found and do Active Scan\n");
+               scan_type = cmd_scan_type_active;
+       } else {
+               lbs_pr_debug(1, "11D: Not Find and do Passive Scan\n");
+       }
+
+       LEAVE();
+       return scan_type;
+
+}
+
+void libertas_init_11d(wlan_private * priv)
+{
+       priv->adapter->enable11d = 0;
+       memset(&(priv->adapter->parsed_region_chan), 0,
+              sizeof(struct parsed_region_chan_11d));
+       return;
+}
+
+static int wlan_enable_11d(wlan_private * priv, u8 flag)
+{
+       int ret;
+
+       priv->adapter->enable11d = flag;
+
+       /* send cmd to FW to enable/disable 11D function in FW */
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_snmp_mib,
+                                   cmd_act_set,
+                                   cmd_option_waitforrsp,
+                                   OID_802_11D_ENABLE,
+                                   &priv->adapter->enable11d);
+       if (ret)
+               lbs_pr_debug(1, "11D: Fail to enable 11D \n");
+
+       return 0;
+}
+
+/**
+ *  @brief This function sets DOMAIN INFO to FW
+ *  @param priv       pointer to wlan_private
+ *  @return          0; -1
+*/
+static int set_domain_info_11d(wlan_private * priv)
+{
+       int ret;
+
+       if (!priv->adapter->enable11d) {
+               lbs_pr_debug(1, "11D: dnld domain Info with 11d disabled\n");
+               return 0;
+       }
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
+                                   cmd_act_set,
+                                   cmd_option_waitforrsp, 0, NULL);
+       if (ret)
+               lbs_pr_debug(1, "11D: Fail to dnld domain Info\n");
+
+       return ret;
+}
+
+/**
+ *  @brief This function setups scan channels
+ *  @param priv       pointer to wlan_private
+ *  @param band       band
+ *  @return          0
+*/
+int libertas_set_universaltable(wlan_private * priv, u8 band)
+{
+       wlan_adapter *adapter = priv->adapter;
+       u16 size = sizeof(struct chan_freq_power);
+       u16 i = 0;
+
+       memset(adapter->universal_channel, 0,
+              sizeof(adapter->universal_channel));
+
+       adapter->universal_channel[i].nrcfp =
+           sizeof(channel_freq_power_UN_BG) / size;
+       lbs_pr_debug(1, "11D: BG-band nrcfp=%d\n",
+              adapter->universal_channel[i].nrcfp);
+
+       adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
+       adapter->universal_channel[i].valid = 1;
+       adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+       adapter->universal_channel[i].band = band;
+       i++;
+
+       return 0;
+}
+
+/**
+ *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ *  @param priv       pointer to wlan_private
+ *  @param cmd        pointer to cmd buffer
+ *  @param cmdno      cmd ID
+ *  @param cmdOption  cmd action
+ *  @return          0
+*/
+int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+                                struct cmd_ds_command *cmd, u16 cmdno,
+                                u16 cmdoption)
+{
+       struct cmd_ds_802_11d_domain_info *pdomaininfo =
+           &cmd->params.domaininfo;
+       struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
+       wlan_adapter *adapter = priv->adapter;
+       u8 nr_subband = adapter->domainreg.nr_subband;
+
+       ENTER();
+
+       lbs_pr_debug(1, "nr_subband=%x\n", nr_subband);
+
+       cmd->command = cpu_to_le16(cmdno);
+       pdomaininfo->action = cpu_to_le16(cmdoption);
+       if (cmdoption == cmd_act_get) {
+               cmd->size =
+                   cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+               lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
+                       (int)(cmd->size));
+               LEAVE();
+               return 0;
+       }
+
+       domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
+       memcpy(domain->countrycode, adapter->domainreg.countrycode,
+              sizeof(domain->countrycode));
+
+       domain->header.len =
+           cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
+                            sizeof(domain->countrycode));
+
+       if (nr_subband) {
+               memcpy(domain->subband, adapter->domainreg.subband,
+                      nr_subband * sizeof(struct ieeetypes_subbandset));
+
+               cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+                                            domain->header.len +
+                                            sizeof(struct mrvlietypesheader) +
+                                            S_DS_GEN);
+       } else {
+               cmd->size =
+                   cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+       }
+
+       lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->size));
+
+       LEAVE();
+
+       return 0;
+}
+
+/**
+ *  @brief This function implements private cmd: enable/disable 11D
+ *  @param priv    pointer to wlan_private
+ *  @param wrq     pointer to user data
+ *  @return       0 or -1
+ */
+int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
+{
+       int data = 0;
+       int *val;
+
+       ENTER();
+       data = SUBCMD_DATA(wrq);
+
+       lbs_pr_debug(1, "enable 11D: %s\n",
+              (data == 1) ? "enable" : "Disable");
+
+       wlan_enable_11d(priv, data);
+       val = (int *)wrq->u.name;
+       *val = priv->adapter->enable11d;
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief This function parses countryinfo from AP and download country info to FW
+ *  @param priv    pointer to wlan_private
+ *  @param resp    pointer to command response buffer
+ *  @return       0; -1
+ */
+int libertas_ret_802_11d_domain_info(wlan_private * priv,
+                                struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11d_domain_info
+       *domaininfo = &resp->params.domaininforesp;
+       struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
+       u16 action = le16_to_cpu(domaininfo->action);
+       s16 ret = 0;
+       u8 nr_subband = 0;
+
+       ENTER();
+
+       lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
+               (int)le16_to_cpu(resp->size));
+
+       nr_subband = (domain->header.len - 3) / sizeof(struct ieeetypes_subbandset);
+       /* countrycode 3 bytes */
+
+       lbs_pr_debug(1, "11D Domain Info Resp: nr_subband=%d\n", nr_subband);
+
+       if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
+               lbs_pr_debug(1, "Invalid Numrer of Subband returned!!\n");
+               return -1;
+       }
+
+       switch (action) {
+       case cmd_act_set:       /*Proc Set action */
+               break;
+
+       case cmd_act_get:
+               break;
+       default:
+               lbs_pr_debug(1, "Invalid action:%d\n", domaininfo->action);
+               ret = -1;
+               break;
+       }
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief This function parses countryinfo from AP and download country info to FW
+ *  @param priv    pointer to wlan_private
+ *  @return       0; -1
+ */
+int libertas_parse_dnld_countryinfo_11d(wlan_private * priv)
+{
+       int ret;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+       if (priv->adapter->enable11d) {
+               memset(&adapter->parsed_region_chan, 0,
+                      sizeof(struct parsed_region_chan_11d));
+               ret = parse_domain_info_11d(&adapter->pattemptedbssdesc->
+                                              countryinfo, 0,
+                                              &adapter->parsed_region_chan);
+
+               if (ret == -1) {
+                       lbs_pr_debug(1, "11D: Err Parse domain_info from AP..\n");
+                       LEAVE();
+                       return ret;
+               }
+
+               memset(&adapter->domainreg, 0,
+                      sizeof(struct wlan_802_11d_domain_reg));
+               generate_domain_info_11d(&adapter->parsed_region_chan,
+                                     &adapter->domainreg);
+
+               ret = set_domain_info_11d(priv);
+
+               if (ret) {
+                       lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
+                       LEAVE();
+                       return ret;
+               }
+       }
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief This function generates 11D info from user specified regioncode and download to FW
+ *  @param priv    pointer to wlan_private
+ *  @return       0; -1
+ */
+int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
+{
+       int ret;
+       wlan_adapter *adapter = priv->adapter;
+       struct region_channel *region_chan;
+       u8 j;
+
+       ENTER();
+       lbs_pr_debug(1, "11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
+
+       if (priv->adapter->enable11d) {
+               /* update parsed_region_chan_11; dnld domaininf to FW */
+
+               for (j = 0; j < sizeof(adapter->region_channel) /
+                    sizeof(adapter->region_channel[0]); j++) {
+                       region_chan = &adapter->region_channel[j];
+
+                       lbs_pr_debug(1, "11D:[%d] region_chan->band[%d]\n", j,
+                              region_chan->band);
+
+                       if (!region_chan || !region_chan->valid
+                           || !region_chan->CFP)
+                               continue;
+                       if (region_chan->band != adapter->curbssparams.band)
+                               continue;
+                       break;
+               }
+
+               if (j >= sizeof(adapter->region_channel) /
+                   sizeof(adapter->region_channel[0])) {
+                       lbs_pr_debug(1, "11D:region_chan not found. band[%d]\n",
+                              adapter->curbssparams.band);
+                       LEAVE();
+                       return -1;
+               }
+
+               memset(&adapter->parsed_region_chan, 0,
+                      sizeof(struct parsed_region_chan_11d));
+               wlan_generate_parsed_region_chan_11d(region_chan,
+                                                    &adapter->
+                                                    parsed_region_chan);
+
+               memset(&adapter->domainreg, 0,
+                      sizeof(struct wlan_802_11d_domain_reg));
+               generate_domain_info_11d(&adapter->parsed_region_chan,
+                                        &adapter->domainreg);
+
+               ret = set_domain_info_11d(priv);
+
+               if (ret) {
+                       lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
+                       LEAVE();
+                       return ret;
+               }
+
+       }
+
+       LEAVE();
+       return 0;
+}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
new file mode 100644 (file)
index 0000000..db2ebea
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+  * This header file contains data structures and
+  * function declarations of 802.11d
+  */
+#ifndef _WLAN_11D_
+#define _WLAN_11D_
+
+#include "types.h"
+#include "defs.h"
+
+#define UNIVERSAL_REGION_CODE                  0xff
+
+/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
+ */
+#define MRVDRV_MAX_SUBBAND_802_11D             83
+
+#define COUNTRY_CODE_LEN                       3
+#define MAX_NO_OF_CHAN                                 40
+
+struct cmd_ds_command;
+
+/** Data structure for Country IE*/
+struct ieeetypes_subbandset {
+       u8 firstchan;
+       u8 nrchan;
+       u8 maxtxpwr;
+} __attribute__ ((packed));
+
+struct ieeetypes_countryinfoset {
+       u8 element_id;
+       u8 len;
+       u8 countrycode[COUNTRY_CODE_LEN];
+       struct ieeetypes_subbandset subband[1];
+};
+
+struct ieeetypes_countryinfofullset {
+       u8 element_id;
+       u8 len;
+       u8 countrycode[COUNTRY_CODE_LEN];
+       struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
+} __attribute__ ((packed));
+
+struct mrvlietypes_domainparamset {
+       struct mrvlietypesheader header;
+       u8 countrycode[COUNTRY_CODE_LEN];
+       struct ieeetypes_subbandset subband[1];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11d_domain_info {
+       u16 action;
+       struct mrvlietypes_domainparamset domain;
+} __attribute__ ((packed));
+
+/** domain regulatory information */
+struct wlan_802_11d_domain_reg {
+       /** country Code*/
+       u8 countrycode[COUNTRY_CODE_LEN];
+       /** No. of subband*/
+       u8 nr_subband;
+       struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
+};
+
+struct chan_power_11d {
+       u8 chan;
+       u8 pwr;
+} __attribute__ ((packed));
+
+struct parsed_region_chan_11d {
+       u8 band;
+       u8 region;
+       s8 countrycode[COUNTRY_CODE_LEN];
+       struct chan_power_11d chanpwr[MAX_NO_OF_CHAN];
+       u8 nr_chan;
+} __attribute__ ((packed));
+
+struct region_code_mapping {
+       u8 region[COUNTRY_CODE_LEN];
+       u8 code;
+};
+
+u8 libertas_get_scan_type_11d(u8 chan,
+                         struct parsed_region_chan_11d *parsed_region_chan);
+
+u32 libertas_chan_2_freq(u8 chan, u8 band);
+
+enum state_11d libertas_get_state_11d(wlan_private * priv);
+
+void libertas_init_11d(wlan_private * priv);
+
+int libertas_set_universaltable(wlan_private * priv, u8 band);
+
+int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+                                struct cmd_ds_command *cmd, u16 cmdno,
+                                u16 cmdOption);
+
+int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
+
+int libertas_ret_802_11d_domain_info(wlan_private * priv,
+                                struct cmd_ds_command *resp);
+
+int libertas_parse_dnld_countryinfo_11d(wlan_private * priv);
+
+int libertas_create_dnld_countryinfo_11d(wlan_private * priv);
+
+#endif                         /* _WLAN_11D_ */
diff --git a/drivers/net/wireless/libertas/LICENSE b/drivers/net/wireless/libertas/LICENSE
new file mode 100644 (file)
index 0000000..8862742
--- /dev/null
@@ -0,0 +1,16 @@
+  Copyright (c) 2003-2006, Marvell International Ltd.
+  All Rights Reserved
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
new file mode 100644 (file)
index 0000000..19c9350
--- /dev/null
@@ -0,0 +1,21 @@
+# EXTRA_CFLAGS += -Wpacked
+
+usb8xxx-objs := main.o fw.o wext.o \
+               rx.o tx.o cmd.o           \
+               cmdresp.o scan.o          \
+               join.o 11d.o              \
+               ioctl.o debugfs.o         \
+               ethtool.o assoc.o
+
+ifeq ($(CONFIG_LIBERTAS_USB_DEBUG), y)
+EXTRA_CFLAGS += -DDEBUG -DPROC_DEBUG
+endif
+
+
+# This is needed to support the newer boot2 bootloader (v >= 3104)
+EXTRA_CFLAGS += -DSUPPORT_BOOT_COMMAND
+usb8xxx-objs += if_bootcmd.o
+usb8xxx-objs += if_usb.o
+
+obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
+
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
new file mode 100644 (file)
index 0000000..688da4c
--- /dev/null
@@ -0,0 +1,1044 @@
+================================================================================
+                       README for USB8388
+
+ (c) Copyright Â© 2003-2006, Marvell International Ltd.
+ All Rights Reserved
+
+ This software file (the "File") is distributed by Marvell International
+ Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ (the "License").  You may use, redistribute and/or modify this File in
+ accordance with the terms and conditions of the License, a copy of which
+ is available along with the File in the license.txt file or by writing to
+ the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+
+ THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ this warranty disclaimer.
+================================================================================
+
+=====================
+DRIVER LOADING
+=====================
+
+       o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/
+
+       o. Load driver by using the following command:
+
+               insmod usb8388.ko [fw_name=usb8388.bin]
+
+=====================
+IWPRIV COMMAND
+=====================
+
+NAME
+       This manual describes the usage of private commands used in Marvell WLAN
+       Linux Driver. All the commands available in Wlanconfig will not be available
+       in the iwpriv.
+
+SYNOPSIS
+       iwpriv <ethX> <command> [sub-command] ...
+
+       iwpriv ethX version
+       iwpriv ethX scantype [sub-command]
+       iwpriv ethX getSNR <n>
+       iwpriv ethX getNF <n>
+       iwpriv ethX getRSSI <n>
+       iwpriv ethX setrxant <n>
+       iwpriv ethX getrxant
+       iwpriv ethX settxant <n>
+       iwpriv ethX gettxant
+       iwpriv ethX authalgs <n>
+       iwpriv ethX pre-TBTT <n>
+       iwpriv ethX 8021xauthalgs <n>
+       iwpriv ethX encryptionmode <n>
+       iwpriv ethX setregioncode <n>
+       iwpriv ethX getregioncode
+       iwpriv ethX setbcnavg <n>
+       iwpriv ethX getbcnavg
+       iwpriv ethX setdataavg <n>
+       iwpriv ethX setlisteninter <n>
+       iwpriv ethX getlisteninter
+       iwpriv ethX setmultipledtim <n>
+       iwpriv ethX getmultipledtim
+       iwpriv ethX atimwindow <n>
+       iwpriv ethX deauth
+       iwpriv ethX adhocstop
+       iwpriv ethX radioon
+       iwpriv ethX radiooff
+       iwpriv ethX reasso-on
+       iwpriv ethX reasso-off
+       iwpriv ethX scanmode  [sub-command]
+       iwpriv ethX setwpaie <n>
+       iwpriv ethX wlanidle-off
+       iwpriv ethX wlanidle-on
+       iwpriv ethX getcis
+       iwpriv ethX getlog
+       iwpriv ethX getadhocstatus
+       iwpriv ethX adhocgrate <n>
+
+Version 4 Command:
+       iwpriv ethX inactvityto <n>
+       iwpriv ethX sleeppd <n>
+       iwpriv ethX enable11d <n>
+       iwpriv ethX tpccfg <n>
+       iwpriv ethX powercfg <n>
+       iwpriv ethX setafc <n>
+       iwpriv ethX getafc
+
+Version 5 Command:
+       iwpriv ethX ledgpio <n>
+       iwpriv ethX scanprobes <n>
+       iwpriv ethX lolisteninter <n>
+       iwpriv ethX rateadapt <n> <m>
+       iwpriv ethX txcontrol <n>
+       iwpriv ethX psnullinterval <n>
+       iwpriv ethX prescan <n>
+       iwpriv ethX getrxinfo
+       iwpriv ethX gettxrate
+       iwpriv ethX beaconinterval
+
+BT Commands:
+       The blinding table (BT) contains a list of mac addresses that should be
+       ignored by the firmware.  It is primarily used for debugging and
+       testing networks.  It can be edited and inspected with the following
+       commands:
+
+       iwpriv ethX bt_reset
+       iwpriv ethX bt_add <mac_address>
+       iwpriv ethX bt_del <mac_address>
+       iwpriv ethX bt_list <id>
+
+FWT Commands:
+       The forwarding table (FWT) is a feature used to manage mesh network
+       routing in the firmware.  The FWT is essentially a routing table that
+       associates a destination mac address (da) with a next hop receiver
+       address (ra).  The FWT can be inspected and edited with the following
+       iwpriv commands, which are described in greater detail below.
+       Eventually, the table will be automatically maintained by a custom
+       routing protocol.
+
+       NOTE: FWT commands replace the previous DFT commands.  What were the DFT
+       commands?, you might ask.  They were an earlier API to the firmware that
+       implemented a simple MAC-layer forwarding mechanism.  In the unlikely
+       event that you were using these commands, you must migrate to the new
+       FWT commands which can be used to achieve the same functionality.
+
+       iwpriv ethX fwt_add [parameters]
+       iwpriv ethX fwt_del [parameters]
+       iwpriv ethX fwt_lookup [parameters]
+       iwpriv ethX fwt_list [parameters]
+       iwpriv ethX fwt_list_route [parameters]
+       iwpriv ethX fwt_list_neigh [parameters]
+       iwpriv ethX fwt_reset [parameters]
+       iwpriv ethX fwt_cleanup
+       iwpriv ethX fwt_time
+
+MESH Commands:
+
+       The MESH commands are used to configure various features of the mesh
+       routing protocol.  The following commands are supported:
+
+       iwpriv ethX mesh_get_ttl
+       iwpriv ethX mesh_set_ttl ttl
+
+DESCRIPTION
+       Those commands are used to send additional commands to the Marvell WLAN
+       card via the Linux device driver.
+
+       The ethX parameter specifies the network device that is to be used to
+               perform this command on. it could be eth0, eth1 etc.
+
+version
+       This is used to get the current version of the driver and the firmware.
+
+scantype
+       This command is used to set the scan type to be used by the driver in
+       the scan command. This setting will not be used while performing a scan
+       for a specific SSID, as it is always done with scan type being active.
+
+       where the sub-commands are: -
+                       active  -- to set the scan type to active
+                       passive -- to set the scan type to passive
+                       get     -- to get the scan type set in the driver
+
+getSNR
+       This command gets the average and non average value of Signal to Noise
+       Ratio of Beacon and Data.
+
+       where value is:-
+                       0       -- Beacon non-average.
+                       1       -- Beacon average.
+                       2       -- Data non-average.
+                       3       -- Data average.
+
+       If no value is given, all four values are returned in the order mentioned
+       above.
+
+       Note: This command is available only when STA is connected.
+
+getRSSI
+       This command gets the average and non average value os Receive Signal
+       Strength of Beacon and Data.
+
+       where value is:-
+                       0       -- Beacon non-average.
+                       1       -- Beacon average.
+                       2       -- Data non-average.
+                       3       -- Data average.
+
+       Note: This command is available only when STA is connected.
+
+getNF
+       This command gets the average and non average value of Noise Floor of
+       Beacon and Data.
+
+       where value is:-
+                       0       -- Beacon non-average.
+                       1       -- Beacon average.
+                       2       -- Data non-average.
+                       3       -- Data average.
+
+       Note: This command is available only when STA is connected.
+
+setrxant
+       This command is used to set the mode for Rx antenna.
+
+       The options that can be sent are:-
+                       1       -- Antenna 1.
+                       2       -- Antenna 2.
+                       0xFFFF  -- Diversity.
+
+       Usage:
+               iwpriv ethX setrxant 0x01: select Antenna 1.
+
+getrxant
+       This command is used to get the mode for Rx antenna.
+
+
+settxant
+       This command is used to set the mode for Tx antenna.
+               The options that can be sent are:-
+                       1       -- Antenna 1.
+                       2       -- Antenna 2.
+                       0xFFFF  -- Diversity.
+       Usage:
+               iwpriv ethX settxant 0x01: select Antenna 1.
+
+gettxant
+       This command is used to get the mode for Tx antenna.
+
+authalgs
+       This command is used by the WPA supplicant to set the authentication
+       algorithms in the station.
+
+8021xauthalgs
+       This command is used by the WPA supplicant to set the 8021.x authentication algorithm type
+       station.
+
+       where values can be:-
+                       1       -- None
+                       2       -- LEAP
+                       4       -- TLS
+                       8       -- TTLs
+                       16      -- MD5
+
+
+encryptionmode
+       This command is used by the WPA supplicant to set the encryption algorithm.
+
+       where values can be:-
+                       0       -- NONE
+                       1       -- WEP40
+                       2       -- TKIP
+                       3       -- CCMP
+                       4       -- WEP104
+
+pre-TBTT
+       This command is used to set pre-TBTT time period where value is in microseconds.
+
+setregioncode
+       This command is used to set the region code in the station.
+       where value is 'region code' for various regions like
+       USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ...
+
+       Usage:
+               iwpriv ethX setregioncode 0x10: set region code to USA (0x10).
+
+getregioncode
+       This command is used to get the region code information set in the
+       station.
+
+setbcnavg
+       Set the weighting factor for calculating RSSI.
+
+getbcnavg
+       Get weighting factor for calculating RSSI.
+
+setdataavg
+       Set the weighting factor for calculating SNR.
+
+setlisteninter
+       This command is used to set the listen interval in the
+       station.
+
+       where the value ranges between 1 - 255
+
+getlisteninter
+       This command is used to get the listen interval value set in the
+       station.
+
+setmultipledtim
+       This command is used to set the multiple dtim value in the
+       station.
+               where the value is 1,2,3,4,5,0xfffe
+               0xfffe means the firmware will use listen interval in association
+               command for waking up
+
+getmultipledtim
+       This command is used to get the multiple dtim value set in the station.
+
+atimwindow
+       This command is used to set the atim value in the
+       station.
+
+       where the value ranges between 0 - 50
+
+deauth
+       This command is used to send the de-authentication to the AP with which
+       the station is associated. This command is valid only when
+       station is in Infrastructure mode.
+
+       Note: This command is available only when STA is connected.
+
+adhocstop
+       This command is used to stop beacon transmission from the station and
+       go into idle state in ad-hoc mode.
+
+       Note: This command is available only when STA is connected.
+
+radioon
+       This command is used to turn on the RF antenna.
+
+radiooff
+       This command is sued to turn off the RF antenna.
+
+scanmode
+       This command is used to set the station to scan for either IBSS
+       networks or BSS networks or both BSS and IBSS networks. This
+       command can be used with sub commands,
+
+       where the value for
+                       bss     -- Scan All the BSS networks.
+                       ibss    -- Scan All the IBSS networks.
+                       any     -- Scan both BSS and IBSS networks.
+
+
+
+setwpaie
+       This command is used by WPA supplicant to send the WPA-IE to the driver.
+
+wlanidle-off
+       This command is used to get into idle state.
+
+       Note: This command is available only when STA is connected.
+
+wlanidle-on
+       This command is used to get off the idle state.
+
+       Note: This command is available only when STA is connected.
+
+
+getlog
+       This command is used to get the 802.11 statistics available in the
+               station.
+
+       Note: This command is available only when STA is connected.
+
+getadhocstatus
+       This command is used to get the ad-hoc Network Status.
+
+       The various status codes are:
+               AdhocStarted
+               AdhocJoined
+               AdhocIdle
+               InfraMode
+               AutoUnknownMode
+
+       Note: This command is available only when STA is connected.
+
+adhocgrate
+       This command is used to enable(1) g_rate, Disable(0) g_rate
+       and request(2) the status which g_rate is disabled/enabled,
+       for Ad-hoc creator.
+
+       where value is:-
+               0       -- Disabled
+               1       -- Enabled
+               2       -- Get
+
+ledgpio
+       This command is used to set/get LEDs.
+
+       iwpriv ethX ledgpio <LEDs>
+               will set the corresponding LED for the GPIO Line.
+
+       iwpriv ethX ledgpio
+               will give u which LEDs are Enabled.
+
+       Usage:
+               iwpriv eth1 ledgpio 1 0 2 1 3 4
+                       will enable
+                       LED 1 -> GPIO 0
+                       LED 2 -> GPIO 1
+                       LED 3 -> GPIO 4
+
+               iwpriv eth1 ledgpio
+                       shows LED information in the format as mentioned above.
+
+       Note: LED0 is invalid
+       Note: Maximum Number of LEDs are 16.
+
+inactivityto
+       This command is used by the host to set/get the inactivity timeout value,
+       which specifies when WLAN device is put to sleep.
+
+       Usage:
+               iwpriv ethX inactivityto [<timeout>]
+
+       where the parameter are:
+               timeout: timeout value in milliseconds.
+
+       Example:
+               iwpriv eth1 inactivityto
+                       "get the timeout value"
+
+               iwpriv eth1 inactivityto X
+                       "set timeout value to X ms"
+
+
+sleeppd
+       This command is used to configure the sleep period of the WLAN device.
+
+       Usage:
+               iwpriv ethX sleeppd [<sleep period>]
+
+       where the parameter are:
+               Period: sleep period in milliseconds. Range 10~60.
+
+       Example:
+               iwpriv eth1 sleeppd 10
+                       "set period as 10 ms"
+               iwpriv eth1 sleeppd
+                       "get the sleep period configuration"
+
+enable11d
+       This command is used to control 11d
+       where value is:-
+               1       -- Enabled
+               0       -- Disabled
+               2       -- Get
+
+
+
+
+tpccfg
+       Enables or disables automatic transmit power control.
+
+       The first parameter turns this feature on (1) or off (0).  When turning
+       on, the user must also supply four more parameters in the following
+       order:
+               -UseSNR (Use SNR (in addition to PER) for TPC algorithm),
+               -P0 (P0 power level for TPC),
+               -P1 (P1 power level for TPC),
+               -P2 (P2 power level for TPC).
+
+       Usage:
+               iwpriv ethX tpccfg: Get current configuration
+               iwpriv ethX tpccfg 0: disable auto TPC
+               iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR;
+                                                            P0=0x05; P1=0x0a; P2=0x0d;
+               iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR;
+                                                            P0=0x05; P1=0x0a; P2=0x0d.
+
+powercfg
+       Enables or disables power adaptation.
+
+       The first parameter turns this feature on (1) or off (0).  When turning
+       on, the user must also supply three more parameters in the following
+       order:
+               -P0 (P0 power level for Power Adaptation),
+               -P1 (P1 power level for Power Adaptation),
+               -P2 (P2 power level for Power Adaptation).
+
+       Usage:
+               iwpriv ethX powercfg: Get current configuration
+               iwpriv ethX powercfg 0: disable power adaptation
+               iwpriv ethX powercfg 1 0x0d 0x0f 0x12: enable power adaptation;
+                                                      P0=0x0d; P1=0x0f; P2=0x12.
+
+getafc
+       This command returns automatic frequency control parameters.  It returns
+       three integers:
+               -P0: automatic is on (1), or off (0),
+               -P1: current timing offset in PPM (part per million), and
+               -P2: current frequency offset in PPM.
+
+setafc
+       Set automatic frequency control options.
+
+       The first parameter turns automatic on (1) or off (0).
+       The user must supply two more parameters in either case, in the following
+  order:
+
+  When auto is on:
+
+               -P0 (automatic adjustment frequency threshold in PPM),
+               -P1 (automatic adjustment period in beacon period),
+
+  When auto is off:
+
+               -P0 (manual adjustment timing offset in PPM), and
+               -P1 (manual adjustment frequency offset in PPM).
+
+       Usage:
+               iwpriv ethX setafc 0 10 10: manual adjustment, both timing and frequcncy
+    offset are 10 PPM.
+
+               iwpriv ethX setafc 1 10 10 enable afc, automatic adjustment,
+    frequency threshold 10 PPM, for every 10 beacon periods.
+
+
+
+scanprobes
+       This command sets number of probe requests per channel.
+
+       Usage:
+               iwpriv ethX scanprobes 3 (set scan probes to 3)
+               iwpriv ethX scanprobes   (get scan probes)
+
+lolisteninter
+       This command sets the value of listen interval.
+
+       Usage:
+       iwpriv ethX lolisteninter 234 (set the lolisteninter to 234)
+       iwpriv ethX lolisteninter     (get the lolisteninter value)
+
+rateadapt
+       This command sets the data rates bitmap.
+       Where <n>
+               0: Disable auto rate adapt
+               1: Enable auto rate adapt
+
+             <m>
+                data rate bitmap
+                       Bit     Data rate
+                       0       1 Mbps
+                       1       2 Mbps
+                       2       5.5 Mbps
+                       3       11 Mbps
+                       4       Reserved
+                       5       6 Mbps
+                       6       9 Mbps
+                       7       12 Mbps
+                       8       18 Mbps
+                       9       24 Mbps
+                       10      36 Mbps
+                       11      48 Mbps
+                       12      54 Mbps
+                       12-15   Reserved
+
+       Usage:
+       iwpriv ethX rateadapt
+                       read the currect data rate setting
+       iwpriv ethX rateadapt 1 0x07
+                       enable auto data rate adapt and
+                       data rates are 1Mbps, 2Mbsp and 5.5Mbps
+
+
+txcontrol
+       This command is used to set the Tx rate, ack policy, and retry limit on a per packet basis.
+
+       Where value <n> is:
+           if bit[4] == 1:
+               bit[3:0]        -- 0   1   2   3   4   5   6   7   8   9   10   11   12   13-16
+               Data Rate(Mbps) -- 1   2   5.5 11  Rsv 6   9   12  18  24  36   48   54   Rsv
+
+           bit[12:8]
+               if bit[12] == 1, bit[11:8] specifies the Tx retry limit.
+
+           bit[14:13] specifies per packet ack policy:
+               bit[14:13]
+                    1  0       use immediate ack policy for this packet
+                    1  1       use no ack policy for this packet
+                    0  x       use the per-packet ack policy setting
+
+       Usage:
+       iwpriv ethX txcontrol 0x7513
+                       Use no-ack policy, 5 retires for Tx, 11Mbps rate
+
+
+
+psnullinterval
+       This command is used to set/request NULL package interval for Power Save
+       under infrastructure mode.
+
+       where value is:-
+               -1      -- Disabled
+               n>0     -- Set interval as n (seconds)
+
+prescan
+       This command is used to enable (1)/disable(0) auto prescan before assoicate to the ap
+
+       where value is:-
+               0       -- Disabled
+               1       -- Enabled
+               2       -- Get
+
+getrxinfo
+       This command gets non average value of Signal to Noise Ratio of Data and rate index.
+
+       The following table shows RateIndex and Rate
+
+                    RateIndex  Data rate
+                       0       1 Mbps
+                       1       2 Mbps
+                       2       5.5 Mbps
+                       3       11 Mbps
+                       4       Reserved
+                       5       6 Mbps
+                       6       9 Mbps
+                       7       12 Mbps
+                       8       18 Mbps
+                       9       24 Mbps
+                       10      36 Mbps
+                       11      48 Mbps
+                       12      54 Mbps
+                       13-15   Reserved
+
+gettxrate
+       This command gets current Tx rate index of the first packet associated with Rate Adaptation.
+
+       The following table shows RateIndex and Rate
+
+                    RateIndex  Data rate
+                       0       1 Mbps
+                       1       2 Mbps
+                       2       5.5 Mbps
+                       3       11 Mbps
+                       4       Reserved
+                       5       6 Mbps
+                       6       9 Mbps
+                       7       12 Mbps
+                       8       18 Mbps
+                       9       24 Mbps
+                       10      36 Mbps
+                       11      48 Mbps
+                       12      54 Mbps
+                       13-15   Reserved
+
+bcninterval
+       This command is used to sets beacon interval in adhoc mode when an argument is given, and gets current adhoc
+       beacon interval when no argument is given. The valid beacon interval is between 20 - 1000,
+       default beacon interval is 100.
+
+       Usage:
+               iwpriv ethX bcninterval 100  (set adhoc beacon interval to 100)
+               iwpriv ethX bcninterval      (get adhoc beacon interval)
+
+fwt_add
+       This command is used to insert an entry into the FWT table. The list of
+       parameters must follow the following structure:
+
+       iwpriv ethX fwt_add da ra [metric dir ssn dsn hopcount ttl expiration sleepmode snr]
+
+       The parameters between brackets are optional, but they must appear in
+       the order specified.  For example, if you want to specify the metric,
+       you must also specify the dir, ssn, and dsn but you need not specify the
+       hopcount, expiration, sleepmode, or snr.  Any unspecified parameters
+       will be assigned the defaults specified below.
+
+       The different parameters are:-
+               da              -- DA MAC address in the form 00:11:22:33:44:55
+               ra              -- RA MAC address in the form 00:11:22:33:44:55
+               metric          -- route metric (cost: smaller-metric routes are
+                                  preferred, default is 0)
+               dir             -- direction (1 for direct, 0 for reverse,
+                                  default is 1)
+               ssn             -- Source Sequence Number (time at the RA for
+                                  reverse routes.  Default is 0)
+               dsn             -- Destination Sequence Number (time at the DA
+                                  for direct routes.  Default is 0)
+               hopcount        -- hop count (currently unused, default is 0)
+               ttl             -- TTL (Only used in reverse entries)
+               expiration      -- entry expiration (in ticks, where a tick is
+                                  1024us, or ~ 1ms. Use 0 for an indefinite
+                                  entry, default is 0)
+               sleepmode       -- RA's sleep mode (currently unused, default is
+                                  0)
+               snr             -- SNR in the link to RA (currently unused,
+                                  default is 0)
+
+       The command does not return anything.
+
+fwt_del
+       This command is used to remove an entry to the FWT table. The list of
+       parameters must follow the following structure:
+
+               iwpriv ethX fwt_del da ra [dir]
+
+       where the different parameters are:-
+               da              -- DA MAC address (in the form "00:11:22:33:44:55")
+               ra              -- RA MAC address (in the form "00:11:22:33:44:55")
+               dir             -- direction (1 for direct, 0 for reverse,
+                                  default is 1)
+
+       The command does not return anything.
+
+fwt_lookup
+       This command is used to get the best route in the FWT table to a given
+       host. The only parameter is the MAC address of the host that is being
+       looked for.
+
+               iwpriv ethX fwt_lookup da
+
+       where:-
+               da              -- DA MAC address (in the form "00:11:22:33:44:55")
+
+       The command returns an output string identical to the one returned by
+       fwt_list described below.
+
+
+fwt_list
+       This command is used to list a route from the FWT table. The only
+       parameter is the index into the table. If you want to list all the
+       routes in a table, start with index=0, and keep listing until you get a
+       "(null)" string.  Note that the indicies may change as the fwt is
+       updated.  It is expected that most users will not use fwt_list directly,
+       but that a utility similar to the traditional route command will be used
+       to invoke fwt_list over and over.
+
+               iwpriv ethX fwt_list index
+
+       The output is a string of the following form:
+
+               da ra metric dir ssn dsn hopcount ttl expiration sleepmode snr
+
+       where the different fields are:-
+               da              -- DA MAC address (in the form "00:11:22:33:44:55")
+               ra              -- RA MAC address (in the form "00:11:22:33:44:55")
+               metric          -- route metric (cost: smaller-metric routes are preferred)
+               dir             -- direction (1 for direct, 0 for reverse)
+               ssn             -- Source Sequence Number (time at the RA for reverse routes)
+               dsn             -- Destination Sequence Number (time at the DA for direct routes)
+               hopcount        -- hop count (currently unused)
+               ttl             -- TTL (only used in reverse entries)
+               expiration      -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+               sleepmode       -- RA's sleep mode (currently unused)
+               snr             -- SNR in the link to RA (currently unused)
+
+fwt_list_route
+       This command is used to list a route from the FWT table. The only
+       parameter is the route ID. If you want to list all the routes in a
+       table, start with rid=0, and keep incrementing rid until you get a
+       "(null)" string. This function is similar to fwt_list. The only
+       difference is the output format.  Also note that this command is meant
+       for debugging.  It is expected that users will use fwt_lookup and
+       fwt_list.  One important reason for this is that the route id may change
+       as the route table is altered.
+
+               iwpriv ethX fwt_list_route rid
+
+       The output is a string of the following form:
+
+               da metric dir nid ssn dsn hopcount ttl expiration
+
+       where the different fields are:-
+               da              -- DA MAC address (in the form "00:11:22:33:44:55")
+               metric          -- route metric (cost: smaller-metric routes are preferred)
+               dir             -- direction (1 for direct, 0 for reverse)
+               nid             -- Next-hop (neighbor) host ID (nid)
+               ssn             -- Source Sequence Number (time at the RA for reverse routes)
+               dsn             -- Destination Sequence Number (time at the DA for direct routes)
+               hopcount        -- hop count (currently unused)
+               ttl             -- TTL count (only used in reverse entries)
+               expiration      -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+
+fwt_list_neigh
+       This command is used to list a neighbor from the FWT table. The only
+       parameter is the neighbor ID. If you want to list all the neighbors in a
+       table, start with nid=0, and keep incrementing nid until you get a
+       "(null)" string.  Note that the nid from a fwt_list_route command can be
+       used as an input to this command.  Also note that this command is meant
+       mostly for debugging.  It is expected that users will use fwt_lookup.
+       One important reason for this is that the neighbor id may change as the
+       neighbor table is altered.
+
+               iwpriv ethX fwt_list_neigh nid
+
+       The output is a string of the following form:
+
+               ra sleepmode snr references
+
+       where the different fields are:-
+               ra              -- RA MAC address (in the form "00:11:22:33:44:55")
+               sleepmode       -- RA's sleep mode (currently unused)
+               snr             -- SNR in the link to RA (currently unused)
+               references      -- RA's reference counter
+
+fwt_reset
+       This command is used to reset the FWT table, getting rid of all the
+       entries. There are no input parameters.
+
+               iwpriv ethX fwt_reset
+
+       The command does not return anything.
+
+fwt_cleanup
+       This command is used to perform user-based garbage recollection. The
+       FWT table is checked, and all the entries that are expired or invalid
+       are cleaned. Note that this is exported to the driver for debugging
+       purposes, as garbage collection is also fired by the firmware when in
+       space problems. There are no input parameters.
+
+               iwpriv ethX fwt_cleanup
+
+       The command does returns the number of invalid/expired routes deleted.
+
+fwt_time
+       This command returns a card's internal time representation.  It is this
+       time that is used to represent the expiration times of FWT entries.  The
+       number is not consistent from card to card; it is simply a timer count.
+       The fwt_time command is used to inspect the timer so that expiration
+       times reported by fwt_list can be properly interpreted.
+
+               iwpriv ethX fwt_time
+
+mesh_get_ttl
+
+       The mesh ttl is the number of hops a mesh packet can traverse before it
+       is dropped.  This parameter is used to prevent infinite loops in the
+       mesh network.  The value returned by this function is the ttl assigned
+       to all mesh packets.  Currently there is no way to control the ttl on a
+       per packet or per socket basis.
+
+       iwpriv ethX mesh_get_ttl
+
+mesh_set_ttl ttl
+
+       Set the ttl.  The argument must be between 0 and 255.
+
+       iwpriv ethX mesh_set_ttl <ttl>
+
+=========================
+ETHTOOL
+=========================
+
+
+Use the -i option to retrieve version information from the driver.
+
+# ethtool -i eth0
+driver: libertas
+version: COMM-USB8388-318.p4
+firmware-version: 5.110.7
+bus-info:
+
+Use the -e option to read the EEPROM contents of the card.
+
+       Usage:
+       ethtool -e ethX [raw on|off] [offset N] [length N]
+
+       -e     retrieves and prints an EEPROM dump for the  specified  ethernet
+              device.   When raw is enabled, then it dumps the raw EEPROM data
+              to stdout. The length and offset parameters allow  dumping  cer-
+              tain portions of the EEPROM.  Default is to dump the entire EEP-
+              ROM.
+
+# ethtool -e eth0 offset 0 length 16
+Offset          Values
+------          ------
+0x0000          38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00
+
+========================
+DEBUGFS COMMANDS
+========================
+
+those commands are used via debugfs interface
+
+===========
+rdmac
+rdbbp
+rdrf
+       These commands are used to read the MAC, BBP and RF registers from the
+       card.  These commands take one parameter that specifies the offset
+       location that is to be read.  This parameter must be specified in
+       hexadecimal (its possible to preceed preceding the number with a "0x").
+
+       Path: /debugfs/libertas_wireless/ethX/registers/
+
+       Usage:
+               echo "0xa123" > rdmac ; cat rdmac
+               echo "0xa123" > rdbbp ; cat rdbbp
+               echo "0xa123" > rdrf ; cat rdrf
+wrmac
+wrbbp
+wrrf
+       These commands are used to write the MAC, BBP and RF registers in the
+       card.  These commands take two parameters that specify the offset
+       location and the value that is to be written. This parameters must
+       be specified in hexadecimal (its possible to preceed the number
+       with a "0x").
+
+       Usage:
+               echo "0xa123 0xaa" > wrmac
+               echo "0xa123 0xaa" > wrbbp
+               echo "0xa123 0xaa" > wrrf
+
+sleepparams
+       This command is used to set the sleepclock configurations
+
+       Path: /debugfs/libertas_wireless/ethX/
+
+       Usage:
+               cat sleepparams: reads the current sleepclock configuration
+
+               echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration.
+
+               where:
+                       p1 is Sleep clock error in ppm (0-65535)
+                       p2 is Wakeup offset in usec (0-65535)
+                       p3 is Clock stabilization time in usec (0-65535)
+                       p4 is Control periodic calibration (0-2)
+                       p5 is Control the use of external sleep clock (0-2)
+                       p6 is reserved for debug (0-65535)
+
+subscribed_events
+
+       The subscribed_events directory contains the interface for the
+       subscribed events API.
+
+       Path: /debugfs/libertas_wireless/ethX/subscribed_events/
+
+       Each event is represented by a filename. Each filename consists of the
+       following three fields:
+       Value Frequency Subscribed
+
+       To read the current values for a given event, do:
+               cat event
+       To set the current values, do:
+               echo "60 2 1" > event
+
+       Frequency field specifies the reporting frequency for this event.
+       If it is set to 0, then the event is reported only once, and then
+       automatically unsubscribed. If it is set to 1, then the event is
+       reported every time it occurs. If it is set to N, then the event is
+       reported every Nth time it occurs.
+
+       beacon_missed
+       Value field specifies the number of consecutive missing beacons which
+       triggers the LINK_LOSS event. This event is generated only once after
+       which the firmware resets its state. At initialization, the LINK_LOSS
+       event is subscribed by default. The default value of MissedBeacons is
+       60.
+
+       failure_count
+       Value field specifies the consecutive failure count threshold which
+       triggers the generation of the MAX_FAIL event. Once this event is
+       generated, the consecutive failure count is reset to 0.
+       At initialization, the MAX_FAIL event is NOT subscribed by
+       default.
+
+       high_rssi
+       This event is generated when the average received RSSI in beacons goes
+       above a threshold, specified by Value.
+
+       low_rssi
+       This event is generated when the average received RSSI in beacons goes
+       below a threshold, specified by Value.
+
+       high_snr
+       This event is generated when the average received SNR in beacons goes
+       above a threshold, specified by Value.
+
+       low_snr
+       This event is generated when the average received SNR in beacons goes
+       below a threshold, specified by Value.
+
+extscan
+       This command is used to do a specific scan.
+
+       Path: /debugfs/libertas_wireless/ethX/
+
+       Usage: echo "SSID" > extscan
+
+       Example:
+               echo "LINKSYS-AP" > extscan
+
+       To see the results of use getscantable command.
+
+getscantable
+
+       Display the current contents of the driver scan table (ie. get the
+       scan results).
+
+       Path: /debugfs/libertas_wireless/ethX/
+
+       Usage:
+               cat getscantable
+
+setuserscan
+       Initiate a customized scan and retrieve the results
+
+
+       Path: /debugfs/libertas_wireless/ethX/
+
+    Usage:
+       echo "[ARGS]" > setuserscan
+
+         where [ARGS]:
+
+      chan=[chan#][band][mode] where band is [a,b,g] and mode is
+                               blank for active or 'p' for passive
+      bssid=xx:xx:xx:xx:xx:xx  specify a BSSID filter for the scan
+      ssid="[SSID]"            specify a SSID filter for the scan
+      keep=[0 or 1]            keep the previous scan results (1), discard (0)
+      dur=[scan time]          time to scan for each channel in milliseconds
+      probes=[#]               number of probe requests to send on each chan
+      type=[1,2,3]             BSS type: 1 (Infra), 2(Adhoc), 3(Any)
+
+    Any combination of the above arguments can be supplied on the command line.
+      If the chan token is absent, a full channel scan will be completed by
+      the driver.  If the dur or probes tokens are absent, the driver default
+      setting will be used.  The bssid and ssid fields, if blank,
+      will produce an unfiltered scan. The type field will default to 3 (Any)
+      and the keep field will default to 0 (Discard).
+
+    Examples:
+    1) Perform an active scan on channels 1, 6, and 11 in the 'g' band:
+            echo "chan=1g,6g,11g" > setuserscan
+
+    2) Perform a passive scan on channel 11 for 20 ms:
+            echo "chan=11gp dur=20" > setuserscan
+
+    3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
+       channel 36 in the 'a' band:
+
+            echo "chan=1g,6g,11g,36ap" > setuserscan
+
+    4) Perform an active scan on channel 6 and 36 for a specific SSID:
+            echo "chan=6g,36a ssid="TestAP"" > setuserscan
+
+    5) Scan all available channels (B/G, A bands) for a specific BSSID, keep
+       the current scan table intact, update existing or append new scan data:
+            echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
+
+    6) Scan channel 6, for all infrastructure networks, sending two probe
+       requests.  Keep the previous scan table intact. Update any duplicate
+       BSSID/SSID matches with the new scan data:
+            echo "chan=6g type=1 probes=2 keep=1" > setuserscan
+
+    All entries in the scan table (not just the new scan data when keep=1)
+    will be displayed upon completion by use of the getscantable ioctl.
+
+==============================================================================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
new file mode 100644 (file)
index 0000000..b55c7f5
--- /dev/null
@@ -0,0 +1,588 @@
+/* Copyright (C) 2006, Red Hat, Inc. */
+
+#include <linux/bitops.h>
+#include <net/ieee80211.h>
+
+#include "assoc.h"
+#include "join.h"
+#include "decl.h"
+#include "hostcmd.h"
+#include "host.h"
+
+
+static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static int assoc_helper_essid(wlan_private *priv,
+                              struct assoc_request * assoc_req)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       int i;
+
+       ENTER();
+
+       lbs_pr_debug(1, "New SSID requested: %s\n", assoc_req->ssid.ssid);
+       if (assoc_req->mode == wlan802_11infrastructure) {
+               if (adapter->prescan) {
+                       libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
+               }
+
+               i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
+                               NULL, wlan802_11infrastructure);
+               if (i >= 0) {
+                       lbs_pr_debug(1,
+                              "SSID found in scan list ... associating...\n");
+
+                       ret = wlan_associate(priv, &adapter->scantable[i]);
+                       if (ret == 0) {
+                               memcpy(&assoc_req->bssid,
+                                      &adapter->scantable[i].macaddress,
+                                      ETH_ALEN);
+                       }
+               } else {
+                       lbs_pr_debug(1, "SSID '%s' not found; cannot associate\n",
+                               assoc_req->ssid.ssid);
+               }
+       } else if (assoc_req->mode == wlan802_11ibss) {
+               /* Scan for the network, do not save previous results.  Stale
+                *   scan data will cause us to join a non-existant adhoc network
+                */
+               libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
+
+               /* Search for the requested SSID in the scan table */
+               i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
+                               wlan802_11ibss);
+               if (i >= 0) {
+                       lbs_pr_debug(1, "SSID found at %d in List, so join\n", ret);
+                       libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+               } else {
+                       /* else send START command */
+                       lbs_pr_debug(1, "SSID not found in list, so creating adhoc"
+                               " with SSID '%s'\n", assoc_req->ssid.ssid);
+                       libertas_start_adhoc_network(priv, &assoc_req->ssid);
+               }
+               memcpy(&assoc_req->bssid, &adapter->current_addr, ETH_ALEN);
+       }
+
+       LEAVE();
+       return ret;
+}
+
+
+static int assoc_helper_bssid(wlan_private *priv,
+                              struct assoc_request * assoc_req)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int i, ret = 0;
+
+       ENTER();
+
+       lbs_pr_debug(1, "ASSOC: WAP: BSSID = " MAC_FMT "\n",
+               MAC_ARG(assoc_req->bssid));
+
+       /* Search for index position in list for requested MAC */
+       i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
+                           assoc_req->mode);
+       if (i < 0) {
+               lbs_pr_debug(1, "ASSOC: WAP: BSSID " MAC_FMT " not found, "
+                       "cannot associate.\n", MAC_ARG(assoc_req->bssid));
+               goto out;
+       }
+
+       if (assoc_req->mode == wlan802_11infrastructure) {
+               ret = wlan_associate(priv, &adapter->scantable[i]);
+               lbs_pr_debug(1, "ASSOC: return from wlan_associate(bssd) was %d\n", ret);
+       } else if (assoc_req->mode == wlan802_11ibss) {
+               libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+       }
+       memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid,
+               sizeof(struct WLAN_802_11_SSID));
+
+out:
+       LEAVE();
+       return ret;
+}
+
+
+static int assoc_helper_associate(wlan_private *priv,
+                                  struct assoc_request * assoc_req)
+{
+       int ret = 0, done = 0;
+
+       /* If we're given and 'any' BSSID, try associating based on SSID */
+
+       if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+               if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN)
+                   && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) {
+                       ret = assoc_helper_bssid(priv, assoc_req);
+                       done = 1;
+                       if (ret) {
+                               lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
+                       }
+               }
+       }
+
+       if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+               ret = assoc_helper_essid(priv, assoc_req);
+               if (ret) {
+                       lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
+               }
+       }
+
+       return ret;
+}
+
+
+static int assoc_helper_mode(wlan_private *priv,
+                             struct assoc_request * assoc_req)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       ENTER();
+
+       if (assoc_req->mode == adapter->inframode) {
+               LEAVE();
+               return 0;
+       }
+
+       if (assoc_req->mode == wlan802_11infrastructure) {
+               if (adapter->psstate != PS_STATE_FULL_POWER)
+                       libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+               adapter->psmode = wlan802_11powermodecam;
+       }
+
+       adapter->inframode = assoc_req->mode;
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_snmp_mib,
+                                   0, cmd_option_waitforrsp,
+                                   OID_802_11_INFRASTRUCTURE_MODE,
+                                   (void *) assoc_req->mode);
+
+       LEAVE();
+       return ret;
+}
+
+
+static int assoc_helper_wep_keys(wlan_private *priv,
+                                 struct assoc_request * assoc_req)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int i;
+       int ret = 0;
+
+       ENTER();
+
+       /* Set or remove WEP keys */
+       if (   assoc_req->wep_keys[0].len
+           || assoc_req->wep_keys[1].len
+           || assoc_req->wep_keys[2].len
+           || assoc_req->wep_keys[3].len) {
+               ret = libertas_prepare_and_send_command(priv,
+                                           cmd_802_11_set_wep,
+                                           cmd_act_add,
+                                           cmd_option_waitforrsp,
+                                           0, assoc_req);
+       } else {
+               ret = libertas_prepare_and_send_command(priv,
+                                           cmd_802_11_set_wep,
+                                           cmd_act_remove,
+                                           cmd_option_waitforrsp,
+                                           0, NULL);
+       }
+
+       if (ret)
+               goto out;
+
+       /* enable/disable the MAC's WEP packet filter */
+       if (assoc_req->secinfo.WEPstatus == wlan802_11WEPenabled)
+               adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
+       else
+               adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
+       ret = libertas_set_mac_packet_filter(priv);
+       if (ret)
+               goto out;
+
+       mutex_lock(&adapter->lock);
+
+       /* Copy WEP keys into adapter wep key fields */
+       for (i = 0; i < 4; i++) {
+               memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
+                       sizeof(struct WLAN_802_11_KEY));
+       }
+       adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
+
+       mutex_unlock(&adapter->lock);
+
+out:
+       LEAVE();
+       return ret;
+}
+
+static int assoc_helper_secinfo(wlan_private *priv,
+                                struct assoc_request * assoc_req)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       ENTER();
+
+       memcpy(&adapter->secinfo, &assoc_req->secinfo,
+               sizeof(struct wlan_802_11_security));
+
+       ret = libertas_set_mac_packet_filter(priv);
+
+       LEAVE();
+       return ret;
+}
+
+
+static int assoc_helper_wpa_keys(wlan_private *priv,
+                                 struct assoc_request * assoc_req)
+{
+       int ret = 0;
+
+       ENTER();
+
+       /* enable/Disable RSN */
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_enable_rsn,
+                                   cmd_act_set,
+                                   cmd_option_waitforrsp,
+                                   0, assoc_req);
+       if (ret)
+               goto out;
+
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_key_material,
+                                   cmd_act_set,
+                                   cmd_option_waitforrsp,
+                                   0, assoc_req);
+
+out:
+       LEAVE();
+       return ret;
+}
+
+
+static int assoc_helper_wpa_ie(wlan_private *priv,
+                               struct assoc_request * assoc_req)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       ENTER();
+
+       if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
+               memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
+               adapter->wpa_ie_len = assoc_req->wpa_ie_len;
+       } else {
+               memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
+               adapter->wpa_ie_len = 0;
+       }
+
+       LEAVE();
+       return ret;
+}
+
+
+static int should_deauth_infrastructure(wlan_adapter *adapter,
+                                        struct assoc_request * assoc_req)
+{
+       if (adapter->connect_status != libertas_connected)
+               return 0;
+
+       if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+               lbs_pr_debug(1, "Deauthenticating due to new SSID in "
+                       " configuration request.\n");
+               return 1;
+       }
+
+       if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+               if (adapter->secinfo.authmode !=
+                   assoc_req->secinfo.authmode) {
+                       lbs_pr_debug(1, "Deauthenticating due to updated security "
+                               "info in configuration request.\n");
+                       return 1;
+               }
+       }
+
+       if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+               lbs_pr_debug(1, "Deauthenticating due to new BSSID in "
+                       " configuration request.\n");
+               return 1;
+       }
+
+       /* FIXME: deal with 'auto' mode somehow */
+       if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+               if (assoc_req->mode != wlan802_11infrastructure)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+static int should_stop_adhoc(wlan_adapter *adapter,
+                             struct assoc_request * assoc_req)
+{
+       if (adapter->connect_status != libertas_connected)
+               return 0;
+
+       if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
+               return 1;
+       if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
+                       sizeof(struct WLAN_802_11_SSID)))
+               return 1;
+
+       /* FIXME: deal with 'auto' mode somehow */
+       if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+               if (assoc_req->mode != wlan802_11ibss)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+void wlan_association_worker(struct work_struct *work)
+{
+       wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
+       wlan_adapter *adapter = priv->adapter;
+       struct assoc_request * assoc_req = NULL;
+       int ret = 0;
+       int find_any_ssid = 0;
+
+       ENTER();
+
+       mutex_lock(&adapter->lock);
+       assoc_req = adapter->assoc_req;
+       adapter->assoc_req = NULL;
+       mutex_unlock(&adapter->lock);
+
+       if (!assoc_req) {
+               LEAVE();
+               return;
+       }
+
+       lbs_pr_debug(1, "ASSOC: starting new association request: flags = 0x%lX\n",
+               assoc_req->flags);
+
+       /* If 'any' SSID was specified, find an SSID to associate with */
+       if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
+           && !assoc_req->ssid.ssidlength)
+               find_any_ssid = 1;
+
+       /* But don't use 'any' SSID if there's a valid locked BSSID to use */
+       if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+               if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN)
+                   && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN))
+                       find_any_ssid = 0;
+       }
+
+       if (find_any_ssid) {
+               enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
+
+               ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
+                               assoc_req->mode, &new_mode);
+               if (ret) {
+                       lbs_pr_debug(1, "Could not find best network\n");
+                       ret = -ENETUNREACH;
+                       goto out;
+               }
+
+               /* Ensure we switch to the mode of the AP */
+               if (assoc_req->mode == wlan802_11autounknown) {
+                       set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+                       assoc_req->mode = new_mode;
+               }
+       }
+
+       /*
+        * Check if the attributes being changing require deauthentication
+        * from the currently associated infrastructure access point.
+        */
+       if (adapter->inframode == wlan802_11infrastructure) {
+               if (should_deauth_infrastructure(adapter, assoc_req)) {
+                       ret = libertas_send_deauthentication(priv);
+                       if (ret) {
+                               lbs_pr_debug(1, "Deauthentication due to new "
+                                       "configuration request failed: %d\n",
+                                       ret);
+                       }
+               }
+       } else if (adapter->inframode == wlan802_11ibss) {
+               if (should_stop_adhoc(adapter, assoc_req)) {
+                       ret = libertas_stop_adhoc_network(priv);
+                       if (ret) {
+                               lbs_pr_debug(1, "Teardown of AdHoc network due to "
+                                       "new configuration request failed: %d\n",
+                                       ret);
+                       }
+
+               }
+       }
+
+       /* Send the various configuration bits to the firmware */
+       if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+               ret = assoc_helper_mode(priv, assoc_req);
+               if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
+                       goto out;
+               }
+       }
+
+       if (   test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
+           || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
+               ret = assoc_helper_wep_keys(priv, assoc_req);
+               if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
+                       goto out;
+               }
+       }
+
+       if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+               ret = assoc_helper_secinfo(priv, assoc_req);
+               if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
+                       goto out;
+               }
+       }
+
+       if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+               ret = assoc_helper_wpa_ie(priv, assoc_req);
+               if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
+                       goto out;
+               }
+       }
+
+       if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
+           || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+               ret = assoc_helper_wpa_keys(priv, assoc_req);
+               if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
+                       goto out;
+               }
+       }
+
+       /* SSID/BSSID should be the _last_ config option set, because they
+        * trigger the association attempt.
+        */
+       if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
+           || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+               int success = 1;
+
+               ret = assoc_helper_associate(priv, assoc_req);
+               if (ret) {
+                       lbs_pr_debug(1, "ASSOC: association attempt unsuccessful: %d\n",
+                               ret);
+                       success = 0;
+               }
+
+               if (adapter->connect_status != libertas_connected) {
+                       lbs_pr_debug(1, "ASSOC: assoication attempt unsuccessful, "
+                               "not connected.\n");
+                       success = 0;
+               }
+
+               if (success) {
+                       lbs_pr_debug(1, "ASSOC: association attempt successful. "
+                               "Associated to '%s' (" MAC_FMT ")\n",
+                               assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid));
+                       libertas_prepare_and_send_command(priv,
+                               cmd_802_11_rssi,
+                               0, cmd_option_waitforrsp, 0, NULL);
+
+                       libertas_prepare_and_send_command(priv,
+                               cmd_802_11_get_log,
+                               0, cmd_option_waitforrsp, 0, NULL);
+               } else {
+
+                       ret = -1;
+               }
+       }
+
+out:
+       if (ret) {
+               lbs_pr_debug(1, "ASSOC: reconfiguration attempt unsuccessful: %d\n",
+                       ret);
+       }
+       kfree(assoc_req);
+       LEAVE();
+}
+
+
+/*
+ * Caller MUST hold any necessary locks
+ */
+struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
+{
+       struct assoc_request * assoc_req;
+
+       if (!adapter->assoc_req) {
+               adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL);
+               if (!adapter->assoc_req) {
+                       lbs_pr_info("Not enough memory to allocate association"
+                               " request!\n");
+                       return NULL;
+               }
+       }
+
+       /* Copy current configuration attributes to the association request,
+        * but don't overwrite any that are already set.
+        */
+       assoc_req = adapter->assoc_req;
+       if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+               memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid,
+                       adapter->curbssparams.ssid.ssidlength);
+       }
+
+       if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
+               assoc_req->channel = adapter->curbssparams.channel;
+
+       if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
+               assoc_req->mode = adapter->inframode;
+
+       if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+               memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
+                       ETH_ALEN);
+       }
+
+       if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
+               int i;
+               for (i = 0; i < 4; i++) {
+                       memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
+                               sizeof(struct WLAN_802_11_KEY));
+               }
+       }
+
+       if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
+               assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
+
+       if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
+               memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
+                       sizeof(struct WLAN_802_11_KEY));
+       }
+
+       if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+               memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
+                       sizeof(struct WLAN_802_11_KEY));
+       }
+
+       if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+               memcpy(&assoc_req->secinfo, &adapter->secinfo,
+                       sizeof(struct wlan_802_11_security));
+       }
+
+       if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+               memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
+                       MAX_WPA_IE_LEN);
+               assoc_req->wpa_ie_len = adapter->wpa_ie_len;
+       }
+
+       return assoc_req;
+}
+
+
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
new file mode 100644 (file)
index 0000000..2ffd82d
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2006, Red Hat, Inc. */
+
+#ifndef _WLAN_ASSOC_H_
+#define _WLAN_ASSOC_H_
+
+#include "dev.h"
+
+void wlan_association_worker(struct work_struct *work);
+
+struct assoc_request * wlan_get_association_request(wlan_adapter *adapter);
+
+#define ASSOC_DELAY (HZ / 2)
+static inline void wlan_postpone_association_work(wlan_private *priv)
+{
+       if (priv->adapter->surpriseremoved)
+               return;
+       cancel_delayed_work(&priv->assoc_work);
+       queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
+}
+
+static inline void wlan_cancel_association_work(wlan_private *priv)
+{
+       cancel_delayed_work(&priv->assoc_work);
+       if (priv->adapter->assoc_req) {
+               kfree(priv->adapter->assoc_req);
+               priv->adapter->assoc_req = NULL;
+       }
+}
+
+#endif /* _WLAN_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
new file mode 100644 (file)
index 0000000..bfdac58
--- /dev/null
@@ -0,0 +1,1958 @@
+/**
+  * This file contains the handling of command.
+  * It prepares command and sends it to firmware when it is ready.
+  */
+
+#include <net/iw_handler.h>
+#include "host.h"
+#include "hostcmd.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
+
+static u16 commands_allowed_in_ps[] = {
+       cmd_802_11_rssi,
+};
+
+/**
+ *  @brief This function checks if the commans is allowed
+ *  in PS mode not.
+ *
+ *  @param command the command ID
+ *  @return       TRUE or FALSE
+ */
+static u8 is_command_allowed_in_ps(u16 command)
+{
+       int count = sizeof(commands_allowed_in_ps)
+           / sizeof(commands_allowed_in_ps[0]);
+       int i;
+
+       for (i = 0; i < count; i++) {
+               if (command == cpu_to_le16(commands_allowed_in_ps[i]))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd)
+{
+       struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
+
+       ENTER();
+
+       cmd->command = cpu_to_le16(cmd_get_hw_spec);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
+       memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
+                                  struct cmd_ds_command *cmd,
+                                  u16 cmd_action)
+{
+       struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
+       u16 action = cmd_action;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       cmd->command = cpu_to_le16(cmd_802_11_ps_mode);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
+                            S_DS_GEN);
+       psm->action = cpu_to_le16(cmd_action);
+       psm->multipledtim = 0;
+       switch (action) {
+       case cmd_subcmd_enter_ps:
+               lbs_pr_debug(1, "PS command:" "SubCode- Enter PS\n");
+               lbs_pr_debug(1, "locallisteninterval = %d\n",
+                      adapter->locallisteninterval);
+
+               psm->locallisteninterval =
+                   cpu_to_le16(adapter->locallisteninterval);
+               psm->nullpktinterval =
+                   cpu_to_le16(adapter->nullpktinterval);
+               psm->multipledtim =
+                   cpu_to_le16(priv->adapter->multipledtim);
+               break;
+
+       case cmd_subcmd_exit_ps:
+               lbs_pr_debug(1, "PS command:" "SubCode- Exit PS\n");
+               break;
+
+       case cmd_subcmd_sleep_confirmed:
+               lbs_pr_debug(1, "PS command: SubCode- sleep confirm\n");
+               break;
+
+       default:
+               break;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
+                                             struct cmd_ds_command *cmd,
+                                             u16 cmd_action, void *pdata_buf)
+{
+       u16 *timeout = pdata_buf;
+
+       cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
+                            + S_DS_GEN);
+
+       cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action);
+
+       if (cmd_action)
+               cmd->params.inactivity_timeout.timeout =
+                   cpu_to_le16(*timeout);
+       else
+               cmd->params.inactivity_timeout.timeout = 0;
+
+       return 0;
+}
+
+static int wlan_cmd_802_11_sleep_params(wlan_private * priv,
+                                       struct cmd_ds_command *cmd,
+                                       u16 cmd_action)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
+
+       ENTER();
+
+       cmd->size =
+           cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
+                            S_DS_GEN);
+       cmd->command = cpu_to_le16(cmd_802_11_sleep_params);
+
+       if (cmd_action == cmd_act_get) {
+               memset(&adapter->sp, 0, sizeof(struct sleep_params));
+               memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
+               sp->action = cpu_to_le16(cmd_action);
+       } else if (cmd_action == cmd_act_set) {
+               sp->action = cpu_to_le16(cmd_action);
+               sp->error = cpu_to_le16(adapter->sp.sp_error);
+               sp->offset = cpu_to_le16(adapter->sp.sp_offset);
+               sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime);
+               sp->calcontrol = (u8) adapter->sp.sp_calcontrol;
+               sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk;
+               sp->reserved = cpu_to_le16(adapter->sp.sp_reserved);
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_cmd_802_11_set_wep(wlan_private * priv,
+                                   struct cmd_ds_command *cmd,
+                                   u32 cmd_act,
+                                   void * pdata_buf)
+{
+       struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       struct assoc_request * assoc_req = pdata_buf;
+
+       ENTER();
+
+       cmd->command = cpu_to_le16(cmd_802_11_set_wep);
+       cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_set_wep))
+                                    + S_DS_GEN);
+
+       if (cmd_act == cmd_act_add) {
+               int i;
+
+               if (!assoc_req) {
+                       lbs_pr_debug(1, "Invalid association request!");
+                       ret = -1;
+                       goto done;
+               }
+
+               wep->action = cpu_to_le16(cmd_act_add);
+
+               /* default tx key index */
+               wep->keyindex = cpu_to_le16((u16)
+                                                (assoc_req->wep_tx_keyidx &
+                                                (u32)cmd_WEP_KEY_INDEX_MASK));
+
+               lbs_pr_debug(1, "Tx key Index: %u\n", wep->keyindex);
+
+               /* Copy key types and material to host command structure */
+               for (i = 0; i < 4; i++) {
+                       struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i];
+
+                       switch (pkey->len) {
+                       case KEY_LEN_WEP_40:
+                               wep->keytype[i] = cmd_type_wep_40_bit;
+                               memmove(&wep->keymaterial[i], pkey->key,
+                                       pkey->len);
+                               break;
+                       case KEY_LEN_WEP_104:
+                               wep->keytype[i] = cmd_type_wep_104_bit;
+                               memmove(&wep->keymaterial[i], pkey->key,
+                                       pkey->len);
+                               break;
+                       case 0:
+                               break;
+                       default:
+                               lbs_pr_debug(1, "Invalid WEP key %d length of %d\n",
+                                      i, pkey->len);
+                               ret = -1;
+                               goto done;
+                               break;
+                       }
+               }
+       } else if (cmd_act == cmd_act_remove) {
+               /* ACT_REMOVE clears _all_ WEP keys */
+               wep->action = cpu_to_le16(cmd_act_remove);
+
+               /* default tx key index */
+               wep->keyindex = cpu_to_le16((u16)
+                                                (adapter->wep_tx_keyidx &
+                                                (u32)cmd_WEP_KEY_INDEX_MASK));
+       }
+
+       ret = 0;
+
+done:
+       LEAVE();
+       return ret;
+}
+
+static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
+                                     struct cmd_ds_command *cmd,
+                                     u16 cmd_action)
+{
+       struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
+       wlan_adapter *adapter = priv->adapter;
+
+       cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) +
+                            S_DS_GEN);
+       penableRSN->action = cpu_to_le16(cmd_action);
+       if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+               penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
+       } else {
+               penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
+       }
+
+       return 0;
+}
+
+
+static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
+                            struct WLAN_802_11_KEY * pkey)
+{
+       pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
+
+       if (pkey->flags & KEY_INFO_WPA_ENABLED) {
+               pkeyparamset->keyinfo = cpu_to_le16(KEY_INFO_WPA_ENABLED);
+       } else {
+               pkeyparamset->keyinfo = cpu_to_le16(!KEY_INFO_WPA_ENABLED);
+       }
+
+       if (pkey->flags & KEY_INFO_WPA_UNICAST) {
+               pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
+       } else if (pkey->flags & KEY_INFO_WPA_MCAST) {
+               pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
+       }
+
+       pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+       pkeyparamset->keylen = cpu_to_le16(pkey->len);
+       memcpy(pkeyparamset->key, pkey->key, pkey->len);
+       pkeyparamset->length = cpu_to_le16(  sizeof(pkeyparamset->keytypeid)
+                                               + sizeof(pkeyparamset->keyinfo)
+                                               + sizeof(pkeyparamset->keylen)
+                                               + sizeof(pkeyparamset->key));
+}
+
+static int wlan_cmd_802_11_key_material(wlan_private * priv,
+                                       struct cmd_ds_command *cmd,
+                                       u16 cmd_action,
+                                       u32 cmd_oid, void *pdata_buf)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ds_802_11_key_material *pkeymaterial =
+           &cmd->params.keymaterial;
+       int ret = 0;
+       int index = 0;
+
+       ENTER();
+
+       cmd->command = cpu_to_le16(cmd_802_11_key_material);
+       pkeymaterial->action = cpu_to_le16(cmd_action);
+
+       if (cmd_action == cmd_act_get) {
+               cmd->size = cpu_to_le16(  S_DS_GEN
+                                            + sizeof (pkeymaterial->action));
+               ret = 0;
+               goto done;
+       }
+
+       memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
+
+       if (adapter->wpa_unicast_key.len) {
+               set_one_wpa_key(&pkeymaterial->keyParamSet[index],
+                               &adapter->wpa_unicast_key);
+               index++;
+       }
+
+       if (adapter->wpa_mcast_key.len) {
+               set_one_wpa_key(&pkeymaterial->keyParamSet[index],
+                               &adapter->wpa_mcast_key);
+               index++;
+       }
+
+       cmd->size = cpu_to_le16(  S_DS_GEN
+                                    + sizeof (pkeymaterial->action)
+                                    + index * sizeof(struct MrvlIEtype_keyParamSet));
+
+       ret = 0;
+
+done:
+       LEAVE();
+       return ret;
+}
+
+static int wlan_cmd_802_11_reset(wlan_private * priv,
+                                struct cmd_ds_command *cmd, int cmd_action)
+{
+       struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
+
+       cmd->command = cpu_to_le16(cmd_802_11_reset);
+       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
+       reset->action = cpu_to_le16(cmd_action);
+
+       return 0;
+}
+
+static int wlan_cmd_802_11_get_log(wlan_private * priv,
+                                  struct cmd_ds_command *cmd)
+{
+       cmd->command = cpu_to_le16(cmd_802_11_get_log);
+       cmd->size =
+               cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
+
+       return 0;
+}
+
+static int wlan_cmd_802_11_get_stat(wlan_private * priv,
+                                   struct cmd_ds_command *cmd)
+{
+       cmd->command = cpu_to_le16(cmd_802_11_get_stat);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) +
+                            S_DS_GEN);
+
+       return 0;
+}
+
+static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
+                                   struct cmd_ds_command *cmd,
+                                   int cmd_action,
+                                   int cmd_oid, void *pdata_buf)
+{
+       struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
+       wlan_adapter *adapter = priv->adapter;
+       u8 ucTemp;
+
+       ENTER();
+
+       lbs_pr_debug(1, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+
+       cmd->command = cpu_to_le16(cmd_802_11_snmp_mib);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_snmp_mib) +
+                            S_DS_GEN);
+
+       switch (cmd_oid) {
+       case OID_802_11_INFRASTRUCTURE_MODE:
+       {
+               enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode =
+                       (enum WLAN_802_11_NETWORK_INFRASTRUCTURE) pdata_buf;
+               pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+               pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i);
+               pSNMPMIB->bufsize = sizeof(u8);
+               if (mode == wlan802_11infrastructure)
+                       ucTemp = SNMP_MIB_VALUE_INFRA;
+               else
+                       ucTemp = SNMP_MIB_VALUE_ADHOC;
+
+               memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
+
+               break;
+       }
+
+       case OID_802_11D_ENABLE:
+               {
+                       u32 ulTemp;
+
+                       pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i);
+
+                       if (cmd_action == cmd_act_set) {
+                               pSNMPMIB->querytype = cmd_act_set;
+                               pSNMPMIB->bufsize = sizeof(u16);
+                               ulTemp = *(u32 *)pdata_buf;
+                               *((unsigned short *)(pSNMPMIB->value)) =
+                                   cpu_to_le16((u16) ulTemp);
+                       }
+                       break;
+               }
+
+       case OID_802_11_FRAGMENTATION_THRESHOLD:
+               {
+                       u32 ulTemp;
+
+                       pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i);
+
+                       if (cmd_action == cmd_act_get) {
+                               pSNMPMIB->querytype =
+                                   cpu_to_le16(cmd_act_get);
+                       } else if (cmd_action == cmd_act_set) {
+                               pSNMPMIB->querytype =
+                                   cpu_to_le16(cmd_act_set);
+                               pSNMPMIB->bufsize =
+                                   cpu_to_le16(sizeof(u16));
+                               ulTemp = *((u32 *) pdata_buf);
+                               *((unsigned short *)(pSNMPMIB->value)) =
+                                   cpu_to_le16((u16) ulTemp);
+
+                       }
+
+                       break;
+               }
+
+       case OID_802_11_RTS_THRESHOLD:
+               {
+
+                       u32 ulTemp;
+                       pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i);
+
+                       if (cmd_action == cmd_act_get) {
+                               pSNMPMIB->querytype =
+                                   cpu_to_le16(cmd_act_get);
+                       } else if (cmd_action == cmd_act_set) {
+                               pSNMPMIB->querytype =
+                                   cpu_to_le16(cmd_act_set);
+                               pSNMPMIB->bufsize =
+                                   cpu_to_le16(sizeof(u16));
+                               ulTemp = *((u32 *)
+                                          pdata_buf);
+                               *(unsigned short *)(pSNMPMIB->value) =
+                                   cpu_to_le16((u16) ulTemp);
+
+                       }
+                       break;
+               }
+       case OID_802_11_TX_RETRYCOUNT:
+               pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i);
+
+               if (cmd_action == cmd_act_get) {
+                       pSNMPMIB->querytype =
+                           cpu_to_le16(cmd_act_get);
+               } else if (cmd_action == cmd_act_set) {
+                       pSNMPMIB->querytype =
+                           cpu_to_le16(cmd_act_set);
+                       pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
+                       *((unsigned short *)(pSNMPMIB->value)) =
+                           cpu_to_le16((u16) adapter->txretrycount);
+               }
+
+               break;
+       default:
+               break;
+       }
+
+       lbs_pr_debug(1,
+              "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
+              cmd->command, cmd->size, cmd->seqnum, cmd->result);
+
+       lbs_pr_debug(1,
+              "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n",
+              pSNMPMIB->querytype, pSNMPMIB->oid, pSNMPMIB->bufsize,
+              *(u16 *) pSNMPMIB->value);
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_cmd_802_11_radio_control(wlan_private * priv,
+                                        struct cmd_ds_command *cmd,
+                                        int cmd_action)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ds_802_11_radio_control *pradiocontrol =
+           &cmd->params.radio;
+
+       ENTER();
+
+       cmd->size =
+           cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
+                            S_DS_GEN);
+       cmd->command = cpu_to_le16(cmd_802_11_radio_control);
+
+       pradiocontrol->action = cpu_to_le16(cmd_action);
+
+       switch (adapter->preamble) {
+       case cmd_type_short_preamble:
+               pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
+               break;
+
+       case cmd_type_long_preamble:
+               pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
+               break;
+
+       case cmd_type_auto_preamble:
+       default:
+               pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
+               break;
+       }
+
+       if (adapter->radioon)
+               pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
+       else
+               pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
+                                      struct cmd_ds_command *cmd,
+                                      u16 cmd_action, void *pdata_buf)
+{
+
+       struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
+
+       ENTER();
+
+       cmd->size =
+           cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) +
+                            S_DS_GEN);
+       cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power);
+       prtp->action = cmd_action;
+
+       lbs_pr_debug(1, "RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", cmd->size,
+              cmd->command, prtp->action);
+
+       switch (cmd_action) {
+       case cmd_act_tx_power_opt_get:
+               prtp->action = cpu_to_le16(cmd_act_get);
+               prtp->currentlevel = 0;
+               break;
+
+       case cmd_act_tx_power_opt_set_high:
+               prtp->action = cpu_to_le16(cmd_act_set);
+               prtp->currentlevel =
+                   cpu_to_le16(cmd_act_tx_power_index_high);
+               break;
+
+       case cmd_act_tx_power_opt_set_mid:
+               prtp->action = cpu_to_le16(cmd_act_set);
+               prtp->currentlevel =
+                   cpu_to_le16(cmd_act_tx_power_index_mid);
+               break;
+
+       case cmd_act_tx_power_opt_set_low:
+               prtp->action = cpu_to_le16(cmd_act_set);
+               prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
+               break;
+       }
+       LEAVE();
+       return 0;
+}
+
+static int wlan_cmd_802_11_rf_antenna(wlan_private * priv,
+                                     struct cmd_ds_command *cmd,
+                                     u16 cmd_action, void *pdata_buf)
+{
+       struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant;
+
+       cmd->command = cpu_to_le16(cmd_802_11_rf_antenna);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) +
+                            S_DS_GEN);
+
+       rant->action = cpu_to_le16(cmd_action);
+       if ((cmd_action == cmd_act_set_rx) ||
+           (cmd_action == cmd_act_set_tx)) {
+               rant->antennamode =
+                   cpu_to_le16((u16) (*(u32 *) pdata_buf));
+       }
+
+       return 0;
+}
+
+static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
+                                             struct cmd_ds_command *cmd,
+                                             u16 cmd_action)
+{
+       struct cmd_ds_802_11_rate_adapt_rateset
+       *rateadapt = &cmd->params.rateset;
+       wlan_adapter *adapter = priv->adapter;
+
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
+                            + S_DS_GEN);
+       cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset);
+
+       ENTER();
+
+       rateadapt->action = cmd_action;
+       rateadapt->enablehwauto = adapter->enablehwauto;
+       rateadapt->bitmap = adapter->ratebitmap;
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_cmd_802_11_data_rate(wlan_private * priv,
+                                    struct cmd_ds_command *cmd,
+                                    u16 cmd_action)
+{
+       struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
+       wlan_adapter *adapter = priv->adapter;
+       u16 action = cmd_action;
+
+       ENTER();
+
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
+                            S_DS_GEN);
+
+       cmd->command = cpu_to_le16(cmd_802_11_data_rate);
+
+       memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
+
+       pdatarate->action = cpu_to_le16(cmd_action);
+
+       if (action == cmd_act_set_tx_fix_rate) {
+               pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate);
+               lbs_pr_debug(1, "Setting FW for fixed rate 0x%02X\n",
+                      adapter->datarate);
+       } else if (action == cmd_act_set_tx_auto) {
+               lbs_pr_debug(1, "Setting FW for AUTO rate\n");
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
+                                     struct cmd_ds_command *cmd,
+                                     u16 cmd_action)
+{
+       struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
+       wlan_adapter *adapter = priv->adapter;
+
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
+                            S_DS_GEN);
+       cmd->command = cpu_to_le16(cmd_mac_multicast_adr);
+
+       pMCastAdr->action = cpu_to_le16(cmd_action);
+       pMCastAdr->nr_of_adrs =
+           cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
+       memcpy(pMCastAdr->maclist, adapter->multicastlist,
+              adapter->nr_of_multicastmacaddr * ETH_ALEN);
+
+       return 0;
+}
+
+static int wlan_cmd_802_11_rf_channel(wlan_private * priv,
+                                     struct cmd_ds_command *cmd,
+                                     int option, void *pdata_buf)
+{
+       struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
+
+       cmd->command = cpu_to_le16(cmd_802_11_rf_channel);
+       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel)
+                                    + S_DS_GEN);
+
+       if (option == cmd_opt_802_11_rf_channel_set) {
+               rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
+       }
+
+       rfchan->action = cpu_to_le16(option);
+
+       return 0;
+}
+
+static int wlan_cmd_802_11_rssi(wlan_private * priv,
+                               struct cmd_ds_command *cmd)
+{
+       wlan_adapter *adapter = priv->adapter;
+
+       cmd->command = cpu_to_le16(cmd_802_11_rssi);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
+       cmd->params.rssi.N = priv->adapter->bcn_avg_factor;
+
+       /* reset Beacon SNR/NF/RSSI values */
+       adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
+       adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0;
+       adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
+       adapter->NF[TYPE_BEACON][TYPE_AVG] = 0;
+       adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
+       adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+
+       return 0;
+}
+
+static int wlan_cmd_reg_access(wlan_private * priv,
+                              struct cmd_ds_command *cmdptr,
+                              u8 cmd_action, void *pdata_buf)
+{
+       struct wlan_offset_value *offval;
+
+       ENTER();
+
+       offval = (struct wlan_offset_value *)pdata_buf;
+
+       switch (cmdptr->command) {
+       case cmd_mac_reg_access:
+               {
+                       struct cmd_ds_mac_reg_access *macreg;
+
+                       cmdptr->size =
+                           cpu_to_le16(sizeof
+                                            (struct cmd_ds_mac_reg_access)
+                                            + S_DS_GEN);
+                       macreg =
+                           (struct cmd_ds_mac_reg_access *)&cmdptr->params.
+                           macreg;
+
+                       macreg->action = cpu_to_le16(cmd_action);
+                       macreg->offset = cpu_to_le16((u16) offval->offset);
+                       macreg->value = cpu_to_le32(offval->value);
+
+                       break;
+               }
+
+       case cmd_bbp_reg_access:
+               {
+                       struct cmd_ds_bbp_reg_access *bbpreg;
+
+                       cmdptr->size =
+                           cpu_to_le16(sizeof
+                                            (struct cmd_ds_bbp_reg_access)
+                                            + S_DS_GEN);
+                       bbpreg =
+                           (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
+                           bbpreg;
+
+                       bbpreg->action = cpu_to_le16(cmd_action);
+                       bbpreg->offset = cpu_to_le16((u16) offval->offset);
+                       bbpreg->value = (u8) offval->value;
+
+                       break;
+               }
+
+       case cmd_rf_reg_access:
+               {
+                       struct cmd_ds_rf_reg_access *rfreg;
+
+                       cmdptr->size =
+                           cpu_to_le16(sizeof
+                                            (struct cmd_ds_rf_reg_access) +
+                                            S_DS_GEN);
+                       rfreg =
+                           (struct cmd_ds_rf_reg_access *)&cmdptr->params.
+                           rfreg;
+
+                       rfreg->action = cpu_to_le16(cmd_action);
+                       rfreg->offset = cpu_to_le16((u16) offval->offset);
+                       rfreg->value = (u8) offval->value;
+
+                       break;
+               }
+
+       default:
+               break;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_cmd_802_11_mac_address(wlan_private * priv,
+                                      struct cmd_ds_command *cmd,
+                                      u16 cmd_action)
+{
+       wlan_adapter *adapter = priv->adapter;
+
+       cmd->command = cpu_to_le16(cmd_802_11_mac_address);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
+                            S_DS_GEN);
+       cmd->result = 0;
+
+       cmd->params.macadd.action = cpu_to_le16(cmd_action);
+
+       if (cmd_action == cmd_act_set) {
+               memcpy(cmd->params.macadd.macadd,
+                      adapter->current_addr, ETH_ALEN);
+               lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6);
+       }
+
+       return 0;
+}
+
+static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
+                                        struct cmd_ds_command *cmd,
+                                        int cmd_action, void *pdata_buf)
+{
+       struct wlan_ioctl_regrdwr *ea = pdata_buf;
+
+       ENTER();
+
+       cmd->command = cpu_to_le16(cmd_802_11_eeprom_access);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
+                            S_DS_GEN);
+       cmd->result = 0;
+
+       cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
+       cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
+       cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
+       cmd->params.rdeeprom.value = 0;
+
+       return 0;
+}
+
+static int wlan_cmd_bt_access(wlan_private * priv,
+                              struct cmd_ds_command *cmd,
+                              u16 cmd_action, void *pdata_buf)
+{
+       struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
+       lbs_pr_debug(1, "BT CMD(%d)\n", cmd_action);
+
+       cmd->command = cpu_to_le16(cmd_bt_access);
+       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access)
+                                    + S_DS_GEN);
+       cmd->result = 0;
+       bt_access->action = cpu_to_le16(cmd_action);
+
+       switch (cmd_action) {
+       case cmd_act_bt_access_add:
+               memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
+               lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6);
+               break;
+       case cmd_act_bt_access_del:
+               memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
+               lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6);
+               break;
+       case cmd_act_bt_access_list:
+               bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
+               break;
+       case cmd_act_bt_access_reset:
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int wlan_cmd_fwt_access(wlan_private * priv,
+                              struct cmd_ds_command *cmd,
+                              u16 cmd_action, void *pdata_buf)
+{
+       struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
+       lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
+
+       cmd->command = cpu_to_le16(cmd_fwt_access);
+       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access)
+                                    + S_DS_GEN);
+       cmd->result = 0;
+
+       if (pdata_buf)
+               memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
+       else
+               memset(fwt_access, 0, sizeof(*fwt_access));
+
+       fwt_access->action = cpu_to_le16(cmd_action);
+
+       return 0;
+}
+
+static int wlan_cmd_mesh_access(wlan_private * priv,
+                               struct cmd_ds_command *cmd,
+                               u16 cmd_action, void *pdata_buf)
+{
+       struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
+       lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
+
+       cmd->command = cpu_to_le16(cmd_mesh_access);
+       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access)
+                                    + S_DS_GEN);
+       cmd->result = 0;
+
+       if (pdata_buf)
+               memcpy(mesh_access, pdata_buf, sizeof(*mesh_access));
+       else
+               memset(mesh_access, 0, sizeof(*mesh_access));
+
+       mesh_access->action = cpu_to_le16(cmd_action);
+
+       return 0;
+}
+
+void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail)
+{
+       unsigned long flags;
+       struct cmd_ds_command *cmdptr;
+
+       ENTER();
+
+       if (!cmdnode) {
+               lbs_pr_debug(1, "QUEUE_CMD: cmdnode is NULL\n");
+               goto done;
+       }
+
+       cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+       if (!cmdptr) {
+               lbs_pr_debug(1, "QUEUE_CMD: cmdptr is NULL\n");
+               goto done;
+       }
+
+       /* Exit_PS command needs to be queued in the header always. */
+       if (cmdptr->command == cmd_802_11_ps_mode) {
+               struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
+               if (psm->action == cmd_subcmd_exit_ps) {
+                       if (adapter->psstate != PS_STATE_FULL_POWER)
+                               addtail = 0;
+               }
+       }
+
+       spin_lock_irqsave(&adapter->driver_lock, flags);
+
+       if (addtail)
+               list_add_tail((struct list_head *)cmdnode,
+                             &adapter->cmdpendingq);
+       else
+               list_add((struct list_head *)cmdnode, &adapter->cmdpendingq);
+
+       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+       lbs_pr_debug(1, "QUEUE_CMD: Inserted node=0x%x, cmd=0x%x in cmdpendingq\n",
+              (u32) cmdnode,
+              ((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command);
+
+done:
+       LEAVE();
+       return;
+}
+
+/*
+ * TODO: Fix the issue when DownloadcommandToStation is being called the
+ * second time when the command timesout. All the cmdptr->xxx are in little
+ * endian and therefore all the comparissions will fail.
+ * For now - we are not performing the endian conversion the second time - but
+ * for PS and DEEP_SLEEP we need to worry
+ */
+static int DownloadcommandToStation(wlan_private * priv,
+                                   struct cmd_ctrl_node *cmdnode)
+{
+       unsigned long flags;
+       struct cmd_ds_command *cmdptr;
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       u16 cmdsize;
+       u16 command;
+
+       ENTER();
+
+       if (!adapter || !cmdnode) {
+               lbs_pr_debug(1, "DNLD_CMD: adapter = %#x, cmdnode = %#x\n",
+                      (int)adapter, (int)cmdnode);
+               if (cmdnode) {
+                       spin_lock_irqsave(&adapter->driver_lock, flags);
+                       __libertas_cleanup_and_insert_cmd(priv, cmdnode);
+                       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               }
+               ret = -1;
+               goto done;
+       }
+
+       cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+
+       spin_lock_irqsave(&adapter->driver_lock, flags);
+       if (!cmdptr || !cmdptr->size) {
+               lbs_pr_debug(1, "DNLD_CMD: cmdptr is Null or cmd size is Zero, "
+                      "Not sending\n");
+               __libertas_cleanup_and_insert_cmd(priv, cmdnode);
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               ret = -1;
+               goto done;
+       }
+
+       adapter->cur_cmd = cmdnode;
+       adapter->cur_cmd_retcode = 0;
+       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+       lbs_pr_debug(1, "DNLD_CMD:: Before download, size of cmd = %d\n",
+              cmdptr->size);
+
+       cmdsize = cmdptr->size;
+
+       command = cpu_to_le16(cmdptr->command);
+
+       cmdnode->cmdwaitqwoken = 0;
+       cmdsize = cpu_to_le16(cmdsize);
+
+       ret = libertas_sbi_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
+
+       if (ret != 0) {
+               lbs_pr_debug(1, "DNLD_CMD: Host to Card failed\n");
+               spin_lock_irqsave(&adapter->driver_lock, flags);
+               __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+               adapter->cur_cmd = NULL;
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               ret = -1;
+               goto done;
+       }
+
+       lbs_pr_debug(1, "DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies);
+       lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize);
+
+       /* Setup the timer after transmit command */
+       if (command == cmd_802_11_scan
+           || command == cmd_802_11_authenticate
+           || command == cmd_802_11_associate)
+               mod_timer(&adapter->command_timer, jiffies + (10*HZ));
+       else
+               mod_timer(&adapter->command_timer, jiffies + (5*HZ));
+
+       ret = 0;
+
+      done:
+       LEAVE();
+       return ret;
+}
+
+static int wlan_cmd_mac_control(wlan_private * priv,
+                               struct cmd_ds_command *cmd)
+{
+       struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
+
+       ENTER();
+
+       cmd->command = cpu_to_le16(cmd_mac_control);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
+       mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
+
+       lbs_pr_debug(1, "wlan_cmd_mac_control(): action=0x%X size=%d\n",
+              mac->action, cmd->size);
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  This function inserts command node to cmdfreeq
+ *  after cleans it. Requires adapter->driver_lock held.
+ */
+void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+{
+       wlan_adapter *adapter = priv->adapter;
+
+       if (!ptempcmd)
+               goto done;
+
+       cleanup_cmdnode(ptempcmd);
+       list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
+done:
+       return;
+}
+
+void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+       __libertas_cleanup_and_insert_cmd(priv, ptempcmd);
+       spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+}
+
+int libertas_set_radio_control(wlan_private * priv)
+{
+       int ret = 0;
+
+       ENTER();
+
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_radio_control,
+                                   cmd_act_set,
+                                   cmd_option_waitforrsp, 0, NULL);
+
+       lbs_pr_debug(1, "RADIO_SET: on or off: 0x%X, preamble = 0x%X\n",
+              priv->adapter->radioon, priv->adapter->preamble);
+
+       LEAVE();
+       return ret;
+}
+
+int libertas_set_mac_packet_filter(wlan_private * priv)
+{
+       int ret = 0;
+
+       ENTER();
+
+       lbs_pr_debug(1, "libertas_set_mac_packet_filter value = %x\n",
+              priv->adapter->currentpacketfilter);
+
+       /* Send MAC control command to station */
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_mac_control, 0, 0, 0, NULL);
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief This function prepare the command before send to firmware.
+ *
+ *  @param priv                A pointer to wlan_private structure
+ *  @param cmd_no      command number
+ *  @param cmd_action  command action: GET or SET
+ *  @param wait_option wait option: wait response or not
+ *  @param cmd_oid     cmd oid: treated as sub command
+ *  @param pdata_buf   A pointer to informaion buffer
+ *  @return            0 or -1
+ */
+int libertas_prepare_and_send_command(wlan_private * priv,
+                         u16 cmd_no,
+                         u16 cmd_action,
+                         u16 wait_option, u32 cmd_oid, void *pdata_buf)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *cmdnode;
+       struct cmd_ds_command *cmdptr;
+       unsigned long flags;
+
+       ENTER();
+
+       if (!adapter) {
+               lbs_pr_debug(1, "PREP_CMD: adapter is Null\n");
+               ret = -1;
+               goto done;
+       }
+
+       if (adapter->surpriseremoved) {
+               lbs_pr_debug(1, "PREP_CMD: Card is Removed\n");
+               ret = -1;
+               goto done;
+       }
+
+       cmdnode = libertas_get_free_cmd_ctrl_node(priv);
+
+       if (cmdnode == NULL) {
+               lbs_pr_debug(1, "PREP_CMD: No free cmdnode\n");
+
+               /* Wake up main thread to execute next command */
+               wake_up_interruptible(&priv->mainthread.waitq);
+               ret = -1;
+               goto done;
+       }
+
+       libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf);
+
+       cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+       lbs_pr_debug(1, "PREP_CMD: Val of cmd ptr =0x%x, command=0x%X\n",
+              (u32) cmdptr, cmd_no);
+
+       if (!cmdptr) {
+               lbs_pr_debug(1, "PREP_CMD: bufvirtualaddr of cmdnode is NULL\n");
+               libertas_cleanup_and_insert_cmd(priv, cmdnode);
+               ret = -1;
+               goto done;
+       }
+
+       /* Set sequence number, command and INT option */
+       adapter->seqnum++;
+       cmdptr->seqnum = cpu_to_le16(adapter->seqnum);
+
+       cmdptr->command = cmd_no;
+       cmdptr->result = 0;
+
+       switch (cmd_no) {
+       case cmd_get_hw_spec:
+               ret = wlan_cmd_hw_spec(priv, cmdptr);
+               break;
+       case cmd_802_11_ps_mode:
+               ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
+               break;
+
+       case cmd_802_11_scan:
+               ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
+               break;
+
+       case cmd_mac_control:
+               ret = wlan_cmd_mac_control(priv, cmdptr);
+               break;
+
+       case cmd_802_11_associate:
+       case cmd_802_11_reassociate:
+               ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
+               break;
+
+       case cmd_802_11_deauthenticate:
+               ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
+               break;
+
+       case cmd_802_11_set_wep:
+               ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
+               break;
+
+       case cmd_802_11_ad_hoc_start:
+               ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
+               break;
+       case cmd_code_dnld:
+               break;
+
+       case cmd_802_11_reset:
+               ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
+               break;
+
+       case cmd_802_11_get_log:
+               ret = wlan_cmd_802_11_get_log(priv, cmdptr);
+               break;
+
+       case cmd_802_11_authenticate:
+               ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
+               break;
+
+       case cmd_802_11_get_stat:
+               ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
+               break;
+
+       case cmd_802_11_snmp_mib:
+               ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
+                                              cmd_action, cmd_oid, pdata_buf);
+               break;
+
+       case cmd_mac_reg_access:
+       case cmd_bbp_reg_access:
+       case cmd_rf_reg_access:
+               ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
+               break;
+
+       case cmd_802_11_rf_channel:
+               ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
+                                                cmd_action, pdata_buf);
+               break;
+
+       case cmd_802_11_rf_tx_power:
+               ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
+                                                 cmd_action, pdata_buf);
+               break;
+
+       case cmd_802_11_radio_control:
+               ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
+               break;
+
+       case cmd_802_11_rf_antenna:
+               ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr,
+                                                cmd_action, pdata_buf);
+               break;
+
+       case cmd_802_11_data_rate:
+               ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
+               break;
+       case cmd_802_11_rate_adapt_rateset:
+               ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
+                                                        cmdptr, cmd_action);
+               break;
+
+       case cmd_mac_multicast_adr:
+               ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
+               break;
+
+       case cmd_802_11_ad_hoc_join:
+               ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
+               break;
+
+       case cmd_802_11_rssi:
+               ret = wlan_cmd_802_11_rssi(priv, cmdptr);
+               break;
+
+       case cmd_802_11_ad_hoc_stop:
+               ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
+               break;
+
+       case cmd_802_11_enable_rsn:
+               ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action);
+               break;
+
+       case cmd_802_11_key_material:
+               ret = wlan_cmd_802_11_key_material(priv, cmdptr,
+                                                  cmd_action, cmd_oid,
+                                                  pdata_buf);
+               break;
+
+       case cmd_802_11_pairwise_tsc:
+               break;
+       case cmd_802_11_group_tsc:
+               break;
+
+       case cmd_802_11_mac_address:
+               ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
+               break;
+
+       case cmd_802_11_eeprom_access:
+               ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
+                                                   cmd_action, pdata_buf);
+               break;
+
+       case cmd_802_11_set_afc:
+       case cmd_802_11_get_afc:
+
+               cmdptr->command = cpu_to_le16(cmd_no);
+               cmdptr->size =
+                   cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
+                                    S_DS_GEN);
+
+               memmove(&cmdptr->params.afc,
+                       pdata_buf, sizeof(struct cmd_ds_802_11_afc));
+
+               ret = 0;
+               goto done;
+
+       case cmd_802_11d_domain_info:
+               ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
+                                                  cmd_no, cmd_action);
+               break;
+
+       case cmd_802_11_sleep_params:
+               ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
+               break;
+       case cmd_802_11_inactivity_timeout:
+               ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
+                                                        cmd_action, pdata_buf);
+               libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
+               break;
+
+       case cmd_802_11_tpc_cfg:
+               cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg);
+               cmdptr->size =
+                   cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
+                                    S_DS_GEN);
+
+               memmove(&cmdptr->params.tpccfg,
+                       pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
+
+               ret = 0;
+               break;
+       case cmd_802_11_led_gpio_ctrl:
+               {
+                       struct mrvlietypes_ledgpio *gpio =
+                           (struct mrvlietypes_ledgpio*)
+                           cmdptr->params.ledgpio.data;
+
+                       memmove(&cmdptr->params.ledgpio,
+                               pdata_buf,
+                               sizeof(struct cmd_ds_802_11_led_ctrl));
+
+                       cmdptr->command =
+                           cpu_to_le16(cmd_802_11_led_gpio_ctrl);
+
+#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
+                       cmdptr->size =
+                           cpu_to_le16(gpio->header.len + S_DS_GEN +
+                                            ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
+                       gpio->header.len = cpu_to_le16(gpio->header.len);
+
+                       ret = 0;
+                       break;
+               }
+       case cmd_802_11_pwr_cfg:
+               cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg);
+               cmdptr->size =
+                   cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
+                                    S_DS_GEN);
+               memmove(&cmdptr->params.pwrcfg, pdata_buf,
+                       sizeof(struct cmd_ds_802_11_pwr_cfg));
+
+               ret = 0;
+               break;
+       case cmd_bt_access:
+               ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
+               break;
+
+       case cmd_fwt_access:
+               ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
+               break;
+
+       case cmd_mesh_access:
+               ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
+               break;
+
+       case cmd_get_tsf:
+               cmdptr->command = cpu_to_le16(cmd_get_tsf);
+               cmdptr->size =
+                   cpu_to_le16(sizeof(struct cmd_ds_get_tsf)
+                                    + S_DS_GEN);
+               ret = 0;
+               break;
+       case cmd_802_11_tx_rate_query:
+               cmdptr->command =
+                   cpu_to_le16(cmd_802_11_tx_rate_query);
+               cmdptr->size =
+                   cpu_to_le16(sizeof(struct cmd_tx_rate_query) +
+                                    S_DS_GEN);
+               adapter->txrate = 0;
+               ret = 0;
+               break;
+       default:
+               lbs_pr_debug(1, "PREP_CMD: unknown command- %#x\n", cmd_no);
+               ret = -1;
+               break;
+       }
+
+       /* return error, since the command preparation failed */
+       if (ret != 0) {
+               lbs_pr_debug(1, "PREP_CMD: command preparation failed\n");
+               libertas_cleanup_and_insert_cmd(priv, cmdnode);
+               ret = -1;
+               goto done;
+       }
+
+       cmdnode->cmdwaitqwoken = 0;
+
+       libertas_queue_cmd(adapter, cmdnode, 1);
+       adapter->nr_cmd_pending++;
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       if (wait_option & cmd_option_waitforrsp) {
+               lbs_pr_debug(1, "PREP_CMD: Wait for CMD response\n");
+               might_sleep();
+               wait_event_interruptible(cmdnode->cmdwait_q,
+                                        cmdnode->cmdwaitqwoken);
+       }
+
+       spin_lock_irqsave(&adapter->driver_lock, flags);
+       if (adapter->cur_cmd_retcode) {
+               lbs_pr_debug(1, "PREP_CMD: command failed with return code=%d\n",
+                      adapter->cur_cmd_retcode);
+               adapter->cur_cmd_retcode = 0;
+               ret = -1;
+       }
+       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+done:
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief This function allocates the command buffer and link
+ *  it to command free queue.
+ *
+ *  @param priv                A pointer to wlan_private structure
+ *  @return            0 or -1
+ */
+int libertas_allocate_cmd_buffer(wlan_private * priv)
+{
+       int ret = 0;
+       u32 ulbufsize;
+       u32 i;
+       struct cmd_ctrl_node *tempcmd_array;
+       u8 *ptempvirtualaddr;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       /* Allocate and initialize cmdCtrlNode */
+       ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
+
+       if (!(tempcmd_array = kmalloc(ulbufsize, GFP_KERNEL))) {
+               lbs_pr_debug(1,
+                      "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n");
+               ret = -1;
+               goto done;
+       }
+
+       adapter->cmd_array = tempcmd_array;
+       memset(adapter->cmd_array, 0, ulbufsize);
+
+       /* Allocate and initialize command buffers */
+       ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+       for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+               if (!(ptempvirtualaddr = kmalloc(ulbufsize, GFP_KERNEL))) {
+                       lbs_pr_debug(1,
+                              "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n");
+                       ret = -1;
+                       goto done;
+               }
+
+               memset(ptempvirtualaddr, 0, ulbufsize);
+
+               /* Update command buffer virtual */
+               tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
+       }
+
+       for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+               init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
+               libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
+       }
+
+       ret = 0;
+      done:
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief This function frees the command buffer.
+ *
+ *  @param priv                A pointer to wlan_private structure
+ *  @return            0 or -1
+ */
+int libertas_free_cmd_buffer(wlan_private * priv)
+{
+       u32 ulbufsize;
+       unsigned int i;
+       struct cmd_ctrl_node *tempcmd_array;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       /* need to check if cmd array is allocated or not */
+       if (adapter->cmd_array == NULL) {
+               lbs_pr_debug(1, "FREE_CMD_BUF: cmd_array is Null\n");
+               goto done;
+       }
+
+       tempcmd_array = adapter->cmd_array;
+
+       /* Release shared memory buffers */
+       ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+       for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+               if (tempcmd_array[i].bufvirtualaddr) {
+                       lbs_pr_debug(1, "Free all the array\n");
+                       kfree(tempcmd_array[i].bufvirtualaddr);
+                       tempcmd_array[i].bufvirtualaddr = NULL;
+               }
+       }
+
+       /* Release cmd_ctrl_node */
+       if (adapter->cmd_array) {
+               lbs_pr_debug(1, "Free cmd_array\n");
+               kfree(adapter->cmd_array);
+               adapter->cmd_array = NULL;
+       }
+
+done:
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief This function gets a free command node if available in
+ *  command free queue.
+ *
+ *  @param priv                A pointer to wlan_private structure
+ *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
+ */
+struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
+{
+       struct cmd_ctrl_node *tempnode;
+       wlan_adapter *adapter = priv->adapter;
+       unsigned long flags;
+
+       if (!adapter)
+               return NULL;
+
+       spin_lock_irqsave(&adapter->driver_lock, flags);
+
+       if (!list_empty(&adapter->cmdfreeq)) {
+               tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
+               list_del((struct list_head *)tempnode);
+       } else {
+               lbs_pr_debug(1, "GET_CMD_NODE: cmd_ctrl_node is not available\n");
+               tempnode = NULL;
+       }
+
+       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+       if (tempnode) {
+               lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n");
+               lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n",
+                      tempnode);
+               cleanup_cmdnode(tempnode);
+       }
+
+       return tempnode;
+}
+
+/**
+ *  @brief This function cleans command node.
+ *
+ *  @param ptempnode   A pointer to cmdCtrlNode structure
+ *  @return            n/a
+ */
+static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
+{
+       if (!ptempnode)
+               return;
+       ptempnode->cmdwaitqwoken = 1;
+       wake_up_interruptible(&ptempnode->cmdwait_q);
+       ptempnode->status = 0;
+       ptempnode->cmd_oid = (u32) 0;
+       ptempnode->wait_option = 0;
+       ptempnode->pdata_buf = NULL;
+
+       if (ptempnode->bufvirtualaddr != NULL)
+               memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+       return;
+}
+
+/**
+ *  @brief This function initializes the command node.
+ *
+ *  @param priv                A pointer to wlan_private structure
+ *  @param ptempnode   A pointer to cmd_ctrl_node structure
+ *  @param cmd_oid     cmd oid: treated as sub command
+ *  @param wait_option wait option: wait response or not
+ *  @param pdata_buf   A pointer to informaion buffer
+ *  @return            0 or -1
+ */
+void libertas_set_cmd_ctrl_node(wlan_private * priv,
+                   struct cmd_ctrl_node *ptempnode,
+                   u32 cmd_oid, u16 wait_option, void *pdata_buf)
+{
+       ENTER();
+
+       if (!ptempnode)
+               return;
+
+       ptempnode->cmd_oid = cmd_oid;
+       ptempnode->wait_option = wait_option;
+       ptempnode->pdata_buf = pdata_buf;
+
+       LEAVE();
+}
+
+/**
+ *  @brief This function executes next command in command
+ *  pending queue. It will put fimware back to PS mode
+ *  if applicable.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @return       0 or -1
+ */
+int libertas_execute_next_command(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *cmdnode = NULL;
+       struct cmd_ds_command *cmdptr;
+       unsigned long flags;
+       int ret = 0;
+
+       lbs_pr_debug(1, "libertas_execute_next_command\n");
+
+       spin_lock_irqsave(&adapter->driver_lock, flags);
+
+       if (adapter->cur_cmd) {
+               lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n");
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               ret = -1;
+               goto done;
+       }
+
+       if (!list_empty(&adapter->cmdpendingq)) {
+               cmdnode = (struct cmd_ctrl_node *)
+                   adapter->cmdpendingq.next;
+       }
+
+       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+       if (cmdnode) {
+               lbs_pr_debug(1,
+                      "EXEC_NEXT_CMD: Got next command from cmdpendingq\n");
+               cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+               if (is_command_allowed_in_ps(cmdptr->command)) {
+                       if ((adapter->psstate == PS_STATE_SLEEP)
+                           || (adapter->psstate == PS_STATE_PRE_SLEEP)
+                           ) {
+                               lbs_pr_debug(1,
+                                      "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n",
+                                      cmdptr->command, adapter->psstate);
+                               ret = -1;
+                               goto done;
+                       }
+                       lbs_pr_debug(1, "EXEC_NEXT_CMD: OK to send command "
+                              "0x%x in psstate %d\n",
+                              cmdptr->command, adapter->psstate);
+               } else if (adapter->psstate != PS_STATE_FULL_POWER) {
+                       /*
+                        * 1. Non-PS command:
+                        * Queue it. set needtowakeup to TRUE if current state
+                        * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS.
+                        * 2. PS command but not Exit_PS:
+                        * Ignore it.
+                        * 3. PS command Exit_PS:
+                        * Set needtowakeup to TRUE if current state is SLEEP,
+                        * otherwise send this command down to firmware
+                        * immediately.
+                        */
+                       if (cmdptr->command !=
+                           cpu_to_le16(cmd_802_11_ps_mode)) {
+                               /*  Prepare to send Exit PS,
+                                *  this non PS command will be sent later */
+                               if ((adapter->psstate == PS_STATE_SLEEP)
+                                   || (adapter->psstate == PS_STATE_PRE_SLEEP)
+                                   ) {
+                                       /* w/ new scheme, it will not reach here.
+                                          since it is blocked in main_thread. */
+                                       adapter->needtowakeup = 1;
+                               } else
+                                       libertas_ps_wakeup(priv, 0);
+
+                               ret = 0;
+                               goto done;
+                       } else {
+                               /*
+                                * PS command. Ignore it if it is not Exit_PS.
+                                * otherwise send it down immediately.
+                                */
+                               struct cmd_ds_802_11_ps_mode *psm =
+                                   &cmdptr->params.psmode;
+
+                               lbs_pr_debug(1,
+                                      "EXEC_NEXT_CMD: PS cmd- action=0x%x\n",
+                                      psm->action);
+                               if (psm->action !=
+                                   cpu_to_le16(cmd_subcmd_exit_ps)) {
+                                       lbs_pr_debug(1,
+                                              "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+                                       list_del((struct list_head *)cmdnode);
+                                       libertas_cleanup_and_insert_cmd(priv, cmdnode);
+
+                                       ret = 0;
+                                       goto done;
+                               }
+
+                               if ((adapter->psstate == PS_STATE_SLEEP)
+                                   || (adapter->psstate == PS_STATE_PRE_SLEEP)
+                                   ) {
+                                       lbs_pr_debug(1,
+                                              "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
+                                       list_del((struct list_head *)cmdnode);
+                                       libertas_cleanup_and_insert_cmd(priv, cmdnode);
+                                       adapter->needtowakeup = 1;
+
+                                       ret = 0;
+                                       goto done;
+                               }
+
+                               lbs_pr_debug(1,
+                                      "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
+                       }
+               }
+               list_del((struct list_head *)cmdnode);
+               lbs_pr_debug(1, "EXEC_NEXT_CMD: Sending 0x%04X command\n",
+                      cmdptr->command);
+               DownloadcommandToStation(priv, cmdnode);
+       } else {
+               /*
+                * check if in power save mode, if yes, put the device back
+                * to PS mode
+                */
+               if ((adapter->psmode != wlan802_11powermodecam) &&
+                   (adapter->psstate == PS_STATE_FULL_POWER) &&
+                   (adapter->connect_status == libertas_connected)) {
+                       if (adapter->secinfo.WPAenabled
+                           || adapter->secinfo.WPA2enabled) {
+                               /* check for valid WPA group keys */
+                               if (adapter->wpa_mcast_key.len
+                                   || adapter->wpa_unicast_key.len) {
+                                       lbs_pr_debug(1,
+                                              "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
+                                              " go back to PS_SLEEP");
+                                       libertas_ps_sleep(priv, 0);
+                               }
+                       } else {
+                               lbs_pr_debug(1,
+                                      "EXEC_NEXT_CMD: command PendQ is empty,"
+                                      " go back to PS_SLEEP");
+                               libertas_ps_sleep(priv, 0);
+                       }
+               }
+       }
+
+       ret = 0;
+done:
+       return ret;
+}
+
+void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
+{
+       union iwreq_data iwrq;
+       u8 buf[50];
+
+       ENTER();
+
+       memset(&iwrq, 0, sizeof(union iwreq_data));
+       memset(buf, 0, sizeof(buf));
+
+       snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+       iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+       /* Send Event to upper layer */
+       lbs_pr_debug(1, "Event Indication string = %s\n",
+              (char *)buf);
+       lbs_pr_debug(1, "Event Indication String length = %d\n", iwrq.data.length);
+
+       lbs_pr_debug(1, "Sending wireless event IWEVCUSTOM for %s\n", str);
+       wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf);
+
+       LEAVE();
+       return;
+}
+
+static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
+{
+       unsigned long flags;
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       ENTER();
+
+       lbs_pr_debug(1, "SEND_SLEEPC_CMD: Before download, size of cmd = %d\n",
+              size);
+
+       lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size);
+
+       ret = libertas_sbi_host_to_card(priv, MVMS_CMD, cmdptr, size);
+       priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+
+       spin_lock_irqsave(&adapter->driver_lock, flags);
+       if (adapter->intcounter || adapter->currenttxskb)
+               lbs_pr_debug(1, "SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n",
+                      adapter->intcounter, adapter->currenttxskb);
+       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+       if (ret) {
+               lbs_pr_alert(
+                      "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
+       } else {
+               spin_lock_irqsave(&adapter->driver_lock, flags);
+               if (!adapter->intcounter) {
+                       adapter->psstate = PS_STATE_SLEEP;
+               } else {
+                       lbs_pr_debug(1, "SEND_SLEEPC_CMD: After sent,IntC=%d\n",
+                              adapter->intcounter);
+               }
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+               lbs_pr_debug(1, "SEND_SLEEPC_CMD: Sent Confirm Sleep command\n");
+               lbs_pr_debug(1, "+");
+       }
+
+       LEAVE();
+       return ret;
+}
+
+void libertas_ps_sleep(wlan_private * priv, int wait_option)
+{
+
+       ENTER();
+
+       /*
+        * PS is currently supported only in Infrastructure mode
+        * Remove this check if it is to be supported in IBSS mode also
+        */
+
+       libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+                             cmd_subcmd_enter_ps, wait_option, 0, NULL);
+
+       LEAVE();
+       return;
+}
+
+/**
+ *  @brief This function sends Eixt_PS command to firmware.
+ *
+ *  @param priv        A pointer to wlan_private structure
+ *  @param wait_option wait response or not
+ *  @return            n/a
+ */
+void libertas_ps_wakeup(wlan_private * priv, int wait_option)
+{
+       enum WLAN_802_11_POWER_MODE Localpsmode;
+
+       ENTER();
+
+       Localpsmode = wlan802_11powermodecam;
+
+       lbs_pr_debug(1, "Exit_PS: Localpsmode = %d\n", Localpsmode);
+
+       libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+                             cmd_subcmd_exit_ps,
+                             wait_option, 0, &Localpsmode);
+
+       LEAVE();
+       return;
+}
+
+/**
+ *  @brief This function checks condition and prepares to
+ *  send sleep confirm command to firmware if ok.
+ *
+ *  @param priv        A pointer to wlan_private structure
+ *  @param psmode      Power Saving mode
+ *  @return            n/a
+ */
+void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode)
+{
+       unsigned long flags =0;
+       wlan_adapter *adapter = priv->adapter;
+       u8 allowed = 1;
+
+       ENTER();
+
+       if (priv->wlan_dev.dnld_sent) {
+               allowed = 0;
+               lbs_pr_debug(1, "D");
+       }
+
+       spin_lock_irqsave(&adapter->driver_lock, flags);
+       if (adapter->cur_cmd) {
+               allowed = 0;
+               lbs_pr_debug(1, "C");
+       }
+       if (adapter->intcounter > 0) {
+               allowed = 0;
+               lbs_pr_debug(1, "I%d", adapter->intcounter);
+       }
+       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+       if (allowed) {
+               lbs_pr_debug(1, "Sending libertas_ps_confirm_sleep\n");
+               sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
+                                sizeof(struct PS_CMD_ConfirmSleep));
+       } else {
+               lbs_pr_debug(1, "Sleep Confirm has been delayed\n");
+       }
+
+       LEAVE();
+}
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
new file mode 100644 (file)
index 0000000..cdb012c
--- /dev/null
@@ -0,0 +1,1031 @@
+/**
+  * This file contains the handling of command
+  * responses as well as events generated by firmware.
+  */
+#include <linux/delay.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+/**
+ *  @brief This function handles disconnect event. it
+ *  reports disconnect to upper layer, clean tx/rx packets,
+ *  reset link state etc.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return       n/a
+ */
+void libertas_mac_event_disconnected(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       union iwreq_data wrqu;
+
+       if (adapter->connect_status != libertas_connected)
+               return;
+
+       lbs_pr_debug(1, "Handles disconnect event.\n");
+
+       memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+       /*
+        * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
+        * It causes problem in the Supplicant
+        */
+
+       msleep_interruptible(1000);
+       wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+       /* Free Tx and Rx packets */
+       kfree_skb(priv->adapter->currenttxskb);
+       priv->adapter->currenttxskb = NULL;
+
+       /* report disconnect to upper layer */
+       netif_stop_queue(priv->wlan_dev.netdev);
+       netif_carrier_off(priv->wlan_dev.netdev);
+
+       /* reset SNR/NF/RSSI values */
+       memset(adapter->SNR, 0x00, sizeof(adapter->SNR));
+       memset(adapter->NF, 0x00, sizeof(adapter->NF));
+       memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI));
+       memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
+       memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
+       adapter->nextSNRNF = 0;
+       adapter->numSNRNF = 0;
+       adapter->rxpd_rate = 0;
+       lbs_pr_debug(1, "Current SSID=%s, ssid length=%u\n",
+              adapter->curbssparams.ssid.ssid,
+              adapter->curbssparams.ssid.ssidlength);
+       lbs_pr_debug(1, "Previous SSID=%s, ssid length=%u\n",
+              adapter->previousssid.ssid, adapter->previousssid.ssidlength);
+
+       /* reset internal flags */
+       adapter->secinfo.WPAenabled = 0;
+       adapter->secinfo.WPA2enabled = 0;
+       adapter->wpa_ie_len = 0;
+       adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
+       adapter->secinfo.Encryptionmode = CIPHER_NONE;
+
+       adapter->connect_status = libertas_disconnected;
+
+       /*
+        * memorize the previous SSID and BSSID
+        * it could be used for re-assoc
+        */
+       memcpy(&adapter->previousssid,
+              &adapter->curbssparams.ssid, sizeof(struct WLAN_802_11_SSID));
+       memcpy(adapter->previousbssid,
+              adapter->curbssparams.bssid, ETH_ALEN);
+
+       /* need to erase the current SSID and BSSID info */
+       adapter->pattemptedbssdesc = NULL;
+       memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+
+       if (adapter->psstate != PS_STATE_FULL_POWER) {
+               /* make firmware to exit PS mode */
+               lbs_pr_debug(1, "Disconnected, so exit PS mode.\n");
+               libertas_ps_wakeup(priv, 0);
+       }
+}
+
+/**
+ *  @brief This function handles MIC failure event.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @para  event   the event id
+ *  @return       n/a
+ */
+static void handle_mic_failureevent(wlan_private * priv, u32 event)
+{
+       char buf[50];
+
+       memset(buf, 0, sizeof(buf));
+
+       sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
+
+       if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
+               strcat(buf, "unicast ");
+       } else {
+               strcat(buf, "multicast ");
+       }
+
+       libertas_send_iwevcustom_event(priv, buf);
+}
+
+static int wlan_ret_reg_access(wlan_private * priv,
+                              u16 type, struct cmd_ds_command *resp)
+{
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       switch (type) {
+       case cmd_ret_mac_reg_access:
+               {
+                       struct cmd_ds_mac_reg_access *reg;
+
+                       reg =
+                           (struct cmd_ds_mac_reg_access *)&resp->params.
+                           macreg;
+
+                       adapter->offsetvalue.offset = reg->offset;
+                       adapter->offsetvalue.value = reg->value;
+                       break;
+               }
+
+       case cmd_ret_bbp_reg_access:
+               {
+                       struct cmd_ds_bbp_reg_access *reg;
+                       reg =
+                           (struct cmd_ds_bbp_reg_access *)&resp->params.
+                           bbpreg;
+
+                       adapter->offsetvalue.offset = reg->offset;
+                       adapter->offsetvalue.value = reg->value;
+                       break;
+               }
+
+       case cmd_ret_rf_reg_access:
+               {
+                       struct cmd_ds_rf_reg_access *reg;
+                       reg =
+                           (struct cmd_ds_rf_reg_access *)&resp->params.
+                           rfreg;
+
+                       adapter->offsetvalue.offset = reg->offset;
+                       adapter->offsetvalue.value = reg->value;
+                       break;
+               }
+
+       default:
+               LEAVE();
+               return -1;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_ret_get_hw_spec(wlan_private * priv,
+                               struct cmd_ds_command *resp)
+{
+       u32 i;
+       struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       ENTER();
+
+       adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);
+
+       adapter->fwreleasenumber = hwspec->fwreleasenumber;
+
+       lbs_pr_debug(1, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n",
+              adapter->fwreleasenumber);
+       lbs_pr_debug(1, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
+              hwspec->permanentaddr[0], hwspec->permanentaddr[1],
+              hwspec->permanentaddr[2], hwspec->permanentaddr[3],
+              hwspec->permanentaddr[4], hwspec->permanentaddr[5]);
+       lbs_pr_debug(1, "GET_HW_SPEC: hwifversion=0x%X  version=0x%X\n",
+              hwspec->hwifversion, hwspec->version);
+
+       adapter->regioncode = le16_to_cpu(hwspec->regioncode);
+
+       for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+               /* use the region code to search for the index */
+               if (adapter->regioncode == libertas_region_code_to_index[i]) {
+                       adapter->regiontableindex = (u16) i;
+                       break;
+               }
+       }
+
+       /* if it's unidentified region code, use the default (USA) */
+       if (i >= MRVDRV_MAX_REGION_CODE) {
+               adapter->regioncode = 0x10;
+               adapter->regiontableindex = 0;
+               lbs_pr_info(
+                      "unidentified region code, use the default (USA)\n");
+       }
+
+       if (adapter->current_addr[0] == 0xff) {
+               memmove(adapter->current_addr, hwspec->permanentaddr,
+                       ETH_ALEN);
+       }
+
+       memcpy(priv->wlan_dev.netdev->dev_addr, adapter->current_addr, ETH_ALEN);
+       memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+
+       if (libertas_set_regiontable(priv, adapter->regioncode, 0)) {
+               ret = -1;
+               goto done;
+       }
+
+       if (libertas_set_universaltable(priv, 0)) {
+               ret = -1;
+               goto done;
+       }
+
+      done:
+       LEAVE();
+       return ret;
+}
+
+static int wlan_ret_802_11_sleep_params(wlan_private * priv,
+                                       struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       lbs_pr_debug(1, "error=%x offset=%x stabletime=%x calcontrol=%x\n"
+              " extsleepclk=%x\n", sp->error, sp->offset,
+              sp->stabletime, sp->calcontrol, sp->externalsleepclk);
+       adapter->sp.sp_error = le16_to_cpu(sp->error);
+       adapter->sp.sp_offset = le16_to_cpu(sp->offset);
+       adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
+       adapter->sp.sp_calcontrol = le16_to_cpu(sp->calcontrol);
+       adapter->sp.sp_extsleepclk = le16_to_cpu(sp->externalsleepclk);
+       adapter->sp.sp_reserved = le16_to_cpu(sp->reserved);
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_ret_802_11_stat(wlan_private * priv,
+                               struct cmd_ds_command *resp)
+{
+/*     currently adapter->wlan802_11Stat is unused
+
+       struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
+       wlan_adapter *adapter = priv->adapter;
+
+       // TODO Convert it to Big endian befor copy
+       memcpy(&adapter->wlan802_11Stat,
+              p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
+*/
+       return 0;
+}
+
+static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
+                                   struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
+       u16 oid = le16_to_cpu(smib->oid);
+       u16 querytype = le16_to_cpu(smib->querytype);
+
+       ENTER();
+
+       lbs_pr_debug(1, "SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
+              querytype);
+       lbs_pr_debug(1, "SNMP_RESP: Buf size  = %x\n",
+              le16_to_cpu(smib->bufsize));
+
+       if (querytype == cmd_act_get) {
+               switch (oid) {
+               case fragthresh_i:
+                       priv->adapter->fragthsd =
+                           le16_to_cpu(*
+                                            ((unsigned short *)(smib->value)));
+                       lbs_pr_debug(1, "SNMP_RESP: fragthsd =%u\n",
+                              priv->adapter->fragthsd);
+                       break;
+               case rtsthresh_i:
+                       priv->adapter->rtsthsd =
+                           le16_to_cpu(*
+                                            ((unsigned short *)(smib->value)));
+                       lbs_pr_debug(1, "SNMP_RESP: rtsthsd =%u\n",
+                              priv->adapter->rtsthsd);
+                       break;
+               case short_retrylim_i:
+                       priv->adapter->txretrycount =
+                           le16_to_cpu(*
+                                            ((unsigned short *)(smib->value)));
+                       lbs_pr_debug(1, "SNMP_RESP: txretrycount =%u\n",
+                              priv->adapter->rtsthsd);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_ret_802_11_key_material(wlan_private * priv,
+                                       struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_key_material *pkeymaterial =
+           &resp->params.keymaterial;
+       wlan_adapter *adapter = priv->adapter;
+       u16 action = le16_to_cpu(pkeymaterial->action);
+
+       ENTER();
+
+       /* Copy the returned key to driver private data */
+       if (action == cmd_act_get) {
+               u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
+               u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
+
+               while (buf_ptr < resp_end) {
+                       struct MrvlIEtype_keyParamSet * pkeyparamset =
+                           (struct MrvlIEtype_keyParamSet *) buf_ptr;
+                       struct WLAN_802_11_KEY * pkey;
+                       u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
+                       u16 param_set_len = le16_to_cpu(pkeyparamset->length);
+                       u8 * end;
+                       u16 key_len = le16_to_cpu(pkeyparamset->keylen);
+
+                       end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
+                                                 + sizeof (pkeyparamset->length)
+                                                 + param_set_len;
+                       /* Make sure we don't access past the end of the IEs */
+                       if (end > resp_end)
+                               break;
+
+                       if (key_info & KEY_INFO_WPA_UNICAST)
+                               pkey = &adapter->wpa_unicast_key;
+                       else if (key_info & KEY_INFO_WPA_MCAST)
+                               pkey = &adapter->wpa_mcast_key;
+                       else
+                               break;
+
+                       /* Copy returned key into driver */
+                       memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+                       if (key_len > sizeof(pkey->key))
+                               break;
+                       pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
+                       pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
+                       pkey->len = le16_to_cpu(pkeyparamset->keylen);
+                       memcpy(pkey->key, pkeyparamset->key, pkey->len);
+
+                       buf_ptr = end + 1;
+               }
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_ret_802_11_mac_address(wlan_private * priv,
+                                      struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN);
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
+                                      struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
+
+       lbs_pr_debug(1, "Current TxPower Level = %d\n", adapter->txpowerlevel);
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
+                                     struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
+       wlan_adapter *adapter = priv->adapter;
+       u16 action = le16_to_cpu(pAntenna->action);
+
+       if (action == cmd_act_get_rx)
+               adapter->rxantennamode =
+                   le16_to_cpu(pAntenna->antennamode);
+
+       if (action == cmd_act_get_tx)
+               adapter->txantennamode =
+                   le16_to_cpu(pAntenna->antennamode);
+
+       lbs_pr_debug(1, "RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
+              action, le16_to_cpu(pAntenna->antennamode));
+
+       return 0;
+}
+
+static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
+                                             struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_rate_adapt_rateset *rates =
+           &resp->params.rateset;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       if (rates->action == cmd_act_get) {
+               adapter->enablehwauto = rates->enablehwauto;
+               adapter->ratebitmap = rates->bitmap;
+       }
+
+       LEAVE();
+
+       return 0;
+}
+
+static int wlan_ret_802_11_data_rate(wlan_private * priv,
+                                    struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
+       wlan_adapter *adapter = priv->adapter;
+       u8 dot11datarate;
+
+       ENTER();
+
+       lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
+               (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
+
+       dot11datarate = pdatarate->datarate[0];
+       if (pdatarate->action == cmd_act_get_tx_rate) {
+               memcpy(adapter->libertas_supported_rates, pdatarate->datarate,
+                      sizeof(adapter->libertas_supported_rates));
+       }
+       adapter->datarate = libertas_index_to_data_rate(dot11datarate);
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_ret_802_11_rf_channel(wlan_private * priv,
+                                     struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_rf_channel *rfchannel =
+           &resp->params.rfchannel;
+       wlan_adapter *adapter = priv->adapter;
+       u16 action = le16_to_cpu(rfchannel->action);
+       u16 newchannel = le16_to_cpu(rfchannel->currentchannel);
+
+       ENTER();
+
+       if (action == cmd_opt_802_11_rf_channel_get
+           && adapter->curbssparams.channel != newchannel) {
+               lbs_pr_debug(1, "channel Switch: %d to %d\n",
+                      adapter->curbssparams.channel, newchannel);
+
+               /* Update the channel again */
+               adapter->curbssparams.channel = newchannel;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_ret_802_11_rssi(wlan_private * priv,
+                               struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
+       wlan_adapter *adapter = priv->adapter;
+
+       /* store the non average value */
+       adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
+       adapter->NF[TYPE_BEACON][TYPE_NOAVG] =
+           le16_to_cpu(rssirsp->noisefloor);
+
+       adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
+       adapter->NF[TYPE_BEACON][TYPE_AVG] =
+           le16_to_cpu(rssirsp->avgnoisefloor);
+
+       adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
+           CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+                    adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+       adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
+           CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
+                    adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
+
+       lbs_pr_debug(1, "Beacon RSSI value = 0x%x\n",
+              adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
+
+       return 0;
+}
+
+static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
+                                 struct cmd_ds_command *resp)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct wlan_ioctl_regrdwr *pbuf;
+       pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
+
+       lbs_pr_debug(1, "eeprom read len=%x\n",
+              le16_to_cpu(resp->params.rdeeprom.bytecount));
+       if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
+               pbuf->NOB = 0;
+               lbs_pr_debug(1, "eeprom read return length is too big\n");
+               return -1;
+       }
+       pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
+       if (pbuf->NOB > 0) {
+
+               memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
+                      le16_to_cpu(resp->params.rdeeprom.bytecount));
+               lbs_dbg_hex("adapter", (char *)&pbuf->value,
+                       le16_to_cpu(resp->params.rdeeprom.bytecount));
+       }
+       return 0;
+}
+
+static int wlan_ret_get_log(wlan_private * priv,
+                           struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_get_log *logmessage =
+           (struct cmd_ds_802_11_get_log *)&resp->params.glog;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       /* TODO Convert it to Big Endian before copy */
+       memcpy(&adapter->logmsg, logmessage,
+              sizeof(struct cmd_ds_802_11_get_log));
+
+       LEAVE();
+       return 0;
+}
+
+static inline int handle_cmd_response(u16 respcmd,
+                                     struct cmd_ds_command *resp,
+                                     wlan_private *priv)
+{
+       int ret = 0;
+       unsigned long flags;
+       wlan_adapter *adapter = priv->adapter;
+
+       switch (respcmd) {
+       case cmd_ret_mac_reg_access:
+       case cmd_ret_bbp_reg_access:
+       case cmd_ret_rf_reg_access:
+               ret = wlan_ret_reg_access(priv, respcmd, resp);
+               break;
+
+       case cmd_ret_hw_spec_info:
+               ret = wlan_ret_get_hw_spec(priv, resp);
+               break;
+
+       case cmd_ret_802_11_scan:
+               ret = libertas_ret_80211_scan(priv, resp);
+               break;
+
+       case cmd_ret_802_11_get_log:
+               ret = wlan_ret_get_log(priv, resp);
+               break;
+
+       case cmd_ret_802_11_associate:
+       case cmd_ret_802_11_reassociate:
+               ret = libertas_ret_80211_associate(priv, resp);
+               break;
+
+       case cmd_ret_802_11_disassociate:
+       case cmd_ret_802_11_deauthenticate:
+               ret = libertas_ret_80211_disassociate(priv, resp);
+               break;
+
+       case cmd_ret_802_11_ad_hoc_start:
+       case cmd_ret_802_11_ad_hoc_join:
+               ret = libertas_ret_80211_ad_hoc_start(priv, resp);
+               break;
+
+       case cmd_ret_802_11_stat:
+               ret = wlan_ret_802_11_stat(priv, resp);
+               break;
+
+       case cmd_ret_802_11_snmp_mib:
+               ret = wlan_ret_802_11_snmp_mib(priv, resp);
+               break;
+
+       case cmd_ret_802_11_rf_tx_power:
+               ret = wlan_ret_802_11_rf_tx_power(priv, resp);
+               break;
+
+       case cmd_ret_802_11_set_afc:
+       case cmd_ret_802_11_get_afc:
+               spin_lock_irqsave(&adapter->driver_lock, flags);
+               memmove(adapter->cur_cmd->pdata_buf,
+                       &resp->params.afc,
+                       sizeof(struct cmd_ds_802_11_afc));
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+               break;
+       case cmd_ret_802_11_rf_antenna:
+               ret = wlan_ret_802_11_rf_antenna(priv, resp);
+               break;
+
+       case cmd_ret_mac_multicast_adr:
+       case cmd_ret_mac_control:
+       case cmd_ret_802_11_set_wep:
+       case cmd_ret_802_11_reset:
+       case cmd_ret_802_11_authenticate:
+       case cmd_ret_802_11_radio_control:
+       case cmd_ret_802_11_beacon_stop:
+       case cmd_ret_802_11_enable_rsn:
+               break;
+
+       case cmd_ret_802_11_data_rate:
+               ret = wlan_ret_802_11_data_rate(priv, resp);
+               break;
+       case cmd_ret_802_11_rate_adapt_rateset:
+               ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
+               break;
+       case cmd_ret_802_11_rf_channel:
+               ret = wlan_ret_802_11_rf_channel(priv, resp);
+               break;
+
+       case cmd_ret_802_11_rssi:
+               ret = wlan_ret_802_11_rssi(priv, resp);
+               break;
+
+       case cmd_ret_802_11_mac_address:
+               ret = wlan_ret_802_11_mac_address(priv, resp);
+               break;
+
+       case cmd_ret_802_11_ad_hoc_stop:
+               ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
+               break;
+
+       case cmd_ret_802_11_key_material:
+               lbs_pr_debug(1, "CMD_RESP: KEY_MATERIAL command response\n");
+               ret = wlan_ret_802_11_key_material(priv, resp);
+               break;
+
+       case cmd_ret_802_11_eeprom_access:
+               ret = wlan_ret_802_11_eeprom_access(priv, resp);
+               break;
+
+       case cmd_ret_802_11d_domain_info:
+               ret = libertas_ret_802_11d_domain_info(priv, resp);
+               break;
+
+       case cmd_ret_802_11_sleep_params:
+               ret = wlan_ret_802_11_sleep_params(priv, resp);
+               break;
+       case cmd_ret_802_11_inactivity_timeout:
+               spin_lock_irqsave(&adapter->driver_lock, flags);
+               *((u16 *) adapter->cur_cmd->pdata_buf) =
+                   le16_to_cpu(resp->params.inactivity_timeout.timeout);
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               break;
+
+       case cmd_ret_802_11_tpc_cfg:
+               spin_lock_irqsave(&adapter->driver_lock, flags);
+               memmove(adapter->cur_cmd->pdata_buf,
+                       &resp->params.tpccfg,
+                       sizeof(struct cmd_ds_802_11_tpc_cfg));
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               break;
+       case cmd_ret_802_11_led_gpio_ctrl:
+               spin_lock_irqsave(&adapter->driver_lock, flags);
+               memmove(adapter->cur_cmd->pdata_buf,
+                       &resp->params.ledgpio,
+                       sizeof(struct cmd_ds_802_11_led_ctrl));
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               break;
+       case cmd_ret_802_11_pwr_cfg:
+               spin_lock_irqsave(&adapter->driver_lock, flags);
+               memmove(adapter->cur_cmd->pdata_buf,
+                       &resp->params.pwrcfg,
+                       sizeof(struct cmd_ds_802_11_pwr_cfg));
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+               break;
+
+       case cmd_ret_get_tsf:
+               spin_lock_irqsave(&adapter->driver_lock, flags);
+               memcpy(priv->adapter->cur_cmd->pdata_buf,
+                      &resp->params.gettsf.tsfvalue, sizeof(u64));
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               break;
+       case cmd_ret_bt_access:
+               spin_lock_irqsave(&adapter->driver_lock, flags);
+               if (adapter->cur_cmd->pdata_buf)
+                       memcpy(adapter->cur_cmd->pdata_buf,
+                              &resp->params.bt.addr1, 2 * ETH_ALEN);
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               break;
+       case cmd_ret_fwt_access:
+               spin_lock_irqsave(&adapter->driver_lock, flags);
+               if (adapter->cur_cmd->pdata_buf)
+                       memcpy(adapter->cur_cmd->pdata_buf,
+                              &resp->params.fwt,
+                               sizeof(resp->params.fwt));
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               break;
+       case cmd_ret_mesh_access:
+               if (adapter->cur_cmd->pdata_buf)
+                       memcpy(adapter->cur_cmd->pdata_buf,
+                              &resp->params.mesh,
+                              sizeof(resp->params.mesh));
+               break;
+       case cmd_rte_802_11_tx_rate_query:
+               priv->adapter->txrate = resp->params.txrate.txrate;
+               break;
+       default:
+               lbs_pr_debug(1, "CMD_RESP: Unknown command response %#x\n",
+                      resp->command);
+               break;
+       }
+       return ret;
+}
+
+int libertas_process_rx_command(wlan_private * priv)
+{
+       u16 respcmd;
+       struct cmd_ds_command *resp;
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       ulong flags;
+       u16 result;
+
+       ENTER();
+
+       lbs_pr_debug(1, "CMD_RESP: @ %lu\n", jiffies);
+
+       /* Now we got response from FW, cancel the command timer */
+       del_timer(&adapter->command_timer);
+
+       mutex_lock(&adapter->lock);
+       spin_lock_irqsave(&adapter->driver_lock, flags);
+
+       if (!adapter->cur_cmd) {
+               lbs_pr_debug(1, "CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
+               ret = -1;
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               goto done;
+       }
+       resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
+
+       lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
+               priv->wlan_dev.upld_len);
+
+       respcmd = le16_to_cpu(resp->command);
+
+       result = le16_to_cpu(resp->result);
+
+       lbs_pr_debug(1, "CMD_RESP: %x result: %d length: %d\n", respcmd,
+              result, priv->wlan_dev.upld_len);
+
+       if (!(respcmd & 0x8000)) {
+               lbs_pr_debug(1, "Invalid response to command!");
+               adapter->cur_cmd_retcode = -1;
+               __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+               adapter->nr_cmd_pending--;
+               adapter->cur_cmd = NULL;
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+               ret = -1;
+               goto done;
+       }
+
+       /* Store the response code to cur_cmd_retcode. */
+       adapter->cur_cmd_retcode = le16_to_cpu(resp->result);
+
+       if (respcmd == cmd_ret_802_11_ps_mode) {
+               struct cmd_ds_802_11_ps_mode *psmode;
+
+               psmode = &resp->params.psmode;
+               lbs_pr_debug(1,
+                      "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+                      resp->result, psmode->action);
+               psmode->action = cpu_to_le16(psmode->action);
+
+               if (result) {
+                       lbs_pr_debug(1, "CMD_RESP: PS command failed- %#x \n",
+                              resp->result);
+                       if (adapter->inframode == wlan802_11ibss) {
+                               /*
+                                * We should not re-try enter-ps command in
+                                * ad-hoc mode. It takes place in
+                                * libertas_execute_next_command().
+                                */
+                               if (psmode->action == cmd_subcmd_enter_ps)
+                                       adapter->psmode =
+                                           wlan802_11powermodecam;
+                       }
+               } else if (psmode->action == cmd_subcmd_enter_ps) {
+                       adapter->needtowakeup = 0;
+                       adapter->psstate = PS_STATE_AWAKE;
+
+                       lbs_pr_debug(1, "CMD_RESP: Enter_PS command response\n");
+                       if (adapter->connect_status != libertas_connected) {
+                               /*
+                                * When Deauth Event received before Enter_PS command
+                                * response, We need to wake up the firmware.
+                                */
+                               lbs_pr_debug(1,
+                                      "Disconnected, Going to invoke libertas_ps_wakeup\n");
+
+                               mutex_unlock(&adapter->lock);
+                               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+                               libertas_ps_wakeup(priv, 0);
+                               mutex_lock(&adapter->lock);
+                               spin_lock_irqsave(&adapter->driver_lock, flags);
+                       }
+               } else if (psmode->action == cmd_subcmd_exit_ps) {
+                       adapter->needtowakeup = 0;
+                       adapter->psstate = PS_STATE_FULL_POWER;
+                       lbs_pr_debug(1, "CMD_RESP: Exit_PS command response\n");
+               } else {
+                       lbs_pr_debug(1, "CMD_RESP: PS- action=0x%X\n",
+                              psmode->action);
+               }
+
+               __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+               adapter->nr_cmd_pending--;
+               adapter->cur_cmd = NULL;
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+               ret = 0;
+               goto done;
+       }
+
+       if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
+               /* Copy the response back to response buffer */
+               memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
+
+               adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
+       }
+
+       /* If the command is not successful, cleanup and return failure */
+       if ((result != 0 || !(respcmd & 0x8000))) {
+               lbs_pr_debug(1, "CMD_RESP: command reply %#x result=%#x\n",
+                      resp->command, resp->result);
+               /*
+                * Handling errors here
+                */
+               switch (respcmd) {
+               case cmd_ret_hw_spec_info:
+               case cmd_ret_802_11_reset:
+                       lbs_pr_debug(1, "CMD_RESP: Reset command failed\n");
+                       break;
+
+               }
+
+               __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+               adapter->nr_cmd_pending--;
+               adapter->cur_cmd = NULL;
+               spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+               ret = -1;
+               goto done;
+       }
+
+       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+       ret = handle_cmd_response(respcmd, resp, priv);
+
+       spin_lock_irqsave(&adapter->driver_lock, flags);
+       if (adapter->cur_cmd) {
+               /* Clean up and Put current command back to cmdfreeq */
+               __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+               adapter->nr_cmd_pending--;
+               WARN_ON(adapter->nr_cmd_pending > 128);
+               adapter->cur_cmd = NULL;
+       }
+       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+done:
+       mutex_unlock(&adapter->lock);
+       LEAVE();
+       return ret;
+}
+
+int libertas_process_event(wlan_private * priv)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+       u32 eventcause;
+
+       spin_lock_irq(&adapter->driver_lock);
+       eventcause = adapter->eventcause;
+       spin_unlock_irq(&adapter->driver_lock);
+
+       ENTER();
+
+       lbs_pr_debug(1, "EVENT Cause %x\n", eventcause);
+
+       switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
+       case MACREG_INT_CODE_LINK_SENSED:
+               lbs_pr_debug(1, "EVENT: MACREG_INT_CODE_LINK_SENSED\n");
+               break;
+
+       case MACREG_INT_CODE_DEAUTHENTICATED:
+               lbs_pr_debug(1, "EVENT: Deauthenticated\n");
+               libertas_mac_event_disconnected(priv);
+               break;
+
+       case MACREG_INT_CODE_DISASSOCIATED:
+               lbs_pr_debug(1, "EVENT: Disassociated\n");
+               libertas_mac_event_disconnected(priv);
+               break;
+
+       case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
+               lbs_pr_debug(1, "EVENT: Link lost\n");
+               libertas_mac_event_disconnected(priv);
+               break;
+
+       case MACREG_INT_CODE_PS_SLEEP:
+               lbs_pr_debug(1, "EVENT: SLEEP\n");
+               lbs_pr_debug(1, "_");
+
+               /* handle unexpected PS SLEEP event */
+               if (adapter->psstate == PS_STATE_FULL_POWER) {
+                       lbs_pr_debug(1,
+                              "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
+                       break;
+               }
+               adapter->psstate = PS_STATE_PRE_SLEEP;
+
+               libertas_ps_confirm_sleep(priv, (u16) adapter->psmode);
+
+               break;
+
+       case MACREG_INT_CODE_PS_AWAKE:
+               lbs_pr_debug(1, "EVENT: AWAKE \n");
+               lbs_pr_debug(1, "|");
+
+               /* handle unexpected PS AWAKE event */
+               if (adapter->psstate == PS_STATE_FULL_POWER) {
+                       lbs_pr_debug(1,
+                              "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
+                       break;
+               }
+
+               adapter->psstate = PS_STATE_AWAKE;
+
+               if (adapter->needtowakeup) {
+                       /*
+                        * wait for the command processing to finish
+                        * before resuming sending
+                        * adapter->needtowakeup will be set to FALSE
+                        * in libertas_ps_wakeup()
+                        */
+                       lbs_pr_debug(1, "Waking up...\n");
+                       libertas_ps_wakeup(priv, 0);
+               }
+               break;
+
+       case MACREG_INT_CODE_MIC_ERR_UNICAST:
+               lbs_pr_debug(1, "EVENT: UNICAST MIC ERROR\n");
+               handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
+               break;
+
+       case MACREG_INT_CODE_MIC_ERR_MULTICAST:
+               lbs_pr_debug(1, "EVENT: MULTICAST MIC ERROR\n");
+               handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
+               break;
+       case MACREG_INT_CODE_MIB_CHANGED:
+       case MACREG_INT_CODE_INIT_DONE:
+               break;
+
+       case MACREG_INT_CODE_ADHOC_BCN_LOST:
+               lbs_pr_debug(1, "EVENT: HWAC - ADHOC BCN LOST\n");
+               break;
+
+       case MACREG_INT_CODE_RSSI_LOW:
+               lbs_pr_alert( "EVENT: RSSI_LOW\n");
+               break;
+       case MACREG_INT_CODE_SNR_LOW:
+               lbs_pr_alert( "EVENT: SNR_LOW\n");
+               break;
+       case MACREG_INT_CODE_MAX_FAIL:
+               lbs_pr_alert( "EVENT: MAX_FAIL\n");
+               break;
+       case MACREG_INT_CODE_RSSI_HIGH:
+               lbs_pr_alert( "EVENT: RSSI_HIGH\n");
+               break;
+       case MACREG_INT_CODE_SNR_HIGH:
+               lbs_pr_alert( "EVENT: SNR_HIGH\n");
+               break;
+
+       default:
+               lbs_pr_alert( "EVENT: unknown event id: %#x\n",
+                      eventcause >> SBI_EVENT_CAUSE_SHIFT);
+               break;
+       }
+
+       spin_lock_irq(&adapter->driver_lock);
+       adapter->eventcause = 0;
+       spin_unlock_irq(&adapter->driver_lock);
+       LEAVE();
+       return ret;
+}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
new file mode 100644 (file)
index 0000000..51dfd20
--- /dev/null
@@ -0,0 +1,1935 @@
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <net/iw_handler.h>
+#include "dev.h"
+#include "decl.h"
+#include "host.h"
+
+static struct dentry *libertas_dir = NULL;
+static char *szStates[] = {
+       "Connected",
+       "Disconnected"
+};
+
+void libertas_debug_init(wlan_private * priv, struct net_device *dev);
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+        return -EINVAL;
+}
+
+static const size_t len = PAGE_SIZE;
+
+static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       size_t pos = 0;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+       ssize_t res;
+
+       pos += snprintf(buf+pos, len-pos, "state = %s\n",
+                               szStates[priv->adapter->connect_status]);
+       pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
+                               (u32) priv->adapter->regioncode);
+
+       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+       free_page(addr);
+       return res;
+}
+
+
+static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       size_t pos = 0;
+       int numscansdone = 0, res;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       pos += snprintf(buf+pos, len-pos,
+                       "---------------------------------------");
+       pos += snprintf(buf+pos, len-pos,
+                       "---------------------------------------\n");
+       pos += snprintf(buf+pos, len-pos,
+               "# | ch  | ss  |       bssid       |   cap    |    TSF   | Qual | SSID \n");
+       pos += snprintf(buf+pos, len-pos,
+               "---------------------------------------");
+       pos += snprintf(buf+pos, len-pos,
+               "---------------------------------------\n");
+
+       while (numscansdone < priv->adapter->numinscantable) {
+               struct bss_descriptor *pbssinfo;
+               u16 cap;
+
+               pbssinfo = &priv->adapter->scantable[numscansdone];
+               memcpy(&cap, &pbssinfo->cap, sizeof(cap));
+               pos += snprintf(buf+pos, len-pos,
+                       "%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |",
+                       numscansdone, pbssinfo->channel, pbssinfo->rssi,
+                       pbssinfo->macaddress[0], pbssinfo->macaddress[1],
+                       pbssinfo->macaddress[2], pbssinfo->macaddress[3],
+                       pbssinfo->macaddress[4], pbssinfo->macaddress[5]);
+               pos += snprintf(buf+pos, len-pos, " %04x-", cap);
+               pos += snprintf(buf+pos, len-pos, "%c%c%c |",
+                               pbssinfo->cap.ibss ? 'A' : 'I',
+                               pbssinfo->cap.privacy ? 'P' : ' ',
+                               pbssinfo->cap.spectrummgmt ? 'S' : ' ');
+               pos += snprintf(buf+pos, len-pos, " %08llx |", pbssinfo->networktsf);
+               pos += snprintf(buf+pos, len-pos, " %d |",
+                       SCAN_RSSI(priv->adapter->scantable[numscansdone].rssi));
+
+               pos += snprintf(buf+pos, len-pos, " %s\n", pbssinfo->ssid.ssid);
+
+               numscansdone++;
+       }
+
+       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_sleepparams_write(struct file *file,
+                               const char __user *user_buf, size_t count,
+                               loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       ssize_t buf_size, res;
+       int p1, p2, p3, p4, p5, p6;
+       struct sleep_params sp;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, user_buf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
+       if (res != 6) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       sp.sp_error = p1;
+       sp.sp_offset = p2;
+       sp.sp_stabletime = p3;
+       sp.sp_calcontrol = p4;
+       sp.sp_extsleepclk = p5;
+       sp.sp_reserved = p6;
+
+       memcpy(&priv->adapter->sp, &sp, sizeof(struct sleep_params));
+
+        res = libertas_prepare_and_send_command(priv,
+                               cmd_802_11_sleep_params,
+                               cmd_act_set,
+                               cmd_option_waitforrsp, 0, NULL);
+
+       if (!res)
+               res = count;
+       else
+               res = -EINVAL;
+
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       ssize_t res;
+       size_t pos = 0;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+        res = libertas_prepare_and_send_command(priv,
+                               cmd_802_11_sleep_params,
+                               cmd_act_get,
+                               cmd_option_waitforrsp, 0, NULL);
+       if (res) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
+                       adapter->sp.sp_offset, adapter->sp.sp_stabletime,
+                       adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
+                       adapter->sp.sp_reserved);
+
+       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       struct WLAN_802_11_SSID extscan_ssid;
+       union iwreq_data wrqu;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1);
+       extscan_ssid.ssidlength = strlen(buf)-1;
+
+       libertas_send_specific_SSID_scan(priv, &extscan_ssid, 1);
+
+       memset(&wrqu, 0, sizeof(union iwreq_data));
+       wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+out_unlock:
+       free_page(addr);
+       return count;
+}
+
+static int libertas_parse_chan(char *buf, size_t count,
+                       struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
+{
+       char *start, *end, *hold, *str;
+       int i = 0;
+
+       start = strstr(buf, "chan=");
+       if (!start)
+               return -EINVAL;
+       start += 5;
+       end = strstr(start, " ");
+       if (!end)
+               end = buf + count;
+       hold = kzalloc((end - start)+1, GFP_KERNEL);
+       if (!hold)
+               return -ENOMEM;
+       strncpy(hold, start, end - start);
+       hold[(end-start)+1] = '\0';
+       while(hold && (str = strsep(&hold, ","))) {
+               int chan;
+               char band, passive = 0;
+               sscanf(str, "%d%c%c", &chan, &band, &passive);
+               scan_cfg->chanlist[i].channumber = chan;
+               scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
+               if (band == 'b' || band == 'g')
+                       scan_cfg->chanlist[i].radiotype = 0;
+               else if (band == 'a')
+                       scan_cfg->chanlist[i].radiotype = 1;
+
+               scan_cfg->chanlist[i].scantime = dur;
+               i++;
+       }
+
+       kfree(hold);
+       return i;
+}
+
+static void libertas_parse_bssid(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+       char *hold;
+       unsigned int mac[ETH_ALEN];
+       int i;
+
+       hold = strstr(buf, "bssid=");
+       if (!hold)
+               return;
+       hold += 6;
+       sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3,
+                       mac+4, mac+5);
+       for(i=0;i<ETH_ALEN;i++)
+               scan_cfg->specificBSSID[i] = mac[i];
+}
+
+static void libertas_parse_ssid(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+       char *hold, *end;
+       ssize_t size;
+
+       hold = strstr(buf, "ssid=");
+       if (!hold)
+               return;
+       hold += 5;
+       end = strstr(hold, " ");
+       if (!end)
+               end = buf + count - 1;
+
+       size = min(IW_ESSID_MAX_SIZE, end - hold);
+       strncpy(scan_cfg->specificSSID, hold, size);
+
+       return;
+}
+
+static void libertas_parse_keep(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+       char *hold;
+       int val;
+
+       hold = strstr(buf, "keep=");
+       if (!hold)
+               return;
+       hold += 5;
+       sscanf(hold, "%d", &val);
+
+       if (val != 0)
+               val = 1;
+
+       scan_cfg->keeppreviousscan = val;
+       return;
+}
+
+static int libertas_parse_dur(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+       char *hold;
+       int val;
+
+       hold = strstr(buf, "dur=");
+       if (!hold)
+               return 0;
+       hold += 4;
+       sscanf(hold, "%d", &val);
+
+       return val;
+}
+
+static void libertas_parse_probes(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+       char *hold;
+       int val;
+
+       hold = strstr(buf, "probes=");
+       if (!hold)
+               return;
+       hold += 7;
+       sscanf(hold, "%d", &val);
+
+       scan_cfg->numprobes = val;
+
+       return;
+}
+
+static void libertas_parse_type(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+       char *hold;
+       int val;
+
+       hold = strstr(buf, "type=");
+       if (!hold)
+               return;
+       hold += 5;
+       sscanf(hold, "%d", &val);
+
+       /* type=1,2 or 3 */
+       if (val < 1 || val > 3)
+               return;
+
+       scan_cfg->bsstype = val;
+
+       return;
+}
+
+static ssize_t libertas_setuserscan(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       struct wlan_ioctl_user_scan_cfg *scan_cfg;
+       union iwreq_data wrqu;
+       int dur;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
+       if (!scan_cfg)
+               return -ENOMEM;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;
+
+       dur = libertas_parse_dur(buf, count, scan_cfg);
+       libertas_parse_chan(buf, count, scan_cfg, dur);
+       libertas_parse_bssid(buf, count, scan_cfg);
+       libertas_parse_ssid(buf, count, scan_cfg);
+       libertas_parse_keep(buf, count, scan_cfg);
+       libertas_parse_probes(buf, count, scan_cfg);
+       libertas_parse_type(buf, count, scan_cfg);
+
+       wlan_scan_networks(priv, scan_cfg);
+       wait_event_interruptible(priv->adapter->cmd_pending,
+                                !priv->adapter->nr_cmd_pending);
+
+       memset(&wrqu, 0x00, sizeof(union iwreq_data));
+       wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+out_unlock:
+       free_page(addr);
+       kfree(scan_cfg);
+       return count;
+}
+
+static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
+                       struct cmd_ctrl_node **cmdnode,
+                       struct cmd_ds_command **cmd)
+{
+       u16 wait_option = cmd_option_waitforrsp;
+
+       if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
+               lbs_pr_debug(1, "failed libertas_get_free_cmd_ctrl_node\n");
+               return -ENOMEM;
+       }
+       if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
+               lbs_pr_debug(1, "failed to allocate response buffer!\n");
+               return -ENOMEM;
+       }
+       libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
+       init_waitqueue_head(&(*cmdnode)->cmdwait_q);
+       (*cmdnode)->pdata_buf = *response_buf;
+       (*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
+       (*cmdnode)->cmdwaitqwoken = 0;
+       *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
+       (*cmd)->command = cmd_802_11_subscribe_event;
+       (*cmd)->seqnum = ++priv->adapter->seqnum;
+       (*cmd)->result = 0;
+       return 0;
+}
+
+static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       void *response_buf;
+       int res, cmd_len;
+       ssize_t pos = 0;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0) {
+               free_page(addr);
+               return res;
+       }
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_get;
+       pcmdptr->size =
+       cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+       while (cmd_len < pcmdptr->size) {
+               struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+               switch(header->type) {
+               struct mrvlietypes_rssithreshold  *Lowrssi;
+               case TLV_TYPE_RSSI_LOW:
+               Lowrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
+               pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+                               Lowrssi->rssivalue,
+                               Lowrssi->rssifreq,
+                               (event->events & 0x0001)?1:0);
+               default:
+                       cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+                       break;
+               }
+       }
+
+       kfree(response_buf);
+       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       free_page(addr);
+       return res;
+}
+
+static u16 libertas_get_events_bitmap(wlan_private *priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       void *response_buf;
+       int res;
+       u16 event_bitmap;
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0)
+               return res;
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_get;
+       pcmdptr->size =
+       cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               return 0;
+       }
+
+       event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+       event_bitmap = event->events;
+       kfree(response_buf);
+       return event_bitmap;
+}
+
+static ssize_t libertas_lowrssi_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       ssize_t res, buf_size;
+       int value, freq, subscribed, cmd_len;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       struct mrvlietypes_rssithreshold *rssi_threshold;
+       void *response_buf;
+       u16 event_bitmap;
+       u8 *ptr;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+       if (res != 3) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       event_bitmap = libertas_get_events_bitmap(priv);
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0)
+               goto out_unlock;
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_set;
+       pcmdptr->size = cpu_to_le16(S_DS_GEN +
+               sizeof(struct cmd_ds_802_11_subscribe_event) +
+               sizeof(struct mrvlietypes_rssithreshold));
+
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       ptr = (u8*) pcmdptr+cmd_len;
+       rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+       rssi_threshold->header.type = cpu_to_le16(0x0104);
+       rssi_threshold->header.len = 2;
+       rssi_threshold->rssivalue = cpu_to_le16(value);
+       rssi_threshold->rssifreq = cpu_to_le16(freq);
+       event_bitmap |= subscribed ? 0x0001 : 0x0;
+       event->events = event_bitmap;
+
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       void *response_buf;
+       int res, cmd_len;
+       ssize_t pos = 0;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0) {
+               free_page(addr);
+               return res;
+       }
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_get;
+       pcmdptr->size =
+       cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+       while (cmd_len < pcmdptr->size) {
+               struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+               switch(header->type) {
+               struct mrvlietypes_snrthreshold *LowSnr;
+               case TLV_TYPE_SNR_LOW:
+               LowSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
+               pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+                               LowSnr->snrvalue,
+                               LowSnr->snrfreq,
+                               (event->events & 0x0002)?1:0);
+               default:
+                       cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+                       break;
+               }
+       }
+
+       kfree(response_buf);
+
+       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_lowsnr_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       ssize_t res, buf_size;
+       int value, freq, subscribed, cmd_len;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       struct mrvlietypes_snrthreshold *snr_threshold;
+       void *response_buf;
+       u16 event_bitmap;
+       u8 *ptr;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+       if (res != 3) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       event_bitmap = libertas_get_events_bitmap(priv);
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0)
+               goto out_unlock;
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_set;
+       pcmdptr->size = cpu_to_le16(S_DS_GEN +
+               sizeof(struct cmd_ds_802_11_subscribe_event) +
+               sizeof(struct mrvlietypes_snrthreshold));
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       ptr = (u8*) pcmdptr+cmd_len;
+       snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+       snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
+       snr_threshold->header.len = 2;
+       snr_threshold->snrvalue = cpu_to_le16(value);
+       snr_threshold->snrfreq = cpu_to_le16(freq);
+       event_bitmap |= subscribed ? 0x0002 : 0x0;
+       event->events = event_bitmap;
+
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       res = count;
+
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       void *response_buf;
+       int res, cmd_len;
+       ssize_t pos = 0;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0) {
+               free_page(addr);
+               return res;
+       }
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_get;
+       pcmdptr->size =
+       cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+       while (cmd_len < pcmdptr->size) {
+               struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+               switch(header->type) {
+               struct mrvlietypes_failurecount *failcount;
+               case TLV_TYPE_FAILCOUNT:
+               failcount = (struct mrvlietypes_failurecount *)(response_buf + cmd_len);
+               pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+                               failcount->failvalue,
+                               failcount->Failfreq,
+                               (event->events & 0x0004)?1:0);
+               default:
+                       cmd_len += sizeof(struct mrvlietypes_failurecount);
+                       break;
+               }
+       }
+
+       kfree(response_buf);
+       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_failcount_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       ssize_t res, buf_size;
+       int value, freq, subscribed, cmd_len;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       struct mrvlietypes_failurecount *failcount;
+       void *response_buf;
+       u16 event_bitmap;
+       u8 *ptr;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+       if (res != 3) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       event_bitmap = libertas_get_events_bitmap(priv);
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0)
+               goto out_unlock;
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_set;
+       pcmdptr->size = cpu_to_le16(S_DS_GEN +
+               sizeof(struct cmd_ds_802_11_subscribe_event) +
+               sizeof(struct mrvlietypes_failurecount));
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       ptr = (u8*) pcmdptr+cmd_len;
+       failcount = (struct mrvlietypes_failurecount *)(ptr);
+       failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
+       failcount->header.len = 2;
+       failcount->failvalue = cpu_to_le16(value);
+       failcount->Failfreq = cpu_to_le16(freq);
+       event_bitmap |= subscribed ? 0x0004 : 0x0;
+       event->events = event_bitmap;
+
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = (struct cmd_ds_command *)response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       void *response_buf;
+       int res, cmd_len;
+       ssize_t pos = 0;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0) {
+               free_page(addr);
+               return res;
+       }
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_get;
+       pcmdptr->size =
+       cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               free_page(addr);
+               kfree(response_buf);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               free_page(addr);
+               kfree(response_buf);
+               return 0;
+       }
+
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+       while (cmd_len < pcmdptr->size) {
+               struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+               switch(header->type) {
+               struct mrvlietypes_beaconsmissed *bcnmiss;
+               case TLV_TYPE_BCNMISS:
+               bcnmiss = (struct mrvlietypes_beaconsmissed *)(response_buf + cmd_len);
+               pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
+                               bcnmiss->beaconmissed,
+                               (event->events & 0x0008)?1:0);
+               default:
+                       cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
+                       break;
+               }
+       }
+
+       kfree(response_buf);
+
+       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_bcnmiss_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       ssize_t res, buf_size;
+       int value, freq, subscribed, cmd_len;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       struct mrvlietypes_beaconsmissed *bcnmiss;
+       void *response_buf;
+       u16 event_bitmap;
+       u8 *ptr;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+       if (res != 3) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       event_bitmap = libertas_get_events_bitmap(priv);
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0)
+               goto out_unlock;
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_set;
+       pcmdptr->size = cpu_to_le16(S_DS_GEN +
+               sizeof(struct cmd_ds_802_11_subscribe_event) +
+               sizeof(struct mrvlietypes_beaconsmissed));
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       ptr = (u8*) pcmdptr+cmd_len;
+       bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
+       bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
+       bcnmiss->header.len = 2;
+       bcnmiss->beaconmissed = cpu_to_le16(value);
+       event_bitmap |= subscribed ? 0x0008 : 0x0;
+       event->events = event_bitmap;
+
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               free_page(addr);
+               kfree(response_buf);
+               return 0;
+       }
+
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       void *response_buf;
+       int res, cmd_len;
+       ssize_t pos = 0;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0) {
+               free_page(addr);
+               return res;
+       }
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_get;
+       pcmdptr->size =
+       cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+       while (cmd_len < pcmdptr->size) {
+               struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+               switch(header->type) {
+               struct mrvlietypes_rssithreshold  *Highrssi;
+               case TLV_TYPE_RSSI_HIGH:
+               Highrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
+               pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+                               Highrssi->rssivalue,
+                               Highrssi->rssifreq,
+                               (event->events & 0x0010)?1:0);
+               default:
+                       cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+                       break;
+               }
+       }
+
+       kfree(response_buf);
+
+       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_highrssi_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       ssize_t res, buf_size;
+       int value, freq, subscribed, cmd_len;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       struct mrvlietypes_rssithreshold *rssi_threshold;
+       void *response_buf;
+       u16 event_bitmap;
+       u8 *ptr;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+       if (res != 3) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       event_bitmap = libertas_get_events_bitmap(priv);
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0)
+               goto out_unlock;
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_set;
+       pcmdptr->size = cpu_to_le16(S_DS_GEN +
+               sizeof(struct cmd_ds_802_11_subscribe_event) +
+               sizeof(struct mrvlietypes_rssithreshold));
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       ptr = (u8*) pcmdptr+cmd_len;
+       rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+       rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
+       rssi_threshold->header.len = 2;
+       rssi_threshold->rssivalue = cpu_to_le16(value);
+       rssi_threshold->rssifreq = cpu_to_le16(freq);
+       event_bitmap |= subscribed ? 0x0010 : 0x0;
+       event->events = event_bitmap;
+
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               return 0;
+       }
+
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       void *response_buf;
+       int res, cmd_len;
+       ssize_t pos = 0;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0) {
+               free_page(addr);
+               return res;
+       }
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_get;
+       pcmdptr->size =
+       cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+       while (cmd_len < pcmdptr->size) {
+               struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+               switch(header->type) {
+               struct mrvlietypes_snrthreshold *HighSnr;
+               case TLV_TYPE_SNR_HIGH:
+               HighSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
+               pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+                               HighSnr->snrvalue,
+                               HighSnr->snrfreq,
+                               (event->events & 0x0020)?1:0);
+               default:
+                       cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+                       break;
+               }
+       }
+
+       kfree(response_buf);
+
+       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_highsnr_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       ssize_t res, buf_size;
+       int value, freq, subscribed, cmd_len;
+       struct cmd_ctrl_node *pcmdnode;
+       struct cmd_ds_command *pcmdptr;
+       struct cmd_ds_802_11_subscribe_event *event;
+       struct mrvlietypes_snrthreshold *snr_threshold;
+       void *response_buf;
+       u16 event_bitmap;
+       u8 *ptr;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+       if (res != 3) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       event_bitmap = libertas_get_events_bitmap(priv);
+
+       res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+       if (res < 0)
+               goto out_unlock;
+
+       event = &pcmdptr->params.subscribe_event;
+       event->action = cmd_act_set;
+       pcmdptr->size = cpu_to_le16(S_DS_GEN +
+               sizeof(struct cmd_ds_802_11_subscribe_event) +
+               sizeof(struct mrvlietypes_snrthreshold));
+       cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+       ptr = (u8*) pcmdptr+cmd_len;
+       snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+       snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
+       snr_threshold->header.len = 2;
+       snr_threshold->snrvalue = cpu_to_le16(value);
+       snr_threshold->snrfreq = cpu_to_le16(freq);
+       event_bitmap |= subscribed ? 0x0020 : 0x0;
+       event->events = event_bitmap;
+
+       libertas_queue_cmd(adapter, pcmdnode, 1);
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       /* Sleep until response is generated by FW */
+       wait_event_interruptible(pcmdnode->cmdwait_q,
+                               pcmdnode->cmdwaitqwoken);
+
+       pcmdptr = response_buf;
+
+       if (pcmdptr->result) {
+               lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+                       pcmdptr->result);
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+               lbs_pr_err("command response incorrect!\n");
+               kfree(response_buf);
+               free_page(addr);
+               return 0;
+       }
+
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       struct wlan_offset_value offval;
+       ssize_t pos = 0;
+       int ret;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       offval.offset = priv->mac_offset;
+       offval.value = 0;
+
+       ret = libertas_prepare_and_send_command(priv,
+                               cmd_mac_reg_access, 0,
+                               cmd_option_waitforrsp, 0, &offval);
+       mdelay(10);
+       pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
+                               priv->mac_offset, adapter->offsetvalue.value);
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       free_page(addr);
+       return ret;
+}
+
+static ssize_t libertas_rdmac_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_wrmac_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+
+       wlan_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       u32 offset, value;
+       struct wlan_offset_value offval;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%x %x", &offset, &value);
+       if (res != 2) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       offval.offset = offset;
+       offval.value = value;
+       res = libertas_prepare_and_send_command(priv,
+                               cmd_mac_reg_access, 1,
+                               cmd_option_waitforrsp, 0, &offval);
+       mdelay(10);
+
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       struct wlan_offset_value offval;
+       ssize_t pos = 0;
+       int ret;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       offval.offset = priv->bbp_offset;
+       offval.value = 0;
+
+       ret = libertas_prepare_and_send_command(priv,
+                               cmd_bbp_reg_access, 0,
+                               cmd_option_waitforrsp, 0, &offval);
+       mdelay(10);
+       pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
+                               priv->bbp_offset, adapter->offsetvalue.value);
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       free_page(addr);
+
+       return ret;
+}
+
+static ssize_t libertas_rdbbp_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_wrbbp_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+
+       wlan_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       u32 offset, value;
+       struct wlan_offset_value offval;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%x %x", &offset, &value);
+       if (res != 2) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       offval.offset = offset;
+       offval.value = value;
+       res = libertas_prepare_and_send_command(priv,
+                               cmd_bbp_reg_access, 1,
+                               cmd_option_waitforrsp, 0, &offval);
+       mdelay(10);
+
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
+                                 size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       wlan_adapter *adapter = priv->adapter;
+       struct wlan_offset_value offval;
+       ssize_t pos = 0;
+       int ret;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       offval.offset = priv->rf_offset;
+       offval.value = 0;
+
+       ret = libertas_prepare_and_send_command(priv,
+                               cmd_rf_reg_access, 0,
+                               cmd_option_waitforrsp, 0, &offval);
+       mdelay(10);
+       pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
+                               priv->rf_offset, adapter->offsetvalue.value);
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       free_page(addr);
+
+       return ret;
+}
+
+static ssize_t libertas_rdrf_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       wlan_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+static ssize_t libertas_wrrf_write(struct file *file,
+                                   const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+
+       wlan_private *priv = file->private_data;
+       ssize_t res, buf_size;
+       u32 offset, value;
+       struct wlan_offset_value offval;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       buf_size = min(count, len - 1);
+       if (copy_from_user(buf, userbuf, buf_size)) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       res = sscanf(buf, "%x %x", &offset, &value);
+       if (res != 2) {
+               res = -EFAULT;
+               goto out_unlock;
+       }
+
+       offval.offset = offset;
+       offval.value = value;
+       res = libertas_prepare_and_send_command(priv,
+                               cmd_rf_reg_access, 1,
+                               cmd_option_waitforrsp, 0, &offval);
+       mdelay(10);
+
+       res = count;
+out_unlock:
+       free_page(addr);
+       return res;
+}
+
+#define FOPS(fread, fwrite) { \
+       .owner = THIS_MODULE, \
+       .open = open_file_generic, \
+       .read = (fread), \
+       .write = (fwrite), \
+}
+
+struct libertas_debugfs_files {
+       char *name;
+       int perm;
+       struct file_operations fops;
+};
+
+struct libertas_debugfs_files debugfs_files[] = {
+       { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
+       { "getscantable", 0444, FOPS(libertas_getscantable,
+                                       write_file_dummy), },
+       { "sleepparams", 0644, FOPS(libertas_sleepparams_read,
+                               libertas_sleepparams_write), },
+       { "extscan", 0600, FOPS(NULL, libertas_extscan), },
+       { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
+};
+
+struct libertas_debugfs_files debugfs_events_files[] = {
+       {"low_rssi", 0644, FOPS(libertas_lowrssi_read,
+                               libertas_lowrssi_write), },
+       {"low_snr", 0644, FOPS(libertas_lowsnr_read,
+                               libertas_lowsnr_write), },
+       {"failure_count", 0644, FOPS(libertas_failcount_read,
+                               libertas_failcount_write), },
+       {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
+                               libertas_bcnmiss_write), },
+       {"high_rssi", 0644, FOPS(libertas_highrssi_read,
+                               libertas_highrssi_write), },
+       {"high_snr", 0644, FOPS(libertas_highsnr_read,
+                               libertas_highsnr_write), },
+};
+
+struct libertas_debugfs_files debugfs_regs_files[] = {
+       {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
+       {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
+       {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
+       {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
+       {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
+       {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
+};
+
+void libertas_debugfs_init(void)
+{
+       if (!libertas_dir)
+               libertas_dir = debugfs_create_dir("libertas_wireless", NULL);
+
+       return;
+}
+
+void libertas_debugfs_remove(void)
+{
+       if (libertas_dir)
+                debugfs_remove(libertas_dir);
+       return;
+}
+
+void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
+{
+       int i;
+       struct libertas_debugfs_files *files;
+       if (!libertas_dir)
+               goto exit;
+
+       priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
+       if (!priv->debugfs_dir)
+               goto exit;
+
+       for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
+               files = &debugfs_files[i];
+               priv->debugfs_files[i] = debugfs_create_file(files->name,
+                                                            files->perm,
+                                                            priv->debugfs_dir,
+                                                            priv,
+                                                            &files->fops);
+       }
+
+       priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
+       if (!priv->events_dir)
+               goto exit;
+
+       for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
+               files = &debugfs_events_files[i];
+               priv->debugfs_events_files[i] = debugfs_create_file(files->name,
+                                                            files->perm,
+                                                            priv->events_dir,
+                                                            priv,
+                                                            &files->fops);
+       }
+
+       priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
+       if (!priv->regs_dir)
+               goto exit;
+
+       for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
+               files = &debugfs_regs_files[i];
+               priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
+                                                            files->perm,
+                                                            priv->regs_dir,
+                                                            priv,
+                                                            &files->fops);
+       }
+
+#ifdef PROC_DEBUG
+       libertas_debug_init(priv, dev);
+#endif
+exit:
+       return;
+}
+
+void libertas_debugfs_remove_one(wlan_private *priv)
+{
+       int i;
+
+       for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
+               debugfs_remove(priv->debugfs_regs_files[i]);
+
+       debugfs_remove(priv->regs_dir);
+
+       for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+               debugfs_remove(priv->debugfs_events_files[i]);
+
+       debugfs_remove(priv->events_dir);
+#ifdef PROC_DEBUG
+       debugfs_remove(priv->debugfs_debug);
+#endif
+       for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+               debugfs_remove(priv->debugfs_files[i]);
+}
+
+/* debug entry */
+
+#define item_size(n)   (FIELD_SIZEOF(wlan_adapter, n))
+#define item_addr(n)   (offsetof(wlan_adapter, n))
+
+struct debug_data {
+       char name[32];
+       u32 size;
+       u32 addr;
+};
+
+/* To debug any member of wlan_adapter, simply add one line here.
+ */
+static struct debug_data items[] = {
+       {"intcounter", item_size(intcounter), item_addr(intcounter)},
+       {"psmode", item_size(psmode), item_addr(psmode)},
+       {"psstate", item_size(psstate), item_addr(psstate)},
+};
+
+static int num_of_items = ARRAY_SIZE(items);
+
+/**
+ *  @brief proc read function
+ *
+ *  @param page           pointer to buffer
+ *  @param s       read data starting position
+ *  @param off     offset
+ *  @param cnt     counter
+ *  @param eof     end of file flag
+ *  @param data    data to output
+ *  @return       number of output data
+ */
+static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
+                       size_t count, loff_t *ppos)
+{
+       int val = 0;
+       size_t pos = 0;
+       ssize_t res;
+       char *p;
+       int i;
+       struct debug_data *d;
+       unsigned long addr = get_zeroed_page(GFP_KERNEL);
+       char *buf = (char *)addr;
+
+       p = buf;
+
+       d = (struct debug_data *)file->private_data;
+
+       for (i = 0; i < num_of_items; i++) {
+               if (d[i].size == 1)
+                       val = *((u8 *) d[i].addr);
+               else if (d[i].size == 2)
+                       val = *((u16 *) d[i].addr);
+               else if (d[i].size == 4)
+                       val = *((u32 *) d[i].addr);
+
+               pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
+       }
+
+       res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
+
+       free_page(addr);
+       return res;
+}
+
+/**
+ *  @brief proc write function
+ *
+ *  @param f      file pointer
+ *  @param buf     pointer to data buffer
+ *  @param cnt     data number to write
+ *  @param data    data to write
+ *  @return       number of data
+ */
+static int wlan_debugfs_write(struct file *f, const char __user *buf,
+                           size_t cnt, loff_t *ppos)
+{
+       int r, i;
+       char *pdata;
+       char *p;
+       char *p0;
+       char *p1;
+       char *p2;
+       struct debug_data *d = (struct debug_data *)f->private_data;
+
+       pdata = (char *)kmalloc(cnt, GFP_KERNEL);
+       if (pdata == NULL)
+               return 0;
+
+       if (copy_from_user(pdata, buf, cnt)) {
+               lbs_pr_debug(1, "Copy from user failed\n");
+               kfree(pdata);
+               return 0;
+       }
+
+       p0 = pdata;
+       for (i = 0; i < num_of_items; i++) {
+               do {
+                       p = strstr(p0, d[i].name);
+                       if (p == NULL)
+                               break;
+                       p1 = strchr(p, '\n');
+                       if (p1 == NULL)
+                               break;
+                       p0 = p1++;
+                       p2 = strchr(p, '=');
+                       if (!p2)
+                               break;
+                       p2++;
+                       r = simple_strtoul(p2, NULL, 0);
+                       if (d[i].size == 1)
+                               *((u8 *) d[i].addr) = (u8) r;
+                       else if (d[i].size == 2)
+                               *((u16 *) d[i].addr) = (u16) r;
+                       else if (d[i].size == 4)
+                               *((u32 *) d[i].addr) = (u32) r;
+                       break;
+               } while (1);
+       }
+       kfree(pdata);
+
+       return cnt;
+}
+
+static struct file_operations libertas_debug_fops = {
+       .owner = THIS_MODULE,
+       .open = open_file_generic,
+       .write = wlan_debugfs_write,
+       .read = wlan_debugfs_read,
+};
+
+/**
+ *  @brief create debug proc file
+ *
+ *  @param priv           pointer wlan_private
+ *  @param dev     pointer net_device
+ *  @return       N/A
+ */
+void libertas_debug_init(wlan_private * priv, struct net_device *dev)
+{
+       int i;
+
+       if (!priv->debugfs_dir)
+               return;
+
+       for (i = 0; i < num_of_items; i++)
+               items[i].addr += (u32) priv->adapter;
+
+       priv->debugfs_debug = debugfs_create_file("debug", 0644,
+                                                 priv->debugfs_dir, &items[0],
+                                                 &libertas_debug_fops);
+}
+
+/**
+ *  @brief remove proc file
+ *
+ *  @param priv           pointer wlan_private
+ *  @return       N/A
+ */
+void libertas_debug_remove(wlan_private * priv)
+{
+       debugfs_remove(priv->debugfs_debug);
+}
diff --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h
new file mode 100644 (file)
index 0000000..880a11b
--- /dev/null
@@ -0,0 +1,6 @@
+void libertas_debugfs_init(void);
+void libertas_debugfs_remove(void);
+
+void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev);
+void libertas_debugfs_remove_one(wlan_private *priv);
+
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
new file mode 100644 (file)
index 0000000..606bdd0
--- /dev/null
@@ -0,0 +1,83 @@
+/**
+  *  This file contains declaration referring to
+  *  functions defined in other source files
+  */
+
+#ifndef _WLAN_DECL_H_
+#define _WLAN_DECL_H_
+
+#include "defs.h"
+
+/** Function Prototype Declaration */
+struct wlan_private;
+struct sk_buff;
+struct net_device;
+
+extern char *libertas_fw_name;
+
+void libertas_free_adapter(wlan_private * priv);
+int libertas_set_mac_packet_filter(wlan_private * priv);
+
+int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt);
+void libertas_send_tx_feedback(wlan_private * priv);
+u8 libertas_check_last_packet_indication(wlan_private * priv);
+
+int libertas_free_cmd_buffer(wlan_private * priv);
+struct cmd_ctrl_node;
+struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv);
+
+void libertas_set_cmd_ctrl_node(wlan_private * priv,
+                   struct cmd_ctrl_node *ptempnode,
+                   u32 cmd_oid, u16 wait_option, void *pdata_buf);
+
+int libertas_prepare_and_send_command(wlan_private * priv,
+                         u16 cmd_no,
+                         u16 cmd_action,
+                         u16 wait_option, u32 cmd_oid, void *pdata_buf);
+
+void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail);
+
+int libertas_allocate_cmd_buffer(wlan_private * priv);
+int libertas_execute_next_command(wlan_private * priv);
+int libertas_process_event(wlan_private * priv);
+void libertas_interrupt(struct net_device *);
+int libertas_set_radio_control(wlan_private * priv);
+u32 libertas_index_to_data_rate(u8 index);
+u8 libertas_data_rate_to_index(u32 rate);
+void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
+
+int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
+
+/** The proc fs interface */
+int libertas_process_rx_command(wlan_private * priv);
+int libertas_process_tx(wlan_private * priv, struct sk_buff *skb);
+void libertas_cleanup_and_insert_cmd(wlan_private * priv,
+                                       struct cmd_ctrl_node *ptempcmd);
+void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
+                                       struct cmd_ctrl_node *ptempcmd);
+
+int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band);
+
+int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *);
+
+void libertas_ps_sleep(wlan_private * priv, int wait_option);
+void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode);
+void libertas_ps_wakeup(wlan_private * priv, int wait_option);
+
+void libertas_tx_runqueue(wlan_private *priv);
+
+extern struct chan_freq_power *libertas_find_cfp_by_band_and_channel(
+                               wlan_adapter * adapter, u8 band, u16 channel);
+
+extern void libertas_mac_event_disconnected(wlan_private * priv);
+
+void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str);
+
+int reset_device(wlan_private *priv);
+/* main.c */
+extern struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band,
+                                                            int *cfp_no);
+wlan_private *wlan_add_card(void *card);
+int wlan_remove_card(void *card);
+
+#endif                         /* _WLAN_DECL_H_ */
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
new file mode 100644 (file)
index 0000000..fb1478c
--- /dev/null
@@ -0,0 +1,369 @@
+/**
+  * This header file contains global constant/enum definitions,
+  * global variable declaration.
+  */
+#ifndef _WLAN_DEFS_H_
+#define _WLAN_DEFS_H_
+
+#include <linux/spinlock.h>
+
+extern unsigned int libertas_debug;
+
+#define DRV_NAME               "usb8xxx"
+
+#define lbs_pr_info(format, args...) \
+       printk(KERN_INFO DRV_NAME": " format, ## args)
+#define lbs_pr_err(format, args...) \
+       printk(KERN_ERR DRV_NAME": " format, ## args)
+#define lbs_pr_alert(format, args...) \
+       printk(KERN_ALERT DRV_NAME": " format, ## args)
+
+#ifdef DEBUG
+#define lbs_pr_debug(level, format, args...) \
+       do { if (libertas_debug >= level) \
+       printk(KERN_INFO DRV_NAME": " format, ##args); } while (0)
+#define lbs_dev_dbg(level, device, format, args...) \
+        lbs_pr_debug(level, "%s: " format, \
+        (device)->bus_id , ## args)
+
+static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
+{
+       int i = 0;
+
+       if (!libertas_debug)
+               return;
+
+       printk(KERN_DEBUG "%s: ", prompt);
+       for (i = 1; i <= len; i++) {
+               printk(KERN_DEBUG "%02x ", (u8) * buf);
+               buf++;
+       }
+       printk("\n");
+}
+#else
+#define lbs_pr_debug(level, format, args...)           do {} while (0)
+#define lbs_dev_dbg(level, device, format, args...)    do {} while (0)
+#define lbs_dbg_hex(x,y,z)                             do {} while (0)
+#endif
+
+#define        ENTER()                 lbs_pr_debug(1, "Enter: %s, %s:%i\n", \
+                                       __FUNCTION__, __FILE__, __LINE__)
+#define        LEAVE()                 lbs_pr_debug(1, "Leave: %s, %s:%i\n", \
+                                       __FUNCTION__, __FILE__, __LINE__)
+
+/** Buffer Constants */
+
+/*     The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
+*      addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+*      driver has more local TxPDs. Each TxPD on the host memory is associated
+*      with a Tx control node. The driver maintains 8 RxPD descriptors for
+*      station firmware to store Rx packet information.
+*
+*      Current version of MAC has a 32x6 multicast address buffer.
+*
+*      802.11b can have up to  14 channels, the driver keeps the
+*      BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+*/
+
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
+#define MRVDRV_NUM_OF_CMD_BUFFER        10
+#define MRVDRV_SIZE_OF_CMD_BUFFER       (2 * 1024)
+#define MRVDRV_MAX_CHANNEL_SIZE                14
+#define MRVDRV_MAX_BSSID_LIST          64
+#define MRVDRV_ASSOCIATION_TIME_OUT    255
+#define MRVDRV_SNAP_HEADER_LEN          8
+
+#define        WLAN_UPLD_SIZE                  2312
+#define DEV_NAME_LEN                   32
+
+/** Misc constants */
+/* This section defines 802.11 specific contants */
+
+#define MRVDRV_MAX_BSS_DESCRIPTS               16
+#define MRVDRV_MAX_REGION_CODE                 6
+
+#define MRVDRV_IGNORE_MULTIPLE_DTIM            0xfffe
+#define MRVDRV_MIN_MULTIPLE_DTIM               1
+#define MRVDRV_MAX_MULTIPLE_DTIM               5
+#define MRVDRV_DEFAULT_MULTIPLE_DTIM           1
+
+#define MRVDRV_DEFAULT_LISTEN_INTERVAL         10
+
+#define        MRVDRV_CHANNELS_PER_SCAN                4
+#define        MRVDRV_MAX_CHANNELS_PER_SCAN            14
+
+#define MRVDRV_DEBUG_RX_PATH           0x00000001
+#define MRVDRV_DEBUG_TX_PATH           0x00000002
+
+#define MRVDRV_MIN_BEACON_INTERVAL             20
+#define MRVDRV_MAX_BEACON_INTERVAL             1000
+#define MRVDRV_BEACON_INTERVAL                 100
+
+/** TxPD status */
+
+/*     Station firmware use TxPD status field to report final Tx transmit
+*      result, Bit masks are used to present combined situations.
+*/
+
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/** Tx mesh flag */
+/* Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define TxPD_CONTROL_WDS_FRAME (1<<17)
+#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
+
+/** RxPD status */
+
+#define MRVDRV_RXPD_STATUS_OK                0x0001
+
+/** RxPD status - Received packet types */
+/** Rx mesh flag */
+/* Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define RxPD_CONTROL_WDS_FRAME (0x40)
+#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
+
+/** RSSI-related defines */
+/*     RSSI constants are used to implement 802.11 RSSI threshold
+*      indication. if the Rx packet signal got too weak for 5 consecutive
+*      times, miniport driver (driver) will report this event to wrapper
+*/
+
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE           (-96)
+
+/** RTS/FRAG related defines */
+#define MRVDRV_RTS_MIN_VALUE           0
+#define MRVDRV_RTS_MAX_VALUE           2347
+#define MRVDRV_FRAG_MIN_VALUE          256
+#define MRVDRV_FRAG_MAX_VALUE          2346
+
+/* This is for firmware specific length */
+#define EXTRA_LEN      36
+
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+       (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
+
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+       (ETH_FRAME_LEN + sizeof(struct rxpd) \
+        + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+#define        CMD_F_HOSTCMD           (1 << 0)
+#define FW_CAPINFO_WPA         (1 << 0)
+
+/** WPA key LENGTH*/
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH     32
+
+#define KEY_LEN_WPA_AES                        16
+#define KEY_LEN_WPA_TKIP               32
+#define KEY_LEN_WEP_104                        13
+#define KEY_LEN_WEP_40                 5
+
+#define RF_ANTENNA_1           0x1
+#define RF_ANTENNA_2           0x2
+#define RF_ANTENNA_AUTO                0xFFFF
+
+#define        BAND_B                  (0x01)
+#define        BAND_G                  (0x02)
+#define ALL_802_11_BANDS       (BAND_B | BAND_G)
+
+/** MACRO DEFINITIONS */
+#define CAL_NF(NF)                     ((s32)(-(s32)(NF)))
+#define CAL_RSSI(SNR, NF)              ((s32)((s32)(SNR) + CAL_NF(NF)))
+#define SCAN_RSSI(RSSI)                        (0x100 - ((u8)(RSSI)))
+
+#define DEFAULT_BCN_AVG_FACTOR         8
+#define DEFAULT_DATA_AVG_FACTOR                8
+#define AVG_SCALE                      100
+#define CAL_AVG_SNR_NF(AVG, SNRNF, N)         \
+                        (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
+                        ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
+                        AVG_SCALE))  / N))
+
+#define B_SUPPORTED_RATES              8
+#define G_SUPPORTED_RATES              14
+
+#define        WLAN_SUPPORTED_RATES            14
+
+#define        MAX_LEDS                        8
+
+#define IS_MESH_FRAME(x) (x->cb[6])
+#define SET_MESH_FRAME(x) (x->cb[6]=1)
+#define UNSET_MESH_FRAME(x) (x->cb[6]=0)
+
+/** Global Variable Declaration */
+typedef struct _wlan_private wlan_private;
+typedef struct _wlan_adapter wlan_adapter;
+extern const char libertas_driver_version[];
+extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
+
+extern u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES];
+
+extern u8 libertas_supported_rates[G_SUPPORTED_RATES];
+
+extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES];
+
+extern u8 libertas_adhoc_rates_b[4];
+
+/** ENUM definition*/
+/** SNRNF_TYPE */
+enum SNRNF_TYPE {
+       TYPE_BEACON = 0,
+       TYPE_RXPD,
+       MAX_TYPE_B
+};
+
+/** SNRNF_DATA*/
+enum SNRNF_DATA {
+       TYPE_NOAVG = 0,
+       TYPE_AVG,
+       MAX_TYPE_AVG
+};
+
+/** WLAN_802_11_AUTH_ALG*/
+enum WLAN_802_11_AUTH_ALG {
+       AUTH_ALG_OPEN_SYSTEM = 1,
+       AUTH_ALG_SHARED_KEY = 2,
+       AUTH_ALG_NETWORK_EAP = 8,
+};
+
+/** WLAN_802_1X_AUTH_ALG */
+enum WLAN_802_1X_AUTH_ALG {
+       WLAN_1X_AUTH_ALG_NONE = 1,
+       WLAN_1X_AUTH_ALG_LEAP = 2,
+       WLAN_1X_AUTH_ALG_TLS = 4,
+       WLAN_1X_AUTH_ALG_TTLS = 8,
+       WLAN_1X_AUTH_ALG_MD5 = 16,
+};
+
+/** WLAN_802_11_ENCRYPTION_MODE */
+enum WLAN_802_11_ENCRYPTION_MODE {
+       CIPHER_NONE,
+       CIPHER_WEP40,
+       CIPHER_TKIP,
+       CIPHER_CCMP,
+       CIPHER_WEP104,
+};
+
+/** WLAN_802_11_POWER_MODE */
+enum WLAN_802_11_POWER_MODE {
+       wlan802_11powermodecam,
+       wlan802_11powermodemax_psp,
+       wlan802_11Powermodefast_psp,
+       /*not a real mode, defined as an upper bound */
+       wlan802_11powemodemax
+};
+
+/** PS_STATE */
+enum PS_STATE {
+       PS_STATE_FULL_POWER,
+       PS_STATE_AWAKE,
+       PS_STATE_PRE_SLEEP,
+       PS_STATE_SLEEP
+};
+
+/** DNLD_STATE */
+enum DNLD_STATE {
+       DNLD_RES_RECEIVED,
+       DNLD_DATA_SENT,
+       DNLD_CMD_SENT
+};
+
+/** WLAN_MEDIA_STATE */
+enum WLAN_MEDIA_STATE {
+       libertas_connected,
+       libertas_disconnected
+};
+
+/** WLAN_802_11_PRIVACY_FILTER */
+enum WLAN_802_11_PRIVACY_FILTER {
+       wlan802_11privfilteracceptall,
+       wlan802_11privfilter8021xWEP
+};
+
+/** mv_ms_type */
+enum mv_ms_type {
+       MVMS_DAT = 0,
+       MVMS_CMD = 1,
+       MVMS_TXDONE = 2,
+       MVMS_EVENT
+};
+
+/** WLAN_802_11_NETWORK_INFRASTRUCTURE */
+enum WLAN_802_11_NETWORK_INFRASTRUCTURE {
+       wlan802_11ibss,
+       wlan802_11infrastructure,
+       wlan802_11autounknown,
+       /*defined as upper bound */
+       wlan802_11infrastructuremax
+};
+
+/** WLAN_802_11_AUTHENTICATION_MODE */
+enum WLAN_802_11_AUTHENTICATION_MODE {
+       wlan802_11authmodeopen = 0x00,
+       wlan802_11authmodeshared = 0x01,
+       wlan802_11authmodenetworkEAP = 0x80,
+};
+
+/** WLAN_802_11_WEP_STATUS */
+enum WLAN_802_11_WEP_STATUS {
+       wlan802_11WEPenabled,
+       wlan802_11WEPdisabled,
+};
+
+/** SNMP_MIB_INDEX_e */
+enum SNMP_MIB_INDEX_e {
+       desired_bsstype_i = 0,
+       op_rateset_i,
+       bcnperiod_i,
+       dtimperiod_i,
+       assocrsp_timeout_i,
+       rtsthresh_i,
+       short_retrylim_i,
+       long_retrylim_i,
+       fragthresh_i,
+       dot11d_i,
+       dot11h_i,
+       manufid_i,
+       prodID_i,
+       manuf_oui_i,
+       manuf_name_i,
+       manuf_prodname_i,
+       manuf_prodver_i,
+};
+
+/** KEY_TYPE_ID */
+enum KEY_TYPE_ID {
+       KEY_TYPE_ID_WEP = 0,
+       KEY_TYPE_ID_TKIP,
+       KEY_TYPE_ID_AES
+};
+
+/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
+enum KEY_INFO_WPA {
+       KEY_INFO_WPA_MCAST = 0x01,
+       KEY_INFO_WPA_UNICAST = 0x02,
+       KEY_INFO_WPA_ENABLED = 0x04
+};
+
+/** SNMP_MIB_VALUE_e */
+enum SNMP_MIB_VALUE_e {
+       SNMP_MIB_VALUE_INFRA = 1,
+       SNMP_MIB_VALUE_ADHOC
+};
+
+/* Default values for fwt commands. */
+#define FWT_DEFAULT_METRIC 0
+#define FWT_DEFAULT_DIR 1
+#define FWT_DEFAULT_SSN 0xffffffff
+#define FWT_DEFAULT_DSN 0
+#define FWT_DEFAULT_HOPCOUNT 0
+#define FWT_DEFAULT_TTL 0
+#define FWT_DEFAULT_EXPIRATION 0
+#define FWT_DEFAULT_SLEEPMODE 0
+#define FWT_DEFAULT_SNR 0
+
+#endif                         /* _WLAN_DEFS_H_ */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
new file mode 100644 (file)
index 0000000..b1f876f
--- /dev/null
@@ -0,0 +1,403 @@
+/**
+  * This file contains definitions and data structures specific
+  * to Marvell 802.11 NIC. It contains the Device Information
+  * structure wlan_adapter.
+  */
+#ifndef _WLAN_DEV_H_
+#define _WLAN_DEV_H_
+
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/ethtool.h>
+#include <linux/debugfs.h>
+
+#include "defs.h"
+#include "scan.h"
+#include "thread.h"
+
+extern struct ethtool_ops libertas_ethtool_ops;
+
+#define        MAX_BSSID_PER_CHANNEL           16
+
+#define NR_TX_QUEUE                    3
+
+/* For the extended Scan */
+#define MAX_EXTENDED_SCAN_BSSID_LIST    MAX_BSSID_PER_CHANNEL * \
+                                               MRVDRV_MAX_CHANNEL_SIZE + 1
+
+#define        MAX_REGION_CHANNEL_NUM  2
+
+/** Chan-freq-TxPower mapping table*/
+struct chan_freq_power {
+       /** channel Number              */
+       u16 channel;
+       /** frequency of this channel   */
+       u32 freq;
+       /** Max allowed Tx power level  */
+       u16 maxtxpower;
+       /** TRUE:channel unsupported;  FLASE:supported*/
+       u8 unsupported;
+};
+
+/** region-band mapping table*/
+struct region_channel {
+       /** TRUE if this entry is valid              */
+       u8 valid;
+       /** region code for US, Japan ...            */
+       u8 region;
+       /** band B/G/A, used for BAND_CONFIG cmd             */
+       u8 band;
+       /** Actual No. of elements in the array below */
+       u8 nrcfp;
+       /** chan-freq-txpower mapping table*/
+       struct chan_freq_power *CFP;
+};
+
+struct wlan_802_11_security {
+       u8 WPAenabled;
+       u8 WPA2enabled;
+       enum WLAN_802_11_WEP_STATUS WEPstatus;
+       enum WLAN_802_11_AUTHENTICATION_MODE authmode;
+       enum WLAN_802_1X_AUTH_ALG auth1xalg;
+       enum WLAN_802_11_ENCRYPTION_MODE Encryptionmode;
+};
+
+/** Current Basic Service Set State Structure */
+struct current_bss_params {
+       struct bss_descriptor bssdescriptor;
+       /** bssid */
+       u8 bssid[ETH_ALEN];
+       /** ssid */
+       struct WLAN_802_11_SSID ssid;
+
+       /** band */
+       u8 band;
+       /** channel */
+       u8 channel;
+       /** number of rates supported */
+       int numofrates;
+       /** supported rates*/
+       u8 datarates[WLAN_SUPPORTED_RATES];
+};
+
+/** sleep_params */
+struct sleep_params {
+       u16 sp_error;
+       u16 sp_offset;
+       u16 sp_stabletime;
+       u8 sp_calcontrol;
+       u8 sp_extsleepclk;
+       u16 sp_reserved;
+};
+
+/** Data structure for the Marvell WLAN device */
+typedef struct _wlan_dev {
+       /** device name */
+       char name[DEV_NAME_LEN];
+       /** card pointer */
+       void *card;
+       /** IO port */
+       u32 ioport;
+       /** Upload received */
+       u32 upld_rcv;
+       /** Upload type */
+       u32 upld_typ;
+       /** Upload length */
+       u32 upld_len;
+       /** netdev pointer */
+       struct net_device *netdev;
+       /* Upload buffer */
+       u8 upld_buf[WLAN_UPLD_SIZE];
+       /* Download sent:
+          bit0 1/0=data_sent/data_tx_done,
+          bit1 1/0=cmd_sent/cmd_tx_done,
+          all other bits reserved 0 */
+       u8 dnld_sent;
+} wlan_dev_t, *pwlan_dev_t;
+
+/* Mesh statistics */
+struct wlan_mesh_stats {
+       u32     fwd_bcast_cnt;          /* Fwd: Broadcast counter */
+       u32     fwd_unicast_cnt;        /* Fwd: Unicast counter */
+       u32     fwd_drop_ttl;           /* Fwd: TTL zero */
+       u32     fwd_drop_rbt;           /* Fwd: Recently Broadcasted */
+       u32     fwd_drop_noroute;       /* Fwd: No route to Destination */
+       u32     fwd_drop_nobuf;         /* Fwd: Run out of internal buffers */
+       u32     drop_blind;             /* Rx:  Dropped by blinding table */
+};
+
+/** Private structure for the MV device */
+struct _wlan_private {
+       int open;
+       int mesh_open;
+       int infra_open;
+
+       wlan_adapter *adapter;
+       wlan_dev_t wlan_dev;
+
+       struct net_device_stats stats;
+       struct net_device *mesh_dev ; /* Virtual device */
+
+       struct iw_statistics wstats;
+       struct wlan_mesh_stats mstats;
+       struct dentry *debugfs_dir;
+       struct dentry *debugfs_debug;
+       struct dentry *debugfs_files[6];
+
+       struct dentry *events_dir;
+       struct dentry *debugfs_events_files[6];
+
+       struct dentry *regs_dir;
+       struct dentry *debugfs_regs_files[6];
+
+       u32 mac_offset;
+       u32 bbp_offset;
+       u32 rf_offset;
+
+       const struct firmware *firmware;
+       struct device *hotplug_device;
+
+       /** thread to service interrupts */
+       struct wlan_thread mainthread;
+
+       struct delayed_work assoc_work;
+       struct workqueue_struct *assoc_thread;
+};
+
+/** Association request
+ *
+ * Encapsulates all the options that describe a specific assocation request
+ * or configuration of the wireless card's radio, mode, and security settings.
+ */
+struct assoc_request {
+#define ASSOC_FLAG_SSID                        1
+#define ASSOC_FLAG_CHANNEL             2
+#define ASSOC_FLAG_MODE                        3
+#define ASSOC_FLAG_BSSID               4
+#define ASSOC_FLAG_WEP_KEYS            5
+#define ASSOC_FLAG_WEP_TX_KEYIDX       6
+#define ASSOC_FLAG_WPA_MCAST_KEY       7
+#define ASSOC_FLAG_WPA_UCAST_KEY       8
+#define ASSOC_FLAG_SECINFO             9
+#define ASSOC_FLAG_WPA_IE              10
+       unsigned long flags;
+
+       struct WLAN_802_11_SSID ssid;
+       u8 channel;
+       enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode;
+       u8 bssid[ETH_ALEN];
+
+       /** WEP keys */
+       struct WLAN_802_11_KEY wep_keys[4];
+       u16 wep_tx_keyidx;
+
+       /** WPA keys */
+       struct WLAN_802_11_KEY wpa_mcast_key;
+       struct WLAN_802_11_KEY wpa_unicast_key;
+
+       struct wlan_802_11_security secinfo;
+
+       /** WPA Information Elements*/
+#define MAX_WPA_IE_LEN 64
+       u8 wpa_ie[MAX_WPA_IE_LEN];
+       u8 wpa_ie_len;
+};
+
+/** Wlan adapter data structure*/
+struct _wlan_adapter {
+       /** STATUS variables */
+       u32 fwreleasenumber;
+       u32 fwcapinfo;
+       /* protected with big lock */
+
+       struct mutex lock;
+
+       u8 tmptxbuf[WLAN_UPLD_SIZE];
+       /* protected by hard_start_xmit serialization */
+
+       /** command-related variables */
+       u16 seqnum;
+       /* protected by big lock */
+
+       struct cmd_ctrl_node *cmd_array;
+       /** Current command */
+       struct cmd_ctrl_node *cur_cmd;
+       int cur_cmd_retcode;
+       /** command Queues */
+       /** Free command buffers */
+       struct list_head cmdfreeq;
+       /** Pending command buffers */
+       struct list_head cmdpendingq;
+
+       wait_queue_head_t cmd_pending;
+       u8 nr_cmd_pending;
+       /* command related variables protected by adapter->driver_lock */
+
+       /** Async and Sync Event variables */
+       u32 intcounter;
+       u32 eventcause;
+       u8 nodename[16];        /* nickname */
+
+       /** spin locks */
+       spinlock_t driver_lock;
+
+       /** Timers */
+       struct timer_list command_timer;
+
+       /* TX queue used in PS mode */
+       spinlock_t txqueue_lock;
+       struct sk_buff *tx_queue_ps[NR_TX_QUEUE];
+       unsigned int tx_queue_idx;
+
+       u8 hisregcpy;
+
+       /** current ssid/bssid related parameters*/
+       struct current_bss_params curbssparams;
+
+       enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
+
+       struct bss_descriptor *pattemptedbssdesc;
+
+       struct WLAN_802_11_SSID previousssid;
+       u8 previousbssid[ETH_ALEN];
+
+       struct bss_descriptor *scantable;
+       u32 numinscantable;
+
+       u8 scantype;
+       u32 scanmode;
+
+       u16 beaconperiod;
+       u8 adhoccreate;
+
+       /** capability Info used in Association, start, join */
+       struct ieeetypes_capinfo capinfo;
+
+       /** MAC address information */
+       u8 current_addr[ETH_ALEN];
+       u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+       u32 nr_of_multicastmacaddr;
+
+       /** 802.11 statistics */
+//     struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
+
+       u16 enablehwauto;
+       u16 ratebitmap;
+       /** control G rates */
+       u8 adhoc_grate_enabled;
+
+       u32 txantenna;
+       u32 rxantenna;
+
+       u8 adhocchannel;
+       u32 fragthsd;
+       u32 rtsthsd;
+
+       u32 datarate;
+       u8 is_datarate_auto;
+
+       u16 listeninterval;
+       u16 prescan;
+       u8 txretrycount;
+
+       /** Tx-related variables (for single packet tx) */
+       struct sk_buff *currenttxskb;
+       u16 TxLockFlag;
+
+       /** NIC Operation characteristics */
+       u16 currentpacketfilter;
+       u32 connect_status;
+       u16 regioncode;
+       u16 regiontableindex;
+       u16 txpowerlevel;
+
+       /** POWER MANAGEMENT AND PnP SUPPORT */
+       u8 surpriseremoved;
+       u16 atimwindow;
+
+       u16 psmode;             /* Wlan802_11PowermodeCAM=disable
+                                  Wlan802_11PowermodeMAX_PSP=enable */
+       u16 multipledtim;
+       u32 psstate;
+       u8 needtowakeup;
+
+       struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep;
+       u16 locallisteninterval;
+       u16 nullpktinterval;
+
+       struct assoc_request * assoc_req;
+
+       /** Encryption parameter */
+       struct wlan_802_11_security secinfo;
+
+       /** WEP keys */
+       struct WLAN_802_11_KEY wep_keys[4];
+       u16 wep_tx_keyidx;
+
+       /** WPA keys */
+       struct WLAN_802_11_KEY wpa_mcast_key;
+       struct WLAN_802_11_KEY wpa_unicast_key;
+
+       /** WPA Information Elements*/
+#define MAX_WPA_IE_LEN 64
+       u8 wpa_ie[MAX_WPA_IE_LEN];
+       u8 wpa_ie_len;
+
+       u16 rxantennamode;
+       u16 txantennamode;
+
+       /** Requested Signal Strength*/
+       u16 bcn_avg_factor;
+       u16 data_avg_factor;
+       u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
+       u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
+       u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
+       u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
+       u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
+       u16 nextSNRNF;
+       u16 numSNRNF;
+       u16 rxpd_rate;
+
+       u8 radioon;
+       u32 preamble;
+
+       /** Multi bands Parameter*/
+       u8 libertas_supported_rates[G_SUPPORTED_RATES];
+
+       /** Blue Tooth Co-existence Arbitration */
+
+       /** sleep_params */
+       struct sleep_params sp;
+
+       /** RF calibration data */
+
+#define        MAX_REGION_CHANNEL_NUM  2
+       /** region channel data */
+       struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
+
+       struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
+
+       /** 11D and Domain Regulatory Data */
+       struct wlan_802_11d_domain_reg domainreg;
+       struct parsed_region_chan_11d parsed_region_chan;
+
+       /** FSM variable for 11d support */
+       u32 enable11d;
+
+       /**     MISCELLANEOUS */
+       u8 *prdeeprom;
+       struct wlan_offset_value offsetvalue;
+
+       struct cmd_ds_802_11_get_log logmsg;
+       u16 scanprobes;
+
+       u32 pkttxctrl;
+
+       u16 txrate;
+       u32 linkmode;
+       u32 radiomode;
+       u32 debugmode;
+       u8 fw_ready;
+};
+
+#endif                         /* _WLAN_DEV_H_ */
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
new file mode 100644 (file)
index 0000000..0064de5
--- /dev/null
@@ -0,0 +1,184 @@
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+static const char * mesh_stat_strings[]= {
+                       "drop_duplicate_bcast",
+                       "drop_ttl_zero",
+                       "drop_no_fwd_route",
+                       "drop_no_buffers",
+                       "fwded_unicast_cnt",
+                       "fwded_bcast_cnt",
+                       "drop_blind_table"
+};
+
+static void libertas_ethtool_get_drvinfo(struct net_device *dev,
+                                        struct ethtool_drvinfo *info)
+{
+       wlan_private *priv = (wlan_private *) dev->priv;
+       char fwver[32];
+
+       libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1);
+
+       strcpy(info->driver, "libertas");
+       strcpy(info->version, libertas_driver_version);
+       strcpy(info->fw_version, fwver);
+}
+
+/* All 8388 parts have 16KiB EEPROM size at the time of writing.
+ * In case that changes this needs fixing.
+ */
+#define LIBERTAS_EEPROM_LEN 16384
+
+static int libertas_ethtool_get_eeprom_len(struct net_device *dev)
+{
+       return LIBERTAS_EEPROM_LEN;
+}
+
+static int libertas_ethtool_get_eeprom(struct net_device *dev,
+                                  struct ethtool_eeprom *eeprom, u8 * bytes)
+{
+       wlan_private *priv = (wlan_private *) dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct wlan_ioctl_regrdwr regctrl;
+       char *ptr;
+       int ret;
+
+       regctrl.action = 0;
+       regctrl.offset = eeprom->offset;
+       regctrl.NOB = eeprom->len;
+
+       if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN)
+               return -EINVAL;
+
+//      mutex_lock(&priv->mutex);
+
+       adapter->prdeeprom =
+                   (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
+       if (!adapter->prdeeprom)
+               return -ENOMEM;
+       memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
+
+       /* +14 is for action, offset, and NOB in
+        * response */
+       lbs_pr_debug(1, "action:%d offset: %x NOB: %02x\n",
+              regctrl.action, regctrl.offset, regctrl.NOB);
+
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_eeprom_access,
+                                   regctrl.action,
+                                   cmd_option_waitforrsp, 0,
+                                   &regctrl);
+
+       if (ret) {
+               if (adapter->prdeeprom)
+                       kfree(adapter->prdeeprom);
+               LEAVE();
+                       return ret;
+       }
+
+       mdelay(10);
+
+       ptr = (char *)adapter->prdeeprom;
+
+       /* skip the command header, but include the "value" u32 variable */
+       ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4;
+
+       /*
+        * Return the result back to the user
+        */
+       memcpy(bytes, ptr, eeprom->len);
+
+       if (adapter->prdeeprom)
+               kfree(adapter->prdeeprom);
+//     mutex_unlock(&priv->mutex);
+
+        return 0;
+}
+
+static void libertas_ethtool_get_stats(struct net_device * dev,
+                               struct ethtool_stats * stats, u64 * data)
+{
+       wlan_private *priv = dev->priv;
+
+       ENTER();
+
+       stats->cmd = ETHTOOL_GSTATS;
+       BUG_ON(stats->n_stats != MESH_STATS_NUM);
+
+        data[0] = priv->mstats.fwd_drop_rbt;
+        data[1] = priv->mstats.fwd_drop_ttl;
+        data[2] = priv->mstats.fwd_drop_noroute;
+        data[3] = priv->mstats.fwd_drop_nobuf;
+        data[4] = priv->mstats.fwd_unicast_cnt;
+        data[5] = priv->mstats.fwd_bcast_cnt;
+        data[6] = priv->mstats.drop_blind;
+
+       LEAVE();
+}
+
+static int libertas_ethtool_get_stats_count(struct net_device * dev)
+{
+       int ret;
+       wlan_private *priv = dev->priv;
+       struct cmd_ds_mesh_access mesh_access;
+
+       ENTER();
+       /* Get Mesh Statistics */
+       ret = libertas_prepare_and_send_command(priv,
+                       cmd_mesh_access, cmd_act_mesh_get_stats,
+                       cmd_option_waitforrsp, 0, &mesh_access);
+
+       if (ret) {
+               LEAVE();
+               return 0;
+       }
+
+        priv->mstats.fwd_drop_rbt = mesh_access.data[0];
+        priv->mstats.fwd_drop_ttl = mesh_access.data[1];
+        priv->mstats.fwd_drop_noroute = mesh_access.data[2];
+        priv->mstats.fwd_drop_nobuf = mesh_access.data[3];
+        priv->mstats.fwd_unicast_cnt = mesh_access.data[4];
+        priv->mstats.fwd_bcast_cnt = mesh_access.data[5];
+        priv->mstats.drop_blind = mesh_access.data[6];
+
+       LEAVE();
+       return MESH_STATS_NUM;
+}
+
+static void libertas_ethtool_get_strings (struct net_device * dev,
+                                         u32 stringset,
+                                         u8 * s)
+{
+       int i;
+
+       ENTER();
+       switch (stringset) {
+        case ETH_SS_STATS:
+               for (i=0; i < MESH_STATS_NUM; i++) {
+                       memcpy(s + i * ETH_GSTRING_LEN,
+                                       mesh_stat_strings[i],
+                                       ETH_GSTRING_LEN);
+               }
+               break;
+        }
+       LEAVE();
+}
+
+struct ethtool_ops libertas_ethtool_ops = {
+       .get_drvinfo = libertas_ethtool_get_drvinfo,
+       .get_eeprom =  libertas_ethtool_get_eeprom,
+       .get_eeprom_len = libertas_ethtool_get_eeprom_len,
+       .get_stats_count = libertas_ethtool_get_stats_count,
+       .get_ethtool_stats = libertas_ethtool_get_stats,
+       .get_strings = libertas_ethtool_get_strings,
+};
+
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c
new file mode 100644 (file)
index 0000000..b194a45
--- /dev/null
@@ -0,0 +1,361 @@
+/**
+  * This file contains the initialization for FW and HW
+  */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/version.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "defs.h"
+#include "decl.h"
+#include "dev.h"
+#include "fw.h"
+#include "wext.h"
+#include "if_usb.h"
+
+char *libertas_fw_name = NULL;
+module_param_named(fw_name, libertas_fw_name, charp, 0644);
+
+unsigned int libertas_debug = 0;
+module_param(libertas_debug, int, 0);
+
+/**
+ *  @brief This function checks the validity of Boot2/FW image.
+ *
+ *  @param data              pointer to image
+ *         len               image length
+ *  @return     0 or -1
+ */
+static int check_fwfile_format(u8 *data, u32 totlen)
+{
+       u8  bincmd, exit;
+       u32 blksize, offset, len;
+       int ret;
+
+       ret = 1;
+       exit = len = 0;
+
+       do {
+               bincmd = *data;
+               blksize = *(u32*)(data + offsetof(struct fwheader, datalength));
+               switch (bincmd) {
+               case FW_HAS_DATA_TO_RECV:
+                       offset = sizeof(struct fwheader) + blksize;
+                       data += offset;
+                       len += offset;
+                       if (len >= totlen)
+                               exit = 1;
+                       break;
+               case FW_HAS_LAST_BLOCK:
+                       exit = 1;
+                       ret = 0;
+                       break;
+               default:
+                       exit = 1;
+                       break;
+               }
+       } while (!exit);
+
+       if (ret)
+               lbs_pr_err("bin file format check FAIL...\n");
+       else
+               lbs_pr_debug(1, "bin file format check PASS...\n");
+
+       return ret;
+}
+
+/**
+ *  @brief This function downloads firmware image, gets
+ *  HW spec from firmware and set basic parameters to
+ *  firmware.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return       0 or -1
+ */
+static int wlan_setup_station_hw(wlan_private * priv)
+{
+       int ret = -1;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       if ((ret = request_firmware(&priv->firmware, libertas_fw_name,
+                                   priv->hotplug_device)) < 0) {
+               lbs_pr_err("request_firmware() failed, error code = %#x\n",
+                      ret);
+               lbs_pr_err("%s not found in /lib/firmware\n", libertas_fw_name);
+               goto done;
+       }
+
+       if(check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
+               release_firmware(priv->firmware);
+               goto done;
+       }
+
+       ret = libertas_sbi_prog_firmware(priv);
+
+       release_firmware(priv->firmware);
+
+       if (ret) {
+               lbs_pr_debug(1, "Bootloader in invalid state!\n");
+               ret = -1;
+               goto done;
+       }
+
+       /*
+        * Read MAC address from HW
+        */
+       memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+       ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec,
+                                   0, cmd_option_waitforrsp, 0, NULL);
+
+       if (ret) {
+               ret = -1;
+               goto done;
+       }
+
+       libertas_set_mac_packet_filter(priv);
+
+       /* Get the supported Data rates */
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+                                   cmd_act_get_tx_rate,
+                                   cmd_option_waitforrsp, 0, NULL);
+
+       if (ret) {
+               ret = -1;
+               goto done;
+       }
+
+       ret = 0;
+done:
+       LEAVE();
+
+       return (ret);
+}
+
+static int wlan_allocate_adapter(wlan_private * priv)
+{
+       u32 ulbufsize;
+       wlan_adapter *adapter = priv->adapter;
+
+       struct bss_descriptor *ptempscantable;
+
+       /* Allocate buffer to store the BSSID list */
+       ulbufsize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST;
+       if (!(ptempscantable = kmalloc(ulbufsize, GFP_KERNEL))) {
+               libertas_free_adapter(priv);
+               return -1;
+       }
+
+       adapter->scantable = ptempscantable;
+       memset(adapter->scantable, 0, ulbufsize);
+
+       /* Allocate the command buffers */
+       libertas_allocate_cmd_buffer(priv);
+
+       memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
+       adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
+       adapter->libertas_ps_confirm_sleep.command =
+           cpu_to_le16(cmd_802_11_ps_mode);
+       adapter->libertas_ps_confirm_sleep.size =
+           cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
+       adapter->libertas_ps_confirm_sleep.result = 0;
+       adapter->libertas_ps_confirm_sleep.action =
+           cpu_to_le16(cmd_subcmd_sleep_confirmed);
+
+       return 0;
+}
+
+static void wlan_init_adapter(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int i;
+
+       adapter->scanprobes = 0;
+
+       adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+       adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+       /* ATIM params */
+       adapter->atimwindow = 0;
+
+       adapter->connect_status = libertas_disconnected;
+       memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+       /* scan type */
+       adapter->scantype = cmd_scan_type_active;
+
+       /* scan mode */
+       adapter->scanmode = cmd_bss_type_any;
+
+       /* 802.11 specific */
+       adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
+       for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
+            i++)
+               memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY));
+       adapter->wep_tx_keyidx = 0;
+       adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
+       adapter->secinfo.authmode = wlan802_11authmodeopen;
+       adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
+       adapter->secinfo.Encryptionmode = CIPHER_NONE;
+       adapter->inframode = wlan802_11infrastructure;
+
+       adapter->assoc_req = NULL;
+
+       adapter->numinscantable = 0;
+       adapter->pattemptedbssdesc = NULL;
+       mutex_init(&adapter->lock);
+
+       adapter->prescan = 1;
+
+       memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+
+       /* PnP and power profile */
+       adapter->surpriseremoved = 0;
+
+       adapter->currentpacketfilter =
+           cmd_act_mac_rx_on | cmd_act_mac_tx_on;
+
+       adapter->radioon = RADIO_ON;
+       adapter->txantenna = RF_ANTENNA_2;
+       adapter->rxantenna = RF_ANTENNA_AUTO;
+
+       adapter->is_datarate_auto = 1;
+       adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
+
+       // set default value of capinfo.
+#define SHORT_PREAMBLE_ALLOWED         1
+       memset(&adapter->capinfo, 0, sizeof(adapter->capinfo));
+       adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED;
+
+       adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
+
+       adapter->psmode = wlan802_11powermodecam;
+       adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+
+       adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
+
+       adapter->psstate = PS_STATE_FULL_POWER;
+       adapter->needtowakeup = 0;
+       adapter->locallisteninterval = 0;       /* default value in firmware will be used */
+
+       adapter->datarate = 0;  // Initially indicate the rate as auto
+
+       adapter->adhoc_grate_enabled = 0;
+
+       adapter->intcounter = 0;
+
+       adapter->currenttxskb = NULL;
+       adapter->pkttxctrl = 0;
+
+       memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
+       adapter->tx_queue_idx = 0;
+       spin_lock_init(&adapter->txqueue_lock);
+
+       return;
+}
+
+static void command_timer_fn(unsigned long data);
+
+int libertas_init_fw(wlan_private * priv)
+{
+       int ret = -1;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       /* Allocate adapter structure */
+       if ((ret = wlan_allocate_adapter(priv)) != 0)
+               goto done;
+
+       /* init adapter structure */
+       wlan_init_adapter(priv);
+
+       /* init timer etc. */
+       setup_timer(&adapter->command_timer, command_timer_fn,
+                       (unsigned long)priv);
+
+       /* download fimrware etc. */
+       if ((ret = wlan_setup_station_hw(priv)) != 0) {
+               del_timer_sync(&adapter->command_timer);
+               goto done;
+       }
+
+       /* init 802.11d */
+       libertas_init_11d(priv);
+
+       ret = 0;
+done:
+       LEAVE();
+       return ret;
+}
+
+void libertas_free_adapter(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+
+       if (!adapter) {
+               lbs_pr_debug(1, "Why double free adapter?:)\n");
+               return;
+       }
+
+       lbs_pr_debug(1, "Free command buffer\n");
+       libertas_free_cmd_buffer(priv);
+
+       lbs_pr_debug(1, "Free commandTimer\n");
+       del_timer(&adapter->command_timer);
+
+       lbs_pr_debug(1, "Free scantable\n");
+       if (adapter->scantable) {
+               kfree(adapter->scantable);
+               adapter->scantable = NULL;
+       }
+
+       lbs_pr_debug(1, "Free adapter\n");
+
+       /* Free the adapter object itself */
+       kfree(adapter);
+       priv->adapter = NULL;
+}
+
+/**
+ *  This function handles the timeout of command sending.
+ *  It will re-send the same command again.
+ */
+static void command_timer_fn(unsigned long data)
+{
+       wlan_private *priv = (wlan_private *)data;
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *ptempnode;
+       struct cmd_ds_command *cmd;
+       unsigned long flags;
+
+       ptempnode = adapter->cur_cmd;
+       cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
+
+       lbs_pr_info("command_timer_fn fired (%x)\n", cmd->command);
+
+       if (!adapter->fw_ready)
+               return;
+
+       if (ptempnode == NULL) {
+               lbs_pr_debug(1, "PTempnode Empty\n");
+               return;
+       }
+
+       spin_lock_irqsave(&adapter->driver_lock, flags);
+       adapter->cur_cmd = NULL;
+       spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+       lbs_pr_debug(1, "Re-sending same command as it timeout...!\n");
+       libertas_queue_cmd(adapter, ptempnode, 0);
+
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       return;
+}
diff --git a/drivers/net/wireless/libertas/fw.h b/drivers/net/wireless/libertas/fw.h
new file mode 100644 (file)
index 0000000..1f9ae26
--- /dev/null
@@ -0,0 +1,13 @@
+/**
+  * This header file contains FW interface related definitions.
+  */
+#ifndef _WLAN_FW_H_
+#define _WLAN_FW_H_
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN            32
+#endif
+
+int libertas_init_fw(wlan_private * priv);
+
+#endif                         /* _WLAN_FW_H_ */
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
new file mode 100644 (file)
index 0000000..c0faaec
--- /dev/null
@@ -0,0 +1,338 @@
+/**
+  * This file contains definitions of WLAN commands.
+  */
+
+#ifndef _HOST_H_
+#define _HOST_H_
+
+/** PUBLIC DEFINITIONS */
+#define DEFAULT_AD_HOC_CHANNEL       6
+#define DEFAULT_AD_HOC_CHANNEL_A    36
+
+/** IEEE 802.11 oids */
+#define OID_802_11_SSID                       0x00008002
+#define OID_802_11_INFRASTRUCTURE_MODE        0x00008008
+#define OID_802_11_FRAGMENTATION_THRESHOLD    0x00008009
+#define OID_802_11_RTS_THRESHOLD              0x0000800A
+#define OID_802_11_TX_ANTENNA_SELECTED        0x0000800D
+#define OID_802_11_SUPPORTED_RATES            0x0000800E
+#define OID_802_11_STATISTICS                 0x00008012
+#define OID_802_11_TX_RETRYCOUNT              0x0000801D
+#define OID_802_11D_ENABLE                    0x00008020
+
+#define cmd_option_waitforrsp             0x0002
+
+/** Host command ID */
+#define cmd_code_dnld                 0x0002
+#define cmd_get_hw_spec               0x0003
+#define cmd_eeprom_update             0x0004
+#define cmd_802_11_reset              0x0005
+#define cmd_802_11_scan               0x0006
+#define cmd_802_11_get_log            0x000b
+#define cmd_mac_multicast_adr         0x0010
+#define cmd_802_11_authenticate       0x0011
+#define cmd_802_11_eeprom_access      0x0059
+#define cmd_802_11_associate          0x0050
+#define cmd_802_11_set_wep            0x0013
+#define cmd_802_11_get_stat           0x0014
+#define cmd_802_3_get_stat            0x0015
+#define cmd_802_11_snmp_mib           0x0016
+#define cmd_mac_reg_map               0x0017
+#define cmd_bbp_reg_map               0x0018
+#define cmd_mac_reg_access            0x0019
+#define cmd_bbp_reg_access            0x001a
+#define cmd_rf_reg_access             0x001b
+#define cmd_802_11_radio_control      0x001c
+#define cmd_802_11_rf_channel         0x001d
+#define cmd_802_11_rf_tx_power        0x001e
+#define cmd_802_11_rssi               0x001f
+#define cmd_802_11_rf_antenna         0x0020
+
+#define cmd_802_11_ps_mode           0x0021
+
+#define cmd_802_11_data_rate          0x0022
+#define cmd_rf_reg_map                0x0023
+#define cmd_802_11_deauthenticate     0x0024
+#define cmd_802_11_reassociate        0x0025
+#define cmd_802_11_disassociate       0x0026
+#define cmd_mac_control               0x0028
+#define cmd_802_11_ad_hoc_start       0x002b
+#define cmd_802_11_ad_hoc_join        0x002c
+
+#define cmd_802_11_query_tkip_reply_cntrs  0x002e
+#define cmd_802_11_enable_rsn              0x002f
+#define cmd_802_11_pairwise_tsc       0x0036
+#define cmd_802_11_group_tsc          0x0037
+#define cmd_802_11_key_material       0x005e
+
+#define cmd_802_11_set_afc            0x003c
+#define cmd_802_11_get_afc            0x003d
+
+#define cmd_802_11_ad_hoc_stop        0x0040
+
+#define cmd_802_11_beacon_stop        0x0049
+
+#define cmd_802_11_mac_address        0x004D
+#define cmd_802_11_eeprom_access      0x0059
+
+#define cmd_802_11_band_config        0x0058
+
+#define cmd_802_11d_domain_info       0x005b
+
+#define cmd_802_11_sleep_params          0x0066
+
+#define cmd_802_11_inactivity_timeout    0x0067
+
+#define cmd_802_11_tpc_cfg               0x0072
+#define cmd_802_11_pwr_cfg               0x0073
+
+#define cmd_802_11_led_gpio_ctrl         0x004e
+
+#define cmd_802_11_subscribe_event       0x0075
+
+#define cmd_802_11_rate_adapt_rateset    0x0076
+
+#define cmd_802_11_tx_rate_query       0x007f
+
+#define cmd_get_tsf                      0x0080
+
+#define cmd_bt_access                 0x0087
+#define cmd_ret_bt_access                 0x8087
+
+#define cmd_fwt_access                0x0088
+#define cmd_ret_fwt_access                0x8088
+
+#define cmd_mesh_access               0x0090
+#define cmd_ret_mesh_access               0x8090
+
+/* For the IEEE Power Save */
+#define cmd_subcmd_enter_ps               0x0030
+#define cmd_subcmd_exit_ps                0x0031
+#define cmd_subcmd_sleep_confirmed        0x0034
+#define cmd_subcmd_full_powerdown         0x0035
+#define cmd_subcmd_full_powerup           0x0036
+
+/* command RET code, MSB is set to 1 */
+#define cmd_ret_hw_spec_info              0x8003
+#define cmd_ret_eeprom_update             0x8004
+#define cmd_ret_802_11_reset              0x8005
+#define cmd_ret_802_11_scan               0x8006
+#define cmd_ret_802_11_get_log            0x800b
+#define cmd_ret_mac_control               0x8028
+#define cmd_ret_mac_multicast_adr         0x8010
+#define cmd_ret_802_11_authenticate       0x8011
+#define cmd_ret_802_11_deauthenticate     0x8024
+#define cmd_ret_802_11_associate          0x8012
+#define cmd_ret_802_11_reassociate        0x8025
+#define cmd_ret_802_11_disassociate       0x8026
+#define cmd_ret_802_11_set_wep            0x8013
+#define cmd_ret_802_11_stat               0x8014
+#define cmd_ret_802_3_stat                0x8015
+#define cmd_ret_802_11_snmp_mib           0x8016
+#define cmd_ret_mac_reg_map               0x8017
+#define cmd_ret_bbp_reg_map               0x8018
+#define cmd_ret_rf_reg_map                0x8023
+#define cmd_ret_mac_reg_access            0x8019
+#define cmd_ret_bbp_reg_access            0x801a
+#define cmd_ret_rf_reg_access             0x801b
+#define cmd_ret_802_11_radio_control      0x801c
+#define cmd_ret_802_11_rf_channel         0x801d
+#define cmd_ret_802_11_rssi               0x801f
+#define cmd_ret_802_11_rf_tx_power        0x801e
+#define cmd_ret_802_11_rf_antenna         0x8020
+#define cmd_ret_802_11_ps_mode            0x8021
+#define cmd_ret_802_11_data_rate          0x8022
+
+#define cmd_ret_802_11_ad_hoc_start       0x802B
+#define cmd_ret_802_11_ad_hoc_join        0x802C
+
+#define cmd_ret_802_11_query_tkip_reply_cntrs  0x802e
+#define cmd_ret_802_11_enable_rsn              0x802f
+#define cmd_ret_802_11_pairwise_tsc       0x8036
+#define cmd_ret_802_11_group_tsc          0x8037
+#define cmd_ret_802_11_key_material       0x805e
+
+#define cmd_enable_rsn                    0x0001
+#define cmd_disable_rsn                   0x0000
+
+#define cmd_act_set                       0x0001
+#define cmd_act_get                       0x0000
+
+#define cmd_act_get_AES                   (cmd_act_get + 2)
+#define cmd_act_set_AES                   (cmd_act_set + 2)
+#define cmd_act_remove_aes                (cmd_act_set + 3)
+
+#define cmd_ret_802_11_set_afc            0x803c
+#define cmd_ret_802_11_get_afc            0x803d
+
+#define cmd_ret_802_11_ad_hoc_stop        0x8040
+
+#define cmd_ret_802_11_beacon_stop        0x8049
+
+#define cmd_ret_802_11_mac_address        0x804D
+#define cmd_ret_802_11_eeprom_access      0x8059
+
+#define cmd_ret_802_11_band_config        0x8058
+
+#define cmd_ret_802_11_sleep_params          0x8066
+
+#define cmd_ret_802_11_inactivity_timeout    0x8067
+
+#define cmd_ret_802_11d_domain_info      (0x8000 |                  \
+                                              cmd_802_11d_domain_info)
+
+#define cmd_ret_802_11_tpc_cfg        (cmd_802_11_tpc_cfg | 0x8000)
+#define cmd_ret_802_11_pwr_cfg        (cmd_802_11_pwr_cfg | 0x8000)
+
+#define cmd_ret_802_11_led_gpio_ctrl     0x804e
+
+#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000)
+
+#define cmd_ret_802_11_rate_adapt_rateset      (cmd_802_11_rate_adapt_rateset | 0x8000)
+
+#define cmd_rte_802_11_tx_rate_query   (cmd_802_11_tx_rate_query | 0x8000)
+
+#define cmd_ret_get_tsf             0x8080
+
+/* Define action or option for cmd_802_11_set_wep */
+#define cmd_act_add                         0x0002
+#define cmd_act_remove                      0x0004
+#define cmd_act_use_default                 0x0008
+
+#define cmd_type_wep_40_bit                 0x0001
+#define cmd_type_wep_104_bit                0x0002
+
+#define cmd_NUM_OF_WEP_KEYS                 4
+
+#define cmd_WEP_KEY_INDEX_MASK              0x3fff
+
+/* Define action or option for cmd_802_11_reset */
+#define cmd_act_halt                        0x0003
+
+/* Define action or option for cmd_802_11_scan */
+#define cmd_bss_type_bss                    0x0001
+#define cmd_bss_type_ibss                   0x0002
+#define cmd_bss_type_any                    0x0003
+
+/* Define action or option for cmd_802_11_scan */
+#define cmd_scan_type_active                0x0000
+#define cmd_scan_type_passive               0x0001
+
+#define cmd_scan_radio_type_bg         0
+
+#define cmd_scan_probe_delay_time           0
+
+/* Define action or option for cmd_mac_control */
+#define cmd_act_mac_rx_on                   0x0001
+#define cmd_act_mac_tx_on                   0x0002
+#define cmd_act_mac_loopback_on             0x0004
+#define cmd_act_mac_wep_enable              0x0008
+#define cmd_act_mac_int_enable              0x0010
+#define cmd_act_mac_multicast_enable        0x0020
+#define cmd_act_mac_broadcast_enable        0x0040
+#define cmd_act_mac_promiscuous_enable      0x0080
+#define cmd_act_mac_all_multicast_enable    0x0100
+#define cmd_act_mac_strict_protection_enable  0x0400
+
+/* Define action or option for cmd_802_11_radio_control */
+#define cmd_type_auto_preamble              0x0001
+#define cmd_type_short_preamble             0x0002
+#define cmd_type_long_preamble              0x0003
+
+#define TURN_ON_RF                              0x01
+#define RADIO_ON                                0x01
+#define RADIO_OFF                               0x00
+
+#define SET_AUTO_PREAMBLE                       0x05
+#define SET_SHORT_PREAMBLE                      0x03
+#define SET_LONG_PREAMBLE                       0x01
+
+/* Define action or option for CMD_802_11_RF_CHANNEL */
+#define cmd_opt_802_11_rf_channel_get       0x00
+#define cmd_opt_802_11_rf_channel_set       0x01
+
+/* Define action or option for cmd_802_11_rf_tx_power */
+#define cmd_act_tx_power_opt_get            0x0000
+#define cmd_act_tx_power_opt_set_high       0x8007
+#define cmd_act_tx_power_opt_set_mid        0x8004
+#define cmd_act_tx_power_opt_set_low        0x8000
+
+#define cmd_act_tx_power_index_high         0x0007
+#define cmd_act_tx_power_index_mid          0x0004
+#define cmd_act_tx_power_index_low          0x0000
+
+/* Define action or option for cmd_802_11_data_rate */
+#define cmd_act_set_tx_auto                 0x0000
+#define cmd_act_set_tx_fix_rate             0x0001
+#define cmd_act_get_tx_rate                 0x0002
+
+#define cmd_act_set_rx                      0x0001
+#define cmd_act_set_tx                      0x0002
+#define cmd_act_set_both                    0x0003
+#define cmd_act_get_rx                      0x0004
+#define cmd_act_get_tx                      0x0008
+#define cmd_act_get_both                    0x000c
+
+/* Define action or option for cmd_802_11_ps_mode */
+#define cmd_type_cam                        0x0000
+#define cmd_type_max_psp                    0x0001
+#define cmd_type_fast_psp                   0x0002
+
+/* Define action or option for cmd_bt_access */
+enum cmd_bt_access_opts {
+       /* The bt commands start at 5 instead of 1 because the old dft commands
+        * are mapped to 1-4.  These old commands are no longer maintained and
+        * should not be called.
+        */
+       cmd_act_bt_access_add = 5,
+       cmd_act_bt_access_del,
+       cmd_act_bt_access_list,
+       cmd_act_bt_access_reset
+};
+
+/* Define action or option for cmd_fwt_access */
+enum cmd_fwt_access_opts {
+       cmd_act_fwt_access_add = 1,
+       cmd_act_fwt_access_del,
+       cmd_act_fwt_access_lookup,
+       cmd_act_fwt_access_list,
+       cmd_act_fwt_access_list_route,
+       cmd_act_fwt_access_list_neighbor,
+       cmd_act_fwt_access_reset,
+       cmd_act_fwt_access_cleanup,
+       cmd_act_fwt_access_time,
+};
+
+/* Define action or option for cmd_mesh_access */
+enum cmd_mesh_access_opts {
+       cmd_act_mesh_get_ttl = 1,
+       cmd_act_mesh_set_ttl,
+       cmd_act_mesh_get_stats,
+       cmd_act_mesh_get_mpp,
+       cmd_act_mesh_set_mpp,
+};
+
+/** Card Event definition */
+#define MACREG_INT_CODE_TX_PPA_FREE             0x00000000
+#define MACREG_INT_CODE_TX_DMA_DONE             0x00000001
+#define MACREG_INT_CODE_LINK_LOSE_W_SCAN        0x00000002
+#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN       0x00000003
+#define MACREG_INT_CODE_LINK_SENSED             0x00000004
+#define MACREG_INT_CODE_CMD_FINISHED            0x00000005
+#define MACREG_INT_CODE_MIB_CHANGED             0x00000006
+#define MACREG_INT_CODE_INIT_DONE               0x00000007
+#define MACREG_INT_CODE_DEAUTHENTICATED         0x00000008
+#define MACREG_INT_CODE_DISASSOCIATED           0x00000009
+#define MACREG_INT_CODE_PS_AWAKE                0x0000000a
+#define MACREG_INT_CODE_PS_SLEEP                0x0000000b
+#define MACREG_INT_CODE_MIC_ERR_MULTICAST       0x0000000d
+#define MACREG_INT_CODE_MIC_ERR_UNICAST         0x0000000e
+#define MACREG_INT_CODE_WM_AWAKE                0x0000000f
+#define MACREG_INT_CODE_ADHOC_BCN_LOST          0x00000011
+#define MACREG_INT_CODE_RSSI_LOW               0x00000019
+#define MACREG_INT_CODE_SNR_LOW                        0x0000001a
+#define MACREG_INT_CODE_MAX_FAIL               0x0000001b
+#define MACREG_INT_CODE_RSSI_HIGH              0x0000001c
+#define MACREG_INT_CODE_SNR_HIGH               0x0000001d
+
+#endif                         /* _HOST_H_ */
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
new file mode 100644 (file)
index 0000000..f239e5d
--- /dev/null
@@ -0,0 +1,693 @@
+/*
+ * This file contains the function prototypes, data structure
+ * and defines for all the host/station commands
+ */
+#ifndef __HOSTCMD__H
+#define __HOSTCMD__H
+
+#include <linux/wireless.h>
+#include "11d.h"
+#include "types.h"
+
+/* 802.11-related definitions */
+
+/* TxPD descriptor */
+struct txpd {
+       /* Current Tx packet status */
+       u32 tx_status;
+       /* Tx control */
+       u32 tx_control;
+       u32 tx_packet_location;
+       /* Tx packet length */
+       u16 tx_packet_length;
+       /* First 2 byte of destination MAC address */
+       u8 tx_dest_addr_high[2];
+       /* Last 4 byte of destination MAC address */
+       u8 tx_dest_addr_low[4];
+       /* Pkt Priority */
+       u8 priority;
+       /* Pkt Trasnit Power control */
+       u8 powermgmt;
+       /* Amount of time the packet has been queued in the driver (units = 2ms) */
+       u8 pktdelay_2ms;
+       /* reserved */
+       u8 reserved1;
+};
+
+/* RxPD Descriptor */
+struct rxpd {
+       /* Current Rx packet status */
+       u16 status;
+
+       /* SNR */
+       u8 snr;
+
+       /* Tx control */
+       u8 rx_control;
+
+       /* Pkt length */
+       u16 pkt_len;
+
+       /* Noise Floor */
+       u8 nf;
+
+       /* Rx Packet Rate */
+       u8 rx_rate;
+
+       /* Pkt addr */
+       u32 pkt_ptr;
+
+       /* Next Rx RxPD addr */
+       u32 next_rxpd_ptr;
+
+       /* Pkt Priority */
+       u8 priority;
+       u8 reserved[3];
+};
+
+struct cmd_ctrl_node {
+       /* CMD link list */
+       struct list_head list;
+       u32 status;
+       /* CMD ID */
+       u32 cmd_oid;
+       /*CMD wait option: wait for finish or no wait */
+       u16 wait_option;
+       /* command parameter */
+       void *pdata_buf;
+       /*command data */
+       u8 *bufvirtualaddr;
+       u16 cmdflags;
+       /* wait queue */
+       u16 cmdwaitqwoken;
+       wait_queue_head_t cmdwait_q;
+};
+
+/* WLAN_802_11_KEY
+ *
+ * Generic structure to hold all key types.  key type (WEP40, WEP104, TKIP, AES)
+ * is determined from the keylength field.
+ */
+struct WLAN_802_11_KEY {
+       u32 len;
+       u32 flags;  /* KEY_INFO_* from wlan_defs.h */
+       u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH];
+       u16 type; /* KEY_TYPE_* from wlan_defs.h */
+};
+
+struct IE_WPA {
+       u8 elementid;
+       u8 len;
+       u8 oui[4];
+       u16 version;
+};
+
+struct WLAN_802_11_SSID {
+       /* SSID length */
+       u32 ssidlength;
+
+       /* SSID information field */
+       u8 ssid[IW_ESSID_MAX_SIZE];
+};
+
+struct WPA_SUPPLICANT {
+       u8 wpa_ie[256];
+       u8 wpa_ie_len;
+};
+
+/* wlan_offset_value */
+struct wlan_offset_value {
+       u32 offset;
+       u32 value;
+};
+
+struct WLAN_802_11_FIXED_IEs {
+       u8 timestamp[8];
+       u16 beaconinterval;
+       u16 capabilities;
+};
+
+struct WLAN_802_11_VARIABLE_IEs {
+       u8 elementid;
+       u8 length;
+       u8 data[1];
+};
+
+/* Define general data structure */
+/* cmd_DS_GEN */
+struct cmd_ds_gen {
+       u16 command;
+       u16 size;
+       u16 seqnum;
+       u16 result;
+};
+
+#define S_DS_GEN sizeof(struct cmd_ds_gen)
+/*
+ * Define data structure for cmd_get_hw_spec
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+struct cmd_ds_get_hw_spec {
+       /* HW Interface version number */
+       u16 hwifversion;
+       /* HW version number */
+       u16 version;
+       /* Max number of TxPD FW can handle */
+       u16 nr_txpd;
+       /* Max no of Multicast address */
+       u16 nr_mcast_adr;
+       /* MAC address */
+       u8 permanentaddr[6];
+
+       /* region Code */
+       u16 regioncode;
+
+       /* Number of antenna used */
+       u16 nr_antenna;
+
+       /* FW release number, example 0x1234=1.2.3.4 */
+       u32 fwreleasenumber;
+
+       /* Base Address of TxPD queue */
+       u32 wcb_base;
+       /* Read Pointer of RxPd queue */
+       u32 rxpd_rdptr;
+
+       /* Write Pointer of RxPd queue */
+       u32 rxpd_wrptr;
+
+       /*FW/HW capability */
+       u32 fwcapinfo;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_reset {
+       u16 action;
+};
+
+struct cmd_ds_802_11_subscribe_event {
+       u16 action;
+       u16 events;
+};
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for cmd_802_11_scan
+ */
+struct cmd_ds_802_11_scan {
+       u8 bsstype;
+       u8 BSSID[ETH_ALEN];
+       u8 tlvbuffer[1];
+#if 0
+       mrvlietypes_ssidparamset_t ssidParamSet;
+       mrvlietypes_chanlistparamset_t ChanListParamSet;
+       mrvlietypes_ratesparamset_t OpRateSet;
+#endif
+};
+
+struct cmd_ds_802_11_scan_rsp {
+       u16 bssdescriptsize;
+       u8 nr_sets;
+       u8 bssdesc_and_tlvbuffer[1];
+};
+
+struct cmd_ds_802_11_get_log {
+       u32 mcasttxframe;
+       u32 failed;
+       u32 retry;
+       u32 multiretry;
+       u32 framedup;
+       u32 rtssuccess;
+       u32 rtsfailure;
+       u32 ackfailure;
+       u32 rxfrag;
+       u32 mcastrxframe;
+       u32 fcserror;
+       u32 txframe;
+       u32 wepundecryptable;
+};
+
+struct cmd_ds_mac_control {
+       u16 action;
+       u16 reserved;
+};
+
+struct cmd_ds_mac_multicast_adr {
+       u16 action;
+       u16 nr_of_adrs;
+       u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+};
+
+struct cmd_ds_802_11_authenticate {
+       u8 macaddr[ETH_ALEN];
+       u8 authtype;
+       u8 reserved[10];
+};
+
+struct cmd_ds_802_11_deauthenticate {
+       u8 macaddr[6];
+       u16 reasoncode;
+};
+
+struct cmd_ds_802_11_associate {
+       u8 peerstaaddr[6];
+       struct ieeetypes_capinfo capinfo;
+       u16 listeninterval;
+       u16 bcnperiod;
+       u8 dtimperiod;
+
+#if 0
+       mrvlietypes_ssidparamset_t ssidParamSet;
+       mrvlietypes_phyparamset_t phyparamset;
+       mrvlietypes_ssparamset_t ssparamset;
+       mrvlietypes_ratesparamset_t ratesParamSet;
+#endif
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_disassociate {
+       u8 destmacaddr[6];
+       u16 reasoncode;
+};
+
+struct cmd_ds_802_11_associate_rsp {
+       struct ieeetypes_assocrsp assocRsp;
+};
+
+struct cmd_ds_802_11_ad_hoc_result {
+       u8 PAD[3];
+       u8 BSSID[ETH_ALEN];
+};
+
+struct cmd_ds_802_11_set_wep {
+       /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
+       u16 action;
+
+       /* key Index selected for Tx */
+       u16 keyindex;
+
+       /* 40, 128bit or TXWEP */
+       u8 keytype[4];
+       u8 keymaterial[4][16];
+};
+
+struct cmd_ds_802_3_get_stat {
+       u32 xmitok;
+       u32 rcvok;
+       u32 xmiterror;
+       u32 rcverror;
+       u32 rcvnobuffer;
+       u32 rcvcrcerror;
+};
+
+struct cmd_ds_802_11_get_stat {
+       u32 txfragmentcnt;
+       u32 mcasttxframecnt;
+       u32 failedcnt;
+       u32 retrycnt;
+       u32 Multipleretrycnt;
+       u32 rtssuccesscnt;
+       u32 rtsfailurecnt;
+       u32 ackfailurecnt;
+       u32 frameduplicatecnt;
+       u32 rxfragmentcnt;
+       u32 mcastrxframecnt;
+       u32 fcserrorcnt;
+       u32 bcasttxframecnt;
+       u32 bcastrxframecnt;
+       u32 txbeacon;
+       u32 rxbeacon;
+       u32 wepundecryptable;
+};
+
+struct cmd_ds_802_11_snmp_mib {
+       u16 querytype;
+       u16 oid;
+       u16 bufsize;
+       u8 value[128];
+};
+
+struct cmd_ds_mac_reg_map {
+       u16 buffersize;
+       u8 regmap[128];
+       u16 reserved;
+};
+
+struct cmd_ds_bbp_reg_map {
+       u16 buffersize;
+       u8 regmap[128];
+       u16 reserved;
+};
+
+struct cmd_ds_rf_reg_map {
+       u16 buffersize;
+       u8 regmap[64];
+       u16 reserved;
+};
+
+struct cmd_ds_mac_reg_access {
+       u16 action;
+       u16 offset;
+       u32 value;
+};
+
+struct cmd_ds_bbp_reg_access {
+       u16 action;
+       u16 offset;
+       u8 value;
+       u8 reserved[3];
+};
+
+struct cmd_ds_rf_reg_access {
+       u16 action;
+       u16 offset;
+       u8 value;
+       u8 reserved[3];
+};
+
+struct cmd_ds_802_11_radio_control {
+       u16 action;
+       u16 control;
+};
+
+struct cmd_ds_802_11_sleep_params {
+       /* ACT_GET/ACT_SET */
+       u16 action;
+
+       /* Sleep clock error in ppm */
+       u16 error;
+
+       /* Wakeup offset in usec */
+       u16 offset;
+
+       /* Clock stabilization time in usec */
+       u16 stabletime;
+
+       /* control periodic calibration */
+       u8 calcontrol;
+
+       /* control the use of external sleep clock */
+       u8 externalsleepclk;
+
+       /* reserved field, should be set to zero */
+       u16 reserved;
+};
+
+struct cmd_ds_802_11_inactivity_timeout {
+       /* ACT_GET/ACT_SET */
+       u16 action;
+
+       /* Inactivity timeout in msec */
+       u16 timeout;
+};
+
+struct cmd_ds_802_11_rf_channel {
+       u16 action;
+       u16 currentchannel;
+       u16 rftype;
+       u16 reserved;
+       u8 channellist[32];
+};
+
+struct cmd_ds_802_11_rssi {
+       /* weighting factor */
+       u16 N;
+
+       u16 reserved_0;
+       u16 reserved_1;
+       u16 reserved_2;
+};
+
+struct cmd_ds_802_11_rssi_rsp {
+       u16 SNR;
+       u16 noisefloor;
+       u16 avgSNR;
+       u16 avgnoisefloor;
+};
+
+struct cmd_ds_802_11_mac_address {
+       u16 action;
+       u8 macadd[ETH_ALEN];
+};
+
+struct cmd_ds_802_11_rf_tx_power {
+       u16 action;
+       u16 currentlevel;
+};
+
+struct cmd_ds_802_11_rf_antenna {
+       u16 action;
+
+       /* Number of antennas or 0xffff(diversity) */
+       u16 antennamode;
+
+};
+
+struct cmd_ds_802_11_ps_mode {
+       u16 action;
+       u16 nullpktinterval;
+       u16 multipledtim;
+       u16 reserved;
+       u16 locallisteninterval;
+};
+
+struct PS_CMD_ConfirmSleep {
+       u16 command;
+       u16 size;
+       u16 seqnum;
+       u16 result;
+
+       u16 action;
+       u16 reserved1;
+       u16 multipledtim;
+       u16 reserved;
+       u16 locallisteninterval;
+};
+
+struct cmd_ds_802_11_data_rate {
+       u16 action;
+       u16 reserverd;
+       u8 datarate[G_SUPPORTED_RATES];
+};
+
+struct cmd_ds_802_11_rate_adapt_rateset {
+       u16 action;
+       u16 enablehwauto;
+       u16 bitmap;
+};
+
+struct cmd_ds_802_11_ad_hoc_start {
+       u8 SSID[IW_ESSID_MAX_SIZE];
+       u8 bsstype;
+       u16 beaconperiod;
+       u8 dtimperiod;
+       union IEEEtypes_ssparamset ssparamset;
+       union ieeetypes_phyparamset phyparamset;
+       u16 probedelay;
+       struct ieeetypes_capinfo cap;
+       u8 datarate[G_SUPPORTED_RATES];
+       u8 tlv_memory_size_pad[100];
+} __attribute__ ((packed));
+
+struct adhoc_bssdesc {
+       u8 BSSID[6];
+       u8 SSID[32];
+       u8 bsstype;
+       u16 beaconperiod;
+       u8 dtimperiod;
+       u8 timestamp[8];
+       u8 localtime[8];
+       union ieeetypes_phyparamset phyparamset;
+       union IEEEtypes_ssparamset ssparamset;
+       struct ieeetypes_capinfo cap;
+       u8 datarates[G_SUPPORTED_RATES];
+
+       /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
+        * Adhoc join command and will cause a binary layout mismatch with
+        * the firmware
+        */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_join {
+       struct adhoc_bssdesc bssdescriptor;
+       u16 failtimeout;
+       u16 probedelay;
+
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_enable_rsn {
+       u16 action;
+       u16 enable;
+};
+
+struct MrvlIEtype_keyParamSet {
+       /* type ID */
+       u16 type;
+
+       /* length of Payload */
+       u16 length;
+
+       /* type of key: WEP=0, TKIP=1, AES=2 */
+       u16 keytypeid;
+
+       /* key control Info specific to a keytypeid */
+       u16 keyinfo;
+
+       /* length of key */
+       u16 keylen;
+
+       /* key material of size keylen */
+       u8 key[32];
+};
+
+struct cmd_ds_802_11_key_material {
+       u16 action;
+       struct MrvlIEtype_keyParamSet keyParamSet[2];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_eeprom_access {
+       u16 action;
+
+       /* multiple 4 */
+       u16 offset;
+       u16 bytecount;
+       u8 value;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_tpc_cfg {
+       u16 action;
+       u8 enable;
+       s8 P0;
+       s8 P1;
+       s8 P2;
+       u8 usesnr;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_led_ctrl {
+       u16 action;
+       u16 numled;
+       u8 data[256];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_pwr_cfg {
+       u16 action;
+       u8 enable;
+       s8 PA_P0;
+       s8 PA_P1;
+       s8 PA_P2;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_afc {
+       u16 afc_auto;
+       union {
+               struct {
+                       u16 threshold;
+                       u16 period;
+               };
+               struct {
+                       s16 timing_offset;
+                       s16 carrier_offset;
+               };
+       };
+} __attribute__ ((packed));
+
+struct cmd_tx_rate_query {
+       u16 txrate;
+} __attribute__ ((packed));
+
+struct cmd_ds_get_tsf {
+       __le64 tsfvalue;
+} __attribute__ ((packed));
+
+struct cmd_ds_bt_access {
+       u16 action;
+       u32 id;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_fwt_access {
+       u16 action;
+       u32 id;
+       u8 da[ETH_ALEN];
+       u8 dir;
+       u8 ra[ETH_ALEN];
+       u32 ssn;
+       u32 dsn;
+       u32 metric;
+       u8 hopcount;
+       u8 ttl;
+       u32 expiration;
+       u8 sleepmode;
+       u32 snr;
+       u32 references;
+} __attribute__ ((packed));
+
+#define MESH_STATS_NUM 7
+struct cmd_ds_mesh_access {
+       u16 action;
+       u32 data[MESH_STATS_NUM + 1];   /* last position reserved */
+} __attribute__ ((packed));
+
+struct cmd_ds_command {
+       /* command header */
+       u16 command;
+       u16 size;
+       u16 seqnum;
+       u16 result;
+
+       /* command Body */
+       union {
+               struct cmd_ds_get_hw_spec hwspec;
+               struct cmd_ds_802_11_ps_mode psmode;
+               struct cmd_ds_802_11_scan scan;
+               struct cmd_ds_802_11_scan_rsp scanresp;
+               struct cmd_ds_mac_control macctrl;
+               struct cmd_ds_802_11_associate associate;
+               struct cmd_ds_802_11_deauthenticate deauth;
+               struct cmd_ds_802_11_set_wep wep;
+               struct cmd_ds_802_11_ad_hoc_start ads;
+               struct cmd_ds_802_11_reset reset;
+               struct cmd_ds_802_11_ad_hoc_result result;
+               struct cmd_ds_802_11_get_log glog;
+               struct cmd_ds_802_11_authenticate auth;
+               struct cmd_ds_802_11_get_stat gstat;
+               struct cmd_ds_802_3_get_stat gstat_8023;
+               struct cmd_ds_802_11_snmp_mib smib;
+               struct cmd_ds_802_11_rf_tx_power txp;
+               struct cmd_ds_802_11_rf_antenna rant;
+               struct cmd_ds_802_11_data_rate drate;
+               struct cmd_ds_802_11_rate_adapt_rateset rateset;
+               struct cmd_ds_mac_multicast_adr madr;
+               struct cmd_ds_802_11_ad_hoc_join adj;
+               struct cmd_ds_802_11_radio_control radio;
+               struct cmd_ds_802_11_rf_channel rfchannel;
+               struct cmd_ds_802_11_rssi rssi;
+               struct cmd_ds_802_11_rssi_rsp rssirsp;
+               struct cmd_ds_802_11_disassociate dassociate;
+               struct cmd_ds_802_11_mac_address macadd;
+               struct cmd_ds_802_11_enable_rsn enbrsn;
+               struct cmd_ds_802_11_key_material keymaterial;
+               struct cmd_ds_mac_reg_access macreg;
+               struct cmd_ds_bbp_reg_access bbpreg;
+               struct cmd_ds_rf_reg_access rfreg;
+               struct cmd_ds_802_11_eeprom_access rdeeprom;
+
+               struct cmd_ds_802_11d_domain_info domaininfo;
+               struct cmd_ds_802_11d_domain_info domaininforesp;
+
+               struct cmd_ds_802_11_sleep_params sleep_params;
+               struct cmd_ds_802_11_inactivity_timeout inactivity_timeout;
+               struct cmd_ds_802_11_tpc_cfg tpccfg;
+               struct cmd_ds_802_11_pwr_cfg pwrcfg;
+               struct cmd_ds_802_11_afc afc;
+               struct cmd_ds_802_11_led_ctrl ledgpio;
+
+               struct cmd_tx_rate_query txrate;
+               struct cmd_ds_bt_access bt;
+               struct cmd_ds_fwt_access fwt;
+               struct cmd_ds_mesh_access mesh;
+               struct cmd_ds_get_tsf gettsf;
+               struct cmd_ds_802_11_subscribe_event subscribe_event;
+       } params;
+} __attribute__ ((packed));
+
+#endif
diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c
new file mode 100644 (file)
index 0000000..567000c
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+  * This file contains functions used in USB Boot command
+  * and Boot2/FW update
+  */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "defs.h"
+#include "dev.h"
+#include "if_usb.h"
+
+/**
+ *  @brief This function issues Boot command to the Boot2 code
+ *  @param ivalue   1:Boot from FW by USB-Download
+ *                  2:Boot from FW in EEPROM
+ *  @return            0
+ */
+int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
+{
+       struct usb_card_rec     *cardp = priv->wlan_dev.card;
+       struct bootcmdstr       sbootcmd;
+       int i;
+
+       /* Prepare command */
+       sbootcmd.u32magicnumber = BOOT_CMD_MAGIC_NUMBER;
+       sbootcmd.u8cmd_tag = ivalue;
+       for (i=0; i<11; i++)
+               sbootcmd.au8dumy[i]=0x00;
+       memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
+
+       /* Issue command */
+       usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
+
+       return 0;
+}
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
new file mode 100644 (file)
index 0000000..695fb6a
--- /dev/null
@@ -0,0 +1,952 @@
+/**
+  * This file contains functions used in USB interface module.
+  */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "if_usb.h"
+
+#define MESSAGE_HEADER_LEN     4
+
+static const char usbdriver_name[] = "usb8xxx";
+
+static struct usb_device_id if_usb_table[] = {
+       /* Enter the device signature inside */
+       {
+               USB_DEVICE(USB8388_VID_1, USB8388_PID_1),
+       },
+       {
+               USB_DEVICE(USB8388_VID_2, USB8388_PID_2),
+       },
+       {}      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, if_usb_table);
+
+static void if_usb_receive(struct urb *urb);
+static void if_usb_receive_fwload(struct urb *urb);
+
+/**
+ *  @brief  call back function to handle the status of the URB
+ *  @param urb                 pointer to urb structure
+ *  @return            N/A
+ */
+static void if_usb_write_bulk_callback(struct urb *urb)
+{
+       wlan_private *priv = (wlan_private *) (urb->context);
+       wlan_adapter *adapter = priv->adapter;
+       struct net_device *dev = priv->wlan_dev.netdev;
+
+       /* handle the transmission complete validations */
+
+       if (urb->status != 0) {
+               /* print the failure status number for debug */
+               lbs_pr_info("URB in failure status\n");
+       } else {
+               lbs_dev_dbg(2, &urb->dev->dev, "URB status is successfull\n");
+               lbs_dev_dbg(2, &urb->dev->dev, "Actual length transmitted %d\n",
+                      urb->actual_length);
+               priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+               /* Wake main thread if commands are pending */
+               if (!adapter->cur_cmd)
+                       wake_up_interruptible(&priv->mainthread.waitq);
+               if ((adapter->connect_status == libertas_connected))
+                       netif_wake_queue(dev);
+       }
+
+       return;
+}
+
+/**
+ *  @brief  free tx/rx urb, skb and rx buffer
+ *  @param cardp       pointer usb_card_rec
+ *  @return            N/A
+ */
+void if_usb_free(struct usb_card_rec *cardp)
+{
+       ENTER();
+
+       /* Unlink tx & rx urb */
+       usb_kill_urb(cardp->tx_urb);
+       usb_kill_urb(cardp->rx_urb);
+
+       usb_free_urb(cardp->tx_urb);
+       cardp->tx_urb = NULL;
+
+       usb_free_urb(cardp->rx_urb);
+       cardp->rx_urb = NULL;
+
+       kfree(cardp->bulk_out_buffer);
+       cardp->bulk_out_buffer = NULL;
+
+       LEAVE();
+       return;
+}
+
+/**
+ *  @brief sets the configuration values
+ *  @param ifnum       interface number
+ *  @param id          pointer to usb_device_id
+ *  @return            0 on success, error code on failure
+ */
+static int if_usb_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       struct usb_device *udev;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       wlan_private *pwlanpriv;
+       struct usb_card_rec *usb_cardp;
+       int i;
+
+       udev = interface_to_usbdev(intf);
+
+       usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
+       if (!usb_cardp) {
+               lbs_pr_err("Out of memory allocating private data.\n");
+               goto error;
+       }
+
+       usb_cardp->udev = udev;
+       iface_desc = intf->cur_altsetting;
+
+       lbs_dev_dbg(1, &udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
+              " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+              udev->descriptor.bcdUSB,
+              udev->descriptor.bDeviceClass,
+              udev->descriptor.bDeviceSubClass,
+              udev->descriptor.bDeviceProtocol);
+
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+               if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                   && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+                       USB_ENDPOINT_XFER_BULK)) {
+                       /* we found a bulk in endpoint */
+                       lbs_dev_dbg(1, &udev->dev, "Bulk in size is %d\n",
+                              endpoint->wMaxPacketSize);
+                       if (!
+                           (usb_cardp->rx_urb =
+                            usb_alloc_urb(0, GFP_KERNEL))) {
+                               lbs_dev_dbg(1, &udev->dev,
+                                      "Rx URB allocation failed\n");
+                               goto dealloc;
+                       }
+                       usb_cardp->rx_urb_recall = 0;
+
+                       usb_cardp->bulk_in_size =
+                           endpoint->wMaxPacketSize;
+                       usb_cardp->bulk_in_endpointAddr =
+                           (endpoint->
+                            bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+                       lbs_dev_dbg(1, &udev->dev, "in_endpoint = %d\n",
+                              endpoint->bEndpointAddress);
+               }
+
+               if (((endpoint->
+                     bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+                    USB_DIR_OUT)
+                   && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+                       USB_ENDPOINT_XFER_BULK)) {
+                       /* We found bulk out endpoint */
+                       if (!
+                           (usb_cardp->tx_urb =
+                            usb_alloc_urb(0, GFP_KERNEL))) {
+                               lbs_dev_dbg(1,&udev->dev,
+                                      "Tx URB allocation failed\n");
+                               goto dealloc;
+                       }
+
+                       usb_cardp->bulk_out_size =
+                           endpoint->wMaxPacketSize;
+                       lbs_dev_dbg(1, &udev->dev,
+                                   "Bulk out size is %d\n",
+                                   endpoint->wMaxPacketSize);
+                       usb_cardp->bulk_out_endpointAddr =
+                           endpoint->bEndpointAddress;
+                       lbs_dev_dbg(1, &udev->dev, "out_endpoint = %d\n",
+                                   endpoint->bEndpointAddress);
+                       usb_cardp->bulk_out_buffer =
+                           kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
+                                   GFP_KERNEL);
+
+                       if (!usb_cardp->bulk_out_buffer) {
+                               lbs_dev_dbg(1, &udev->dev,
+                                      "Could not allocate buffer\n");
+                               goto dealloc;
+                       }
+               }
+       }
+
+
+       /* At this point wlan_add_card() will be called.  Don't worry
+        * about keeping pwlanpriv around since it will be set on our
+        * usb device data in -> add() -> libertas_sbi_register_dev().
+        */
+       if (!(pwlanpriv = wlan_add_card(usb_cardp)))
+               goto dealloc;
+
+       usb_get_dev(udev);
+       usb_set_intfdata(intf, usb_cardp);
+
+       /*
+        * return card structure, which can be got back in the
+        * diconnect function as the ptr
+        * argument.
+        */
+       return 0;
+
+dealloc:
+       if_usb_free(usb_cardp);
+
+error:
+       return -ENOMEM;
+}
+
+/**
+ *  @brief free resource and cleanup
+ *  @param udev                pointer to usb_device
+ *  @param ptr         pointer to usb_cardp
+ *  @return            N/A
+ */
+static void if_usb_disconnect(struct usb_interface *intf)
+{
+       struct usb_card_rec *cardp = usb_get_intfdata(intf);
+       wlan_private *priv = (wlan_private *) cardp->priv;
+       wlan_adapter *adapter = NULL;
+
+       adapter = priv->adapter;
+
+       /*
+        * Update Surprise removed to TRUE
+        */
+       adapter->surpriseremoved = 1;
+
+       /* card is removed and we can call wlan_remove_card */
+       lbs_dev_dbg(1, &cardp->udev->dev, "call remove card\n");
+       wlan_remove_card(cardp);
+
+       /* Unlink and free urb */
+       if_usb_free(cardp);
+
+       usb_set_intfdata(intf, NULL);
+       usb_put_dev(interface_to_usbdev(intf));
+
+       return;
+}
+
+/**
+ *  @brief  This function download FW
+ *  @param priv                pointer to wlan_private
+ *  @return            0
+ */
+static int if_prog_firmware(wlan_private * priv)
+{
+       struct usb_card_rec *cardp = priv->wlan_dev.card;
+       struct FWData *fwdata;
+       struct fwheader *fwheader;
+       u8 *firmware = priv->firmware->data;
+
+       fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
+
+       if (!fwdata)
+               return -1;
+
+       fwheader = &fwdata->fwheader;
+
+       if (!cardp->CRC_OK) {
+               cardp->totalbytes = cardp->fwlastblksent;
+               cardp->fwseqnum = cardp->lastseqnum - 1;
+       }
+
+       lbs_dev_dbg(2, &cardp->udev->dev, "totalbytes = %d\n",
+                   cardp->totalbytes);
+
+       memcpy(fwheader, &firmware[cardp->totalbytes],
+              sizeof(struct fwheader));
+
+       cardp->fwlastblksent = cardp->totalbytes;
+       cardp->totalbytes += sizeof(struct fwheader);
+
+       lbs_dev_dbg(2, &cardp->udev->dev,"Copy Data\n");
+       memcpy(fwdata->data, &firmware[cardp->totalbytes],
+              fwdata->fwheader.datalength);
+
+       lbs_dev_dbg(2, &cardp->udev->dev,
+                   "Data length = %d\n", fwdata->fwheader.datalength);
+
+       cardp->fwseqnum = cardp->fwseqnum + 1;
+
+       fwdata->seqnum = cardp->fwseqnum;
+       cardp->lastseqnum = fwdata->seqnum;
+       cardp->totalbytes += fwdata->fwheader.datalength;
+
+       if (fwheader->dnldcmd == FW_HAS_DATA_TO_RECV) {
+               lbs_dev_dbg(2, &cardp->udev->dev, "There is data to follow\n");
+               lbs_dev_dbg(2, &cardp->udev->dev,
+                           "seqnum = %d totalbytes = %d\n", cardp->fwseqnum,
+                           cardp->totalbytes);
+               memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
+               usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+
+       } else if (fwdata->fwheader.dnldcmd == FW_HAS_LAST_BLOCK) {
+               lbs_dev_dbg(2, &cardp->udev->dev,
+                           "Host has finished FW downloading\n");
+               lbs_dev_dbg(2, &cardp->udev->dev,
+                           "Donwloading FW JUMP BLOCK\n");
+               memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
+               usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+               cardp->fwfinalblk = 1;
+       }
+
+       lbs_dev_dbg(2, &cardp->udev->dev,
+                   "The firmware download is done size is %d\n",
+                   cardp->totalbytes);
+
+       kfree(fwdata);
+
+       return 0;
+}
+
+static int libertas_do_reset(wlan_private *priv)
+{
+       int ret;
+       struct usb_card_rec *cardp = priv->wlan_dev.card;
+
+       ret = usb_reset_device(cardp->udev);
+       if (!ret) {
+               msleep(10);
+               reset_device(priv);
+               msleep(10);
+       }
+       return ret;
+}
+
+/**
+ *  @brief This function transfer the data to the device.
+ *  @param priv        pointer to wlan_private
+ *  @param payload     pointer to payload data
+ *  @param nb          data length
+ *  @return            0 or -1
+ */
+int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
+{
+       /* pointer to card structure */
+       struct usb_card_rec *cardp = priv->wlan_dev.card;
+       int ret = -1;
+
+       /* check if device is removed */
+       if (priv->adapter->surpriseremoved) {
+               lbs_dev_dbg(1, &cardp->udev->dev, "Device removed\n");
+               goto tx_ret;
+       }
+
+       usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
+                         usb_sndbulkpipe(cardp->udev,
+                                         cardp->bulk_out_endpointAddr),
+                         payload, nb, if_usb_write_bulk_callback, priv);
+
+       cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+       if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
+               /*  transfer failed */
+               lbs_dev_dbg(1, &cardp->udev->dev, "usb_submit_urb failed\n");
+               ret = -1;
+       } else {
+               lbs_dev_dbg(2, &cardp->udev->dev, "usb_submit_urb success\n");
+               ret = 0;
+       }
+
+tx_ret:
+       return ret;
+}
+
+static int __if_usb_submit_rx_urb(wlan_private * priv,
+                                 void (*callbackfn)
+                                 (struct urb *urb))
+{
+       struct usb_card_rec *cardp = priv->wlan_dev.card;
+       struct sk_buff *skb;
+       struct read_cb_info *rinfo = &cardp->rinfo;
+       int ret = -1;
+
+       if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
+               lbs_pr_err("No free skb\n");
+               goto rx_ret;
+       }
+
+       rinfo->skb = skb;
+
+       /* Fill the receive configuration URB and initialise the Rx call back */
+       usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
+                         usb_rcvbulkpipe(cardp->udev,
+                                         cardp->bulk_in_endpointAddr),
+                         skb->tail + IPFIELD_ALIGN_OFFSET,
+                         MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
+                         rinfo);
+
+       cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+       lbs_dev_dbg(2, &cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+       if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
+               /* handle failure conditions */
+               lbs_dev_dbg(1, &cardp->udev->dev, "Submit Rx URB failed\n");
+               ret = -1;
+       } else {
+               lbs_dev_dbg(2, &cardp->udev->dev, "Submit Rx URB success\n");
+               ret = 0;
+       }
+
+rx_ret:
+       return ret;
+}
+
+static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
+{
+       return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
+}
+
+static inline int if_usb_submit_rx_urb(wlan_private * priv)
+{
+       return __if_usb_submit_rx_urb(priv, &if_usb_receive);
+}
+
+static void if_usb_receive_fwload(struct urb *urb)
+{
+       struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
+       wlan_private *priv = rinfo->priv;
+       struct sk_buff *skb = rinfo->skb;
+       struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+       struct fwsyncheader *syncfwheader;
+       struct bootcmdrespStr bootcmdresp;
+
+       if (urb->status) {
+               lbs_dev_dbg(1, &cardp->udev->dev,
+                           "URB status is failed during fw load\n");
+               kfree_skb(skb);
+               return;
+       }
+
+       if (cardp->bootcmdresp == 0) {
+               memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
+                       sizeof(bootcmdresp));
+               if (cardp->udev->descriptor.bcdDevice < 0x3106) {
+                       kfree_skb(skb);
+                       if_usb_submit_rx_urb_fwload(priv);
+                       cardp->bootcmdresp = 1;
+                       lbs_dev_dbg(1, &cardp->udev->dev,
+                                   "Received valid boot command response\n");
+                       return;
+               }
+               if (bootcmdresp.u32magicnumber != BOOT_CMD_MAGIC_NUMBER) {
+                       lbs_pr_info(
+                               "boot cmd response wrong magic number (0x%x)\n",
+                               bootcmdresp.u32magicnumber);
+               } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) {
+                       lbs_pr_info(
+                               "boot cmd response cmd_tag error (%d)\n",
+                               bootcmdresp.u8cmd_tag);
+               } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) {
+                       lbs_pr_info(
+                               "boot cmd response result error (%d)\n",
+                               bootcmdresp.u8result);
+               } else {
+                       cardp->bootcmdresp = 1;
+                       lbs_dev_dbg(1, &cardp->udev->dev,
+                                   "Received valid boot command response\n");
+               }
+               kfree_skb(skb);
+               if_usb_submit_rx_urb_fwload(priv);
+               return;
+       }
+
+       syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+       if (!syncfwheader) {
+               lbs_dev_dbg(1, &cardp->udev->dev, "Failure to allocate syncfwheader\n");
+               kfree_skb(skb);
+               return;
+       }
+
+       memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
+                       sizeof(struct fwsyncheader));
+
+       if (!syncfwheader->cmd) {
+               lbs_dev_dbg(2, &cardp->udev->dev,
+                           "FW received Blk with correct CRC\n");
+               lbs_dev_dbg(2, &cardp->udev->dev,
+                           "FW received Blk seqnum = %d\n",
+                      syncfwheader->seqnum);
+               cardp->CRC_OK = 1;
+       } else {
+               lbs_dev_dbg(1, &cardp->udev->dev,
+                           "FW received Blk with CRC error\n");
+               cardp->CRC_OK = 0;
+       }
+
+       kfree_skb(skb);
+
+       if (cardp->fwfinalblk) {
+               cardp->fwdnldover = 1;
+               goto exit;
+       }
+
+       if_prog_firmware(priv);
+
+       if_usb_submit_rx_urb_fwload(priv);
+exit:
+       kfree(syncfwheader);
+
+       return;
+
+}
+
+#define MRVDRV_MIN_PKT_LEN     30
+
+static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
+                                      struct usb_card_rec *cardp,
+                                      wlan_private *priv)
+{
+       if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +
+           MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) {
+               lbs_dev_dbg(1, &cardp->udev->dev,
+                           "Packet length is Invalid\n");
+               kfree_skb(skb);
+               return;
+       }
+
+       skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
+       skb_put(skb, recvlength);
+       skb_pull(skb, MESSAGE_HEADER_LEN);
+       libertas_process_rxed_packet(priv, skb);
+       priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN);
+}
+
+static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
+                                     struct sk_buff *skb,
+                                     struct usb_card_rec *cardp,
+                                     wlan_private *priv)
+{
+       u8 *cmdbuf;
+       if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) {
+               lbs_dev_dbg(1, &cardp->udev->dev,
+                           "The receive buffer is too large\n");
+               kfree_skb(skb);
+               return;
+       }
+
+       if (!in_interrupt())
+               BUG();
+
+       spin_lock(&priv->adapter->driver_lock);
+       /* take care of cur_cmd = NULL case by reading the
+        * data to clear the interrupt */
+       if (!priv->adapter->cur_cmd) {
+               cmdbuf = priv->wlan_dev.upld_buf;
+               priv->adapter->hisregcpy &= ~his_cmdupldrdy;
+       } else
+               cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
+
+       cardp->usb_int_cause |= his_cmdupldrdy;
+       priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN);
+       memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
+              priv->wlan_dev.upld_len);
+
+       kfree_skb(skb);
+       libertas_interrupt(priv->wlan_dev.netdev);
+       spin_unlock(&priv->adapter->driver_lock);
+
+       lbs_dev_dbg(1, &cardp->udev->dev,
+                   "Wake up main thread to handle cmd response\n");
+
+       return;
+}
+
+/**
+ *  @brief This function reads of the packet into the upload buff,
+ *  wake up the main thread and initialise the Rx callack.
+ *
+ *  @param urb         pointer to struct urb
+ *  @return            N/A
+ */
+static void if_usb_receive(struct urb *urb)
+{
+       struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
+       wlan_private *priv = rinfo->priv;
+       struct sk_buff *skb = rinfo->skb;
+       struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+
+       int recvlength = urb->actual_length;
+       u8 *recvbuff = NULL;
+       u32 recvtype;
+
+       ENTER();
+
+       if (recvlength) {
+               if (urb->status) {
+                       lbs_dev_dbg(1, &cardp->udev->dev,
+                                   "URB status is failed\n");
+                       kfree_skb(skb);
+                       goto setup_for_next;
+               }
+
+               recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
+               memcpy(&recvtype, recvbuff, sizeof(u32));
+               lbs_dev_dbg(1, &cardp->udev->dev,
+                           "Recv length = 0x%x\n", recvlength);
+               lbs_dev_dbg(1, &cardp->udev->dev,
+                           "Receive type = 0x%X\n", recvtype);
+               recvtype = le32_to_cpu(recvtype);
+               lbs_dev_dbg(1, &cardp->udev->dev,
+                           "Receive type after = 0x%X\n", recvtype);
+       } else if (urb->status)
+               goto rx_exit;
+
+
+       switch (recvtype) {
+       case CMD_TYPE_DATA:
+               process_cmdtypedata(recvlength, skb, cardp, priv);
+               break;
+
+       case CMD_TYPE_REQUEST:
+               process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
+               break;
+
+       case CMD_TYPE_INDICATION:
+               /* Event cause handling */
+               spin_lock(&priv->adapter->driver_lock);
+               cardp->usb_event_cause = *(u32 *) (recvbuff + MESSAGE_HEADER_LEN);
+               lbs_dev_dbg(1, &cardp->udev->dev,"**EVENT** 0x%X\n",
+                           cardp->usb_event_cause);
+               if (cardp->usb_event_cause & 0xffff0000) {
+                       libertas_send_tx_feedback(priv);
+                       break;
+               }
+               cardp->usb_event_cause = le32_to_cpu(cardp->usb_event_cause) << 3;
+               cardp->usb_int_cause |= his_cardevent;
+               kfree_skb(skb);
+               libertas_interrupt(priv->wlan_dev.netdev);
+               spin_unlock(&priv->adapter->driver_lock);
+               goto rx_exit;
+       default:
+               kfree_skb(skb);
+               break;
+       }
+
+setup_for_next:
+       if_usb_submit_rx_urb(priv);
+rx_exit:
+       LEAVE();
+       return;
+}
+
+/**
+ *  @brief This function downloads data to FW
+ *  @param priv                pointer to wlan_private structure
+ *  @param type                type of data
+ *  @param buf         pointer to data buffer
+ *  @param len         number of bytes
+ *  @return            0 or -1
+ */
+int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
+{
+       int ret = -1;
+       u32 tmp;
+       struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+
+       lbs_dev_dbg(1, &cardp->udev->dev,"*** type = %u\n", type);
+       lbs_dev_dbg(1, &cardp->udev->dev,"size after = %d\n", nb);
+
+       if (type == MVMS_CMD) {
+               tmp = cpu_to_le32(CMD_TYPE_REQUEST);
+               priv->wlan_dev.dnld_sent = DNLD_CMD_SENT;
+               memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
+                      MESSAGE_HEADER_LEN);
+
+       } else {
+               tmp = cpu_to_le32(CMD_TYPE_DATA);
+               priv->wlan_dev.dnld_sent = DNLD_DATA_SENT;
+               memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
+                      MESSAGE_HEADER_LEN);
+       }
+
+       memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
+
+       ret =
+           usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN);
+
+       return ret;
+}
+
+/* called with adapter->driver_lock held */
+int libertas_sbi_get_int_status(wlan_private * priv, u8 * ireg)
+{
+       struct usb_card_rec *cardp = priv->wlan_dev.card;
+
+       *ireg = cardp->usb_int_cause;
+       cardp->usb_int_cause = 0;
+
+       lbs_dev_dbg(1, &cardp->udev->dev,"Int cause is 0x%X\n", *ireg);
+
+       return 0;
+}
+
+int libertas_sbi_read_event_cause(wlan_private * priv)
+{
+       struct usb_card_rec *cardp = priv->wlan_dev.card;
+       priv->adapter->eventcause = cardp->usb_event_cause;
+       /* Re-submit rx urb here to avoid event lost issue */
+       if_usb_submit_rx_urb(priv);
+       return 0;
+}
+
+int reset_device(wlan_private *priv)
+{
+       int ret;
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset,
+                                   cmd_act_halt, 0, 0, NULL);
+       msleep_interruptible(10);
+
+       return ret;
+}
+
+int libertas_sbi_unregister_dev(wlan_private * priv)
+{
+       int ret = 0;
+
+       /* Need to send a Reset command to device before USB resources freed
+        * and wlan_remove_card() called, then device can handle FW download
+        * again.
+        */
+       if (priv)
+               reset_device(priv);
+
+       return ret;
+}
+
+
+/**
+ *  @brief  This function register usb device and initialize parameter
+ *  @param             priv pointer to wlan_private
+ *  @return            0 or -1
+ */
+int libertas_sbi_register_dev(wlan_private * priv)
+{
+
+       struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+       ENTER();
+
+       cardp->priv = priv;
+       cardp->eth_dev = priv->wlan_dev.netdev;
+       priv->hotplug_device = &(cardp->udev->dev);
+
+       SET_NETDEV_DEV(cardp->eth_dev, &(cardp->udev->dev));
+
+       lbs_dev_dbg(1, &cardp->udev->dev, "udev pointer is at %p\n",
+                   cardp->udev);
+
+       LEAVE();
+       return 0;
+}
+
+
+
+int libertas_sbi_prog_firmware(wlan_private * priv)
+{
+       struct usb_card_rec *cardp = priv->wlan_dev.card;
+       int i = 0;
+       static int reset_count = 10;
+
+       ENTER();
+
+       cardp->rinfo.priv = priv;
+
+restart:
+       if (if_usb_submit_rx_urb_fwload(priv) < 0) {
+               lbs_dev_dbg(1, &cardp->udev->dev, "URB submission is failed\n");
+               LEAVE();
+               return -1;
+       }
+
+#ifdef SUPPORT_BOOT_COMMAND
+       cardp->bootcmdresp = 0;
+       do {
+               int j = 0;
+               i++;
+               /* Issue Boot command = 1, Boot from Download-FW */
+               if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
+               /* wait for command response */
+               do {
+                       j++;
+                       msleep_interruptible(100);
+               } while (cardp->bootcmdresp == 0 && j < 10);
+       } while (cardp->bootcmdresp == 0 && i < 5);
+
+       if (cardp->bootcmdresp == 0) {
+               if (--reset_count >= 0) {
+                       libertas_do_reset(priv);
+                       goto restart;
+               }
+               return -1;
+       }
+#endif
+
+       i = 0;
+       priv->adapter->fw_ready = 0;
+
+       cardp->totalbytes = 0;
+       cardp->fwlastblksent = 0;
+       cardp->CRC_OK = 1;
+       cardp->fwdnldover = 0;
+       cardp->fwseqnum = -1;
+       cardp->totalbytes = 0;
+       cardp->fwfinalblk = 0;
+
+       if_prog_firmware(priv);
+
+       do {
+               lbs_dev_dbg(1, &cardp->udev->dev,"Wlan sched timeout\n");
+               i++;
+               msleep_interruptible(100);
+               if (priv->adapter->surpriseremoved || i >= 20)
+                       break;
+       } while (!cardp->fwdnldover);
+
+       if (!cardp->fwdnldover) {
+               lbs_pr_info("failed to load fw, resetting device!\n");
+               if (--reset_count >= 0) {
+                       libertas_do_reset(priv);
+                       goto restart;
+               }
+
+               lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
+               LEAVE();
+               return -1;
+       }
+
+       if_usb_submit_rx_urb(priv);
+
+       /* Delay 200 ms to waiting for the FW ready */
+       msleep_interruptible(200);
+
+       priv->adapter->fw_ready = 1;
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief Given a usb_card_rec return its wlan_private
+ *  @param card                pointer to a usb_card_rec
+ *  @return            pointer to wlan_private
+ */
+wlan_private *libertas_sbi_get_priv(void *card)
+{
+       struct usb_card_rec *cardp = card;
+       return cardp->priv;
+}
+
+#ifdef ENABLE_PM
+int libertas_sbi_suspend(wlan_private * priv)
+{
+       return 0;
+}
+
+int libertas_sbi_resume(wlan_private * priv)
+{
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct usb_card_rec *cardp = usb_get_intfdata(intf);
+       wlan_private *priv = cardp->priv;
+
+       ENTER();
+
+       if (priv->adapter->psstate != PS_STATE_FULL_POWER)
+               return -1;
+
+       netif_device_detach(cardp->eth_dev);
+
+       /* Unlink tx & rx urb */
+       usb_kill_urb(cardp->tx_urb);
+       usb_kill_urb(cardp->rx_urb);
+
+       cardp->rx_urb_recall = 1;
+
+       LEAVE();
+       return 0;
+}
+
+static int if_usb_resume(struct usb_interface *intf)
+{
+       struct usb_card_rec *cardp = usb_get_intfdata(intf);
+
+       ENTER();
+
+       cardp->rx_urb_recall = 0;
+
+       if_usb_submit_rx_urb(cardp->priv);
+
+       netif_device_attach(cardp->eth_dev);
+
+       LEAVE();
+       return 0;
+}
+#else
+#define if_usb_suspend NULL
+#define if_usb_resume NULL
+#endif
+
+static struct usb_driver if_usb_driver = {
+       /* driver name */
+       .name = usbdriver_name,
+       /* probe function name */
+       .probe = if_usb_probe,
+       /* disconnect function  name */
+       .disconnect = if_usb_disconnect,
+       /* device signature table */
+       .id_table = if_usb_table,
+       .suspend = if_usb_suspend,
+       .resume = if_usb_resume,
+};
+
+/**
+ *  @brief This function registers driver.
+ *  @param add         pointer to add_card callback function
+ *  @param remove      pointer to remove card callback function
+ *  @param arg         pointer to call back function parameter
+ *  @return            dummy success variable
+ */
+int libertas_sbi_register(void)
+{
+       /*
+        * API registers the Marvell USB driver
+        * to the USB system
+        */
+       usb_register(&if_usb_driver);
+
+       /* Return success to wlan layer */
+       return 0;
+}
+
+/**
+ *  @brief This function removes usb driver.
+ *  @return            N/A
+ */
+void libertas_sbi_unregister(void)
+{
+       /* API unregisters the driver from USB subsystem */
+       usb_deregister(&if_usb_driver);
+       return;
+}
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
new file mode 100644 (file)
index 0000000..7851167
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+  * This file contains definition for USB interface.
+  */
+#define CMD_TYPE_REQUEST                0xF00DFACE
+#define CMD_TYPE_DATA                   0xBEADC0DE
+#define CMD_TYPE_INDICATION             0xBEEFFACE
+
+#define IPFIELD_ALIGN_OFFSET   2
+
+#define USB8388_VID_1  0x1286
+#define USB8388_PID_1  0x2001
+#define USB8388_VID_2  0x05a3
+#define USB8388_PID_2  0x8388
+
+#ifdef SUPPORT_BOOT_COMMAND
+#define BOOT_CMD_FW_BY_USB     0x01
+#define BOOT_CMD_FW_IN_EEPROM  0x02
+#define BOOT_CMD_UPDATE_BOOT2  0x03
+#define BOOT_CMD_UPDATE_FW     0x04
+#define BOOT_CMD_MAGIC_NUMBER  0x4C56524D   /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */
+
+struct bootcmdstr
+{
+       u32 u32magicnumber;
+       u8  u8cmd_tag;
+       u8  au8dumy[11];
+};
+
+#define BOOT_CMD_RESP_OK     0x0001
+#define BOOT_CMD_RESP_FAIL   0x0000
+
+struct bootcmdrespStr
+{
+       u32 u32magicnumber;
+       u8  u8cmd_tag;
+       u8  u8result;
+       u8  au8dumy[2];
+};
+#endif /* SUPPORT_BOOT_COMMAND */
+
+/* read callback private data */
+struct read_cb_info {
+        wlan_private *priv;
+        struct sk_buff *skb;
+};
+
+/** USB card description structure*/
+struct usb_card_rec {
+       struct net_device *eth_dev;
+       struct usb_device *udev;
+       struct urb *rx_urb, *tx_urb;
+       void *priv;
+       struct read_cb_info rinfo;
+
+       int bulk_in_size;
+       u8 bulk_in_endpointAddr;
+
+       u8 *bulk_out_buffer;
+       int bulk_out_size;
+       u8 bulk_out_endpointAddr;
+
+       u8 CRC_OK;
+       u32 fwseqnum;
+       u32 lastseqnum;
+       u32 totalbytes;
+       u32 fwlastblksent;
+       u8 fwdnldover;
+       u8 fwfinalblk;
+
+       u32 usb_event_cause;
+       u8 usb_int_cause;
+
+       u8 rx_urb_recall;
+
+       u8 bootcmdresp;
+};
+
+/** fwheader */
+struct fwheader {
+       u32 dnldcmd;
+       u32 baseaddr;
+       u32 datalength;
+       u32 CRC;
+};
+
+#define FW_MAX_DATA_BLK_SIZE   600
+/** FWData */
+struct FWData {
+       struct fwheader fwheader;
+       u32 seqnum;
+       u8 data[FW_MAX_DATA_BLK_SIZE];
+};
+
+/** fwsyncheader */
+struct fwsyncheader {
+       u32 cmd;
+       u32 seqnum;
+};
+
+#define FW_HAS_DATA_TO_RECV            0x00000001
+#define FW_HAS_LAST_BLOCK              0x00000004
+
+#define FW_DATA_XMIT_SIZE \
+       sizeof(struct fwheader) + fwdata->fwheader.datalength + sizeof(u32)
+
+int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
+void if_usb_free(struct usb_card_rec *cardp);
+int if_usb_issue_boot_command(wlan_private *priv, int ivalue);
+
diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c
new file mode 100644 (file)
index 0000000..82b3964
--- /dev/null
@@ -0,0 +1,2500 @@
+/**
+  * This file contains ioctl functions
+  */
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+#define MAX_SCAN_CELL_SIZE      (IW_EV_ADDR_LEN + \
+                               IW_ESSID_MAX_SIZE + \
+                               IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
+                               IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
+                               IW_EV_PARAM_LEN + 40)   /* 40 for WPAIE */
+
+#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
+
+static int setrxantenna(wlan_private * priv, int mode)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+
+       if (mode != RF_ANTENNA_1 && mode != RF_ANTENNA_2
+           && mode != RF_ANTENNA_AUTO) {
+               return -EINVAL;
+       }
+
+       adapter->rxantennamode = mode;
+
+       lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode);
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+                                   cmd_act_set_rx,
+                                   cmd_option_waitforrsp, 0,
+                                   &adapter->rxantennamode);
+       return ret;
+}
+
+static int settxantenna(wlan_private * priv, int mode)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+
+       if ((mode != RF_ANTENNA_1) && (mode != RF_ANTENNA_2)
+           && (mode != RF_ANTENNA_AUTO)) {
+               return -EINVAL;
+       }
+
+       adapter->txantennamode = mode;
+
+       lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode);
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+                                   cmd_act_set_tx,
+                                   cmd_option_waitforrsp, 0,
+                                   &adapter->txantennamode);
+
+       return ret;
+}
+
+static int getrxantenna(wlan_private * priv, char *buf)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+
+       // clear it, so we will know if the value
+       // returned below is correct or not.
+       adapter->rxantennamode = 0;
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+                                   cmd_act_get_rx,
+                                   cmd_option_waitforrsp, 0, NULL);
+
+       if (ret) {
+               LEAVE();
+               return ret;
+       }
+
+       lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode);
+
+       return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1;
+}
+
+static int gettxantenna(wlan_private * priv, char *buf)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+
+       // clear it, so we will know if the value
+       // returned below is correct or not.
+       adapter->txantennamode = 0;
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+                                   cmd_act_get_tx,
+                                   cmd_option_waitforrsp, 0, NULL);
+
+       if (ret) {
+               LEAVE();
+               return ret;
+       }
+
+       lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode);
+
+       return sprintf(buf, "0x%04x", adapter->txantennamode) + 1;
+}
+
+static int wlan_set_region(wlan_private * priv, u16 region_code)
+{
+       int i;
+
+       for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+               // use the region code to search for the index
+               if (region_code == libertas_region_code_to_index[i]) {
+                       priv->adapter->regiontableindex = (u16) i;
+                       priv->adapter->regioncode = region_code;
+                       break;
+               }
+       }
+
+       // if it's unidentified region code
+       if (i >= MRVDRV_MAX_REGION_CODE) {
+               lbs_pr_debug(1, "region Code not identified\n");
+               LEAVE();
+               return -1;
+       }
+
+       if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) {
+               LEAVE();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ *  @brief Get/Set Firmware wakeup method
+ *
+ *  @param priv                A pointer to wlan_private structure
+ *  @param wrq         A pointer to user data
+ *  @return            0--success, otherwise fail
+ */
+static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int data;
+       ENTER();
+
+       if ((int)wrq->u.data.length == 0) {
+               if (copy_to_user
+                   (wrq->u.data.pointer, &adapter->pkttxctrl, sizeof(u32))) {
+                       lbs_pr_alert("copy_to_user failed!\n");
+                       return -EFAULT;
+               }
+       } else {
+               if ((int)wrq->u.data.length > 1) {
+                       lbs_pr_alert("ioctl too many args!\n");
+                       return -EFAULT;
+               }
+               if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+                       lbs_pr_alert("Copy from user failed\n");
+                       return -EFAULT;
+               }
+
+               adapter->pkttxctrl = (u32) data;
+       }
+
+       wrq->u.data.length = 1;
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief Get/Set NULL Package generation interval
+ *
+ *  @param priv                A pointer to wlan_private structure
+ *  @param wrq         A pointer to user data
+ *  @return            0--success, otherwise fail
+ */
+static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int data;
+       ENTER();
+
+       if ((int)wrq->u.data.length == 0) {
+               data = adapter->nullpktinterval;
+
+               if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+                       lbs_pr_alert( "copy_to_user failed!\n");
+                       return -EFAULT;
+               }
+       } else {
+               if ((int)wrq->u.data.length > 1) {
+                       lbs_pr_alert( "ioctl too many args!\n");
+                       return -EFAULT;
+               }
+               if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+                       lbs_pr_debug(1, "Copy from user failed\n");
+                       return -EFAULT;
+               }
+
+               adapter->nullpktinterval = data;
+       }
+
+       wrq->u.data.length = 1;
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int data[2];
+       ENTER();
+       data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+       data[1] = adapter->rxpd_rate;
+       if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+               lbs_pr_debug(1, "Copy to user failed\n");
+               return -EFAULT;
+       }
+       wrq->u.data.length = 2;
+       LEAVE();
+       return 0;
+}
+
+static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+       int data[4];
+
+       ENTER();
+       memset(data, 0, sizeof(data));
+       if (wrq->u.data.length) {
+               if (copy_from_user(data, wrq->u.data.pointer,
+                    min_t(size_t, wrq->u.data.length, 4) * sizeof(int)))
+                       return -EFAULT;
+       }
+       if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) {
+               if (adapter->connect_status == libertas_connected) {
+                       ret = libertas_prepare_and_send_command(priv,
+                                                   cmd_802_11_rssi,
+                                                   0,
+                                                   cmd_option_waitforrsp,
+                                                   0, NULL);
+
+                       if (ret) {
+                               LEAVE();
+                               return ret;
+                       }
+               }
+       }
+
+       if (wrq->u.data.length == 0) {
+               data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+               data[1] = adapter->SNR[TYPE_BEACON][TYPE_AVG];
+               data[2] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+               data[3] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+               if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4))
+                       return -EFAULT;
+               wrq->u.data.length = 4;
+       } else if (data[0] == 0) {
+               data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+               if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+                       return -EFAULT;
+               wrq->u.data.length = 1;
+       } else if (data[0] == 1) {
+               data[0] = adapter->SNR[TYPE_BEACON][TYPE_AVG];
+               if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+                       return -EFAULT;
+               wrq->u.data.length = 1;
+       } else if (data[0] == 2) {
+               data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+               if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+                       return -EFAULT;
+               wrq->u.data.length = 1;
+       } else if (data[0] == 3) {
+               data[0] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+               if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+                       return -EFAULT;
+               wrq->u.data.length = 1;
+       } else
+               return -ENOTSUPP;
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq)
+{
+       int data;
+       wlan_adapter *adapter = priv->adapter;
+
+       if (wrq->u.data.length > 0) {
+               if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int)))
+                       return -EFAULT;
+
+               lbs_pr_debug(1, "WLAN SET BEACON INTERVAL: %d\n", data);
+               if ((data > MRVDRV_MAX_BEACON_INTERVAL)
+                   || (data < MRVDRV_MIN_BEACON_INTERVAL))
+                       return -ENOTSUPP;
+               adapter->beaconperiod = data;
+       }
+       data = adapter->beaconperiod;
+       if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int)))
+               return -EFAULT;
+
+       wrq->u.data.length = 1;
+
+       return 0;
+}
+
+static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+       int temp;
+       int data = 0;
+       int *val;
+
+       ENTER();
+       data = SUBCMD_DATA(wrq);
+       if ((data == 0) || (data == 1)) {
+               ret = libertas_prepare_and_send_command(priv,
+                                           cmd_802_11_rssi,
+                                           0, cmd_option_waitforrsp,
+                                           0, NULL);
+               if (ret) {
+                       LEAVE();
+                       return ret;
+               }
+       }
+
+       switch (data) {
+       case 0:
+
+               temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+                               adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+               break;
+       case 1:
+               temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG],
+                               adapter->NF[TYPE_BEACON][TYPE_AVG]);
+               break;
+       case 2:
+               temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+                               adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+               break;
+       case 3:
+               temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+                               adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+       val = (int *)wrq->u.name;
+       *val = temp;
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+       int temp;
+       int data = 0;
+       int *val;
+
+       data = SUBCMD_DATA(wrq);
+       if ((data == 0) || (data == 1)) {
+               ret = libertas_prepare_and_send_command(priv,
+                                           cmd_802_11_rssi,
+                                           0, cmd_option_waitforrsp,
+                                           0, NULL);
+
+               if (ret) {
+                       LEAVE();
+                       return ret;
+               }
+       }
+
+       switch (data) {
+       case 0:
+               temp = adapter->NF[TYPE_BEACON][TYPE_NOAVG];
+               break;
+       case 1:
+               temp = adapter->NF[TYPE_BEACON][TYPE_AVG];
+               break;
+       case 2:
+               temp = adapter->NF[TYPE_RXPD][TYPE_NOAVG];
+               break;
+       case 3:
+               temp = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       temp = CAL_NF(temp);
+
+       lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp);
+       val = (int *)wrq->u.name;
+       *val = temp;
+       return 0;
+}
+
+static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int *pdata;
+       struct iwreq *wrq = (struct iwreq *)req;
+       int ret = 0;
+       adapter->txrate = 0;
+       lbs_pr_debug(1, "wlan_get_txrate_ioctl\n");
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query,
+                                   cmd_act_get, cmd_option_waitforrsp,
+                                   0, NULL);
+       if (ret)
+               return ret;
+
+       pdata = (int *)wrq->u.name;
+       *pdata = (int)adapter->txrate;
+       return 0;
+}
+
+static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+       char status[64];
+       wlan_adapter *adapter = priv->adapter;
+
+       memset(status, 0, sizeof(status));
+
+       switch (adapter->inframode) {
+       case wlan802_11ibss:
+               if (adapter->connect_status == libertas_connected) {
+                       if (adapter->adhoccreate)
+                               memcpy(&status, "AdhocStarted", sizeof(status));
+                       else
+                               memcpy(&status, "AdhocJoined", sizeof(status));
+               } else {
+                       memcpy(&status, "AdhocIdle", sizeof(status));
+               }
+               break;
+       case wlan802_11infrastructure:
+               memcpy(&status, "Inframode", sizeof(status));
+               break;
+       default:
+               memcpy(&status, "AutoUnknownmode", sizeof(status));
+               break;
+       }
+
+       lbs_pr_debug(1, "status = %s\n", status);
+       wrq->u.data.length = strlen(status) + 1;
+
+       if (wrq->u.data.pointer) {
+               if (copy_to_user(wrq->u.data.pointer,
+                                &status, wrq->u.data.length))
+                       return -EFAULT;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief Set/Get WPA IE
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req                 A pointer to ifreq structure
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       ENTER();
+
+       if (wrq->u.data.length) {
+               if (wrq->u.data.length > sizeof(adapter->wpa_ie)) {
+                       lbs_pr_debug(1, "failed to copy WPA IE, too big \n");
+                       return -EFAULT;
+               }
+               if (copy_from_user(adapter->wpa_ie, wrq->u.data.pointer,
+                                  wrq->u.data.length)) {
+                       lbs_pr_debug(1, "failed to copy WPA IE \n");
+                       return -EFAULT;
+               }
+               adapter->wpa_ie_len = wrq->u.data.length;
+               lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len,
+                      adapter->wpa_ie[0]);
+               lbs_dbg_hex("wpa_ie", adapter->wpa_ie, adapter->wpa_ie_len);
+               if (adapter->wpa_ie[0] == WPA_IE)
+                       adapter->secinfo.WPAenabled = 1;
+               else if (adapter->wpa_ie[0] == WPA2_IE)
+                       adapter->secinfo.WPA2enabled = 1;
+               else {
+                       adapter->secinfo.WPAenabled = 0;
+                       adapter->secinfo.WPA2enabled = 0;
+               }
+       } else {
+               memset(adapter->wpa_ie, 0, sizeof(adapter->wpa_ie));
+               adapter->wpa_ie_len = wrq->u.data.length;
+               lbs_pr_debug(1, "Reset wpa_ie_len=%d IE=%#x\n",
+                      adapter->wpa_ie_len, adapter->wpa_ie[0]);
+               adapter->secinfo.WPAenabled = 0;
+               adapter->secinfo.WPA2enabled = 0;
+       }
+
+       // enable/disable RSN in firmware if WPA is enabled/disabled
+       // depending on variable adapter->secinfo.WPAenabled is set or not
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn,
+                                   cmd_act_set, cmd_option_waitforrsp,
+                                   0, NULL);
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Set Auto prescan
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq                 A pointer to iwreq structure
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+       int data;
+       wlan_adapter *adapter = priv->adapter;
+       int *val;
+
+       data = SUBCMD_DATA(wrq);
+       lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data);
+       adapter->prescan = data;
+
+       val = (int *)wrq->u.name;
+       *val = data;
+       return 0;
+}
+
+static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       u32 mdtim;
+       int idata;
+       int ret = -EINVAL;
+
+       ENTER();
+
+       idata = SUBCMD_DATA(wrq);
+       mdtim = (u32) idata;
+       if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM)
+            && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM))
+           || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) {
+               priv->adapter->multipledtim = mdtim;
+               ret = 0;
+       }
+       if (ret)
+               lbs_pr_debug(1, "Invalid parameter, multipledtim not changed.\n");
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Set authentication mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req                 A pointer to ifreq structure
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       int alg;
+       struct iwreq *wrq = (struct iwreq *)req;
+       wlan_adapter *adapter = priv->adapter;
+
+       if (wrq->u.data.flags == 0) {
+               //from iwpriv subcmd
+               alg = SUBCMD_DATA(wrq);
+       } else {
+               //from wpa_supplicant subcmd
+               if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) {
+                       lbs_pr_debug(1, "Copy from user failed\n");
+                       return -EFAULT;
+               }
+       }
+
+       lbs_pr_debug(1, "auth alg is %#x\n", alg);
+
+       switch (alg) {
+       case AUTH_ALG_SHARED_KEY:
+               adapter->secinfo.authmode = wlan802_11authmodeshared;
+               break;
+       case AUTH_ALG_NETWORK_EAP:
+               adapter->secinfo.authmode =
+                   wlan802_11authmodenetworkEAP;
+               break;
+       case AUTH_ALG_OPEN_SYSTEM:
+       default:
+               adapter->secinfo.authmode = wlan802_11authmodeopen;
+               break;
+       }
+       return 0;
+}
+
+/**
+ *  @brief Set 802.1x authentication mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req                 A pointer to ifreq structure
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       int alg;
+       struct iwreq *wrq = (struct iwreq *)req;
+
+       if (wrq->u.data.flags == 0) {
+               //from iwpriv subcmd
+               alg = SUBCMD_DATA(wrq);
+       } else {
+               //from wpa_supplicant subcmd
+               if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) {
+                       lbs_pr_debug(1, "Copy from user failed\n");
+                       return -EFAULT;
+               }
+       }
+       lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg);
+       priv->adapter->secinfo.auth1xalg = alg;
+       return 0;
+}
+
+static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       int mode;
+       struct iwreq *wrq = (struct iwreq *)req;
+
+       ENTER();
+
+       if (wrq->u.data.flags == 0) {
+               //from iwpriv subcmd
+               mode = SUBCMD_DATA(wrq);
+       } else {
+               //from wpa_supplicant subcmd
+               if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) {
+                       lbs_pr_debug(1, "Copy from user failed\n");
+                       return -EFAULT;
+               }
+       }
+       lbs_pr_debug(1, "encryption mode is %#x\n", mode);
+       priv->adapter->secinfo.Encryptionmode = mode;
+
+       LEAVE();
+       return 0;
+}
+
+static void adjust_mtu(wlan_private * priv)
+{
+       int mtu_increment = 0;
+
+       if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+               mtu_increment += sizeof(struct ieee80211_hdr_4addr);
+
+       if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP)
+               mtu_increment += max(sizeof(struct tx_radiotap_hdr),
+                                    sizeof(struct rx_radiotap_hdr));
+       priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN
+           - sizeof(struct ethhdr)
+           + mtu_increment;
+}
+
+/**
+ *  @brief Set Link-Layer Layer mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req                 A pointer to ifreq structure
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       int mode;
+
+       mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data;
+
+       switch (mode) {
+       case WLAN_LINKMODE_802_3:
+               priv->adapter->linkmode = mode;
+               break;
+       case WLAN_LINKMODE_802_11:
+               priv->adapter->linkmode = mode;
+               break;
+       default:
+               lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n",
+                      mode);
+               return -EINVAL;
+               break;
+       }
+       lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode);
+
+       adjust_mtu(priv);
+
+       return 0;
+}
+
+/**
+ *  @brief Set Radio header mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req                 A pointer to ifreq structure
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       int mode;
+
+       mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data;
+
+       switch (mode) {
+       case WLAN_RADIOMODE_NONE:
+               priv->adapter->radiomode = mode;
+               break;
+       case WLAN_RADIOMODE_RADIOTAP:
+               priv->adapter->radiomode = mode;
+               break;
+       default:
+               lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n",
+                      mode);
+               return -EINVAL;
+       }
+       lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode);
+
+       adjust_mtu(priv);
+       return 0;
+}
+
+/**
+ *  @brief Set Debug header mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req                 A pointer to ifreq structure
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       priv->adapter->debugmode = (int)((struct ifreq *)
+                                        ((u8 *) req + 4))->ifr_data;
+       return 0;
+}
+
+static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv,
+                                         struct ifreq *req)
+{
+       int len;
+       char buf[8];
+       struct iwreq *wrq = (struct iwreq *)req;
+
+       lbs_pr_debug(1, "WLAN_SUBCMD_GETRXANTENNA\n");
+       len = getrxantenna(priv, buf);
+
+       wrq->u.data.length = len;
+       if (wrq->u.data.pointer) {
+               if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+                       lbs_pr_debug(1, "CopyToUser failed\n");
+                       return -EFAULT;
+               }
+       }
+
+       return 0;
+}
+
+static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv,
+                                         struct ifreq *req)
+{
+       int len;
+       char buf[8];
+       struct iwreq *wrq = (struct iwreq *)req;
+
+       lbs_pr_debug(1, "WLAN_SUBCMD_GETTXANTENNA\n");
+       len = gettxantenna(priv, buf);
+
+       wrq->u.data.length = len;
+       if (wrq->u.data.pointer) {
+               if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+                       lbs_pr_debug(1, "CopyToUser failed\n");
+                       return -EFAULT;
+               }
+       }
+       return 0;
+}
+
+/**
+ *  @brief Get the MAC TSF value from the firmware
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure containing buffer
+ *                      space to store a TSF value retrieved from the firmware
+ *
+ *  @return             0 if successful; IOCTL error code otherwise
+ */
+static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+       u64 tsfval;
+       int ret;
+
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_get_tsf,
+                                   0, cmd_option_waitforrsp, 0, &tsfval);
+
+       lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval);
+
+       if (ret != 0) {
+               lbs_pr_debug(1, "IOCTL: Get TSF; command exec failed\n");
+               ret = -EFAULT;
+       } else {
+               if (copy_to_user(wrq->u.data.pointer,
+                                &tsfval,
+                                min_t(size_t, wrq->u.data.length,
+                                    sizeof(tsfval))) != 0) {
+
+                       lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n");
+                       ret = -EFAULT;
+               } else {
+                       ret = 0;
+               }
+       }
+       return ret;
+}
+
+/**
+ *  @brief Get/Set adapt rate
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq                 A pointer to iwreq structure
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq)
+{
+       int ret;
+       wlan_adapter *adapter = priv->adapter;
+       int data[2];
+
+       memset(data, 0, sizeof(data));
+       if (!wrq->u.data.length) {
+               lbs_pr_debug(1, "Get ADAPT RATE SET\n");
+               ret = libertas_prepare_and_send_command(priv,
+                                           cmd_802_11_rate_adapt_rateset,
+                                           cmd_act_get,
+                                           cmd_option_waitforrsp, 0, NULL);
+               data[0] = adapter->enablehwauto;
+               data[1] = adapter->ratebitmap;
+               if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+                       lbs_pr_debug(1, "Copy to user failed\n");
+                       return -EFAULT;
+               }
+#define GET_TWO_INT    2
+               wrq->u.data.length = GET_TWO_INT;
+       } else {
+               lbs_pr_debug(1, "Set ADAPT RATE SET\n");
+               if (wrq->u.data.length > 2)
+                       return -EINVAL;
+               if (copy_from_user
+                   (data, wrq->u.data.pointer,
+                    sizeof(int) * wrq->u.data.length)) {
+                       lbs_pr_debug(1, "Copy from user failed\n");
+                       return -EFAULT;
+               }
+
+               adapter->enablehwauto = data[0];
+               adapter->ratebitmap = data[1];
+               ret = libertas_prepare_and_send_command(priv,
+                                           cmd_802_11_rate_adapt_rateset,
+                                           cmd_act_set,
+                                           cmd_option_waitforrsp, 0, NULL);
+       }
+       return ret;
+}
+
+/**
+ *  @brief Get/Set inactivity timeout
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq                 A pointer to iwreq structure
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq)
+{
+       int ret;
+       int data = 0;
+       u16 timeout = 0;
+
+       ENTER();
+       if (wrq->u.data.length > 1)
+               return -ENOTSUPP;
+
+       if (wrq->u.data.length == 0) {
+               /* Get */
+               ret = libertas_prepare_and_send_command(priv,
+                                           cmd_802_11_inactivity_timeout,
+                                           cmd_act_get,
+                                           cmd_option_waitforrsp, 0,
+                                           &timeout);
+               data = timeout;
+               if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+                       lbs_pr_debug(1, "Copy to user failed\n");
+                       return -EFAULT;
+               }
+       } else {
+               /* Set */
+               if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+                       lbs_pr_debug(1, "Copy from user failed\n");
+                       return -EFAULT;
+               }
+
+               timeout = data;
+               ret = libertas_prepare_and_send_command(priv,
+                                           cmd_802_11_inactivity_timeout,
+                                           cmd_act_set,
+                                           cmd_option_waitforrsp, 0,
+                                           &timeout);
+       }
+
+       wrq->u.data.length = 1;
+
+       LEAVE();
+       return ret;
+}
+
+static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+       int ret;
+       char buf[GETLOG_BUFSIZE - 1];
+       wlan_adapter *adapter = priv->adapter;
+
+       lbs_pr_debug(1, " GET STATS\n");
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log,
+                                   0, cmd_option_waitforrsp, 0, NULL);
+
+       if (ret) {
+               return ret;
+       }
+
+       if (wrq->u.data.pointer) {
+               sprintf(buf, "\n  mcasttxframe %u failed %u retry %u "
+                       "multiretry %u framedup %u "
+                       "rtssuccess %u rtsfailure %u ackfailure %u\n"
+                       "rxfrag %u mcastrxframe %u fcserror %u "
+                       "txframe %u wepundecryptable %u ",
+                       adapter->logmsg.mcasttxframe,
+                       adapter->logmsg.failed,
+                       adapter->logmsg.retry,
+                       adapter->logmsg.multiretry,
+                       adapter->logmsg.framedup,
+                       adapter->logmsg.rtssuccess,
+                       adapter->logmsg.rtsfailure,
+                       adapter->logmsg.ackfailure,
+                       adapter->logmsg.rxfrag,
+                       adapter->logmsg.mcastrxframe,
+                       adapter->logmsg.fcserror,
+                       adapter->logmsg.txframe,
+                       adapter->logmsg.wepundecryptable);
+               wrq->u.data.length = strlen(buf) + 1;
+               if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+                       lbs_pr_debug(1, "Copy to user failed\n");
+                       return -EFAULT;
+               }
+       }
+
+       return 0;
+}
+
+static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+       u8 buf[12];
+       u8 *option[] = { "active", "passive", "get", };
+       int i, max_options = (sizeof(option) / sizeof(option[0]));
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+
+       if (priv->adapter->enable11d) {
+               lbs_pr_debug(1, "11D: Cannot set scantype when 11D enabled\n");
+               return -EFAULT;
+       }
+
+       memset(buf, 0, sizeof(buf));
+
+       if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf),
+                                                        wrq->u.data.length)))
+               return -EFAULT;
+
+       lbs_pr_debug(1, "Scan type Option = %s\n", buf);
+
+       buf[sizeof(buf) - 1] = '\0';
+
+       for (i = 0; i < max_options; i++) {
+               if (!strcmp(buf, option[i]))
+                       break;
+       }
+
+       switch (i) {
+       case 0:
+               adapter->scantype = cmd_scan_type_active;
+               break;
+       case 1:
+               adapter->scantype = cmd_scan_type_passive;
+               break;
+       case 2:
+               wrq->u.data.length = strlen(option[adapter->scantype]) + 1;
+
+               if (copy_to_user(wrq->u.data.pointer,
+                                option[adapter->scantype],
+                                wrq->u.data.length)) {
+                       lbs_pr_debug(1, "Copy to user failed\n");
+                       ret = -EFAULT;
+               }
+
+               break;
+       default:
+               lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+       wlan_adapter *adapter = priv->adapter;
+       u8 buf[12];
+       u8 *option[] = { "bss", "ibss", "any", "get" };
+       int i, max_options = (sizeof(option) / sizeof(option[0]));
+       int ret = 0;
+
+       ENTER();
+
+       memset(buf, 0, sizeof(buf));
+
+       if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf),
+                                                        wrq->u.data.length))) {
+               lbs_pr_debug(1, "Copy from user failed\n");
+               return -EFAULT;
+       }
+
+       lbs_pr_debug(1, "Scan mode Option = %s\n", buf);
+
+       buf[sizeof(buf) - 1] = '\0';
+
+       for (i = 0; i < max_options; i++) {
+               if (!strcmp(buf, option[i]))
+                       break;
+       }
+
+       switch (i) {
+
+       case 0:
+               adapter->scanmode = cmd_bss_type_bss;
+               break;
+       case 1:
+               adapter->scanmode = cmd_bss_type_ibss;
+               break;
+       case 2:
+               adapter->scanmode = cmd_bss_type_any;
+               break;
+       case 3:
+
+               wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1;
+
+               lbs_pr_debug(1, "Get Scan mode Option = %s\n",
+                      option[adapter->scanmode - 1]);
+
+               lbs_pr_debug(1, "Scan mode length %d\n", wrq->u.data.length);
+
+               if (copy_to_user(wrq->u.data.pointer,
+                                option[adapter->scanmode - 1],
+                                wrq->u.data.length)) {
+                       lbs_pr_debug(1, "Copy to user failed\n");
+                       ret = -EFAULT;
+               }
+               lbs_pr_debug(1, "GET Scan type Option after copy = %s\n",
+                      (char *)wrq->u.data.pointer);
+
+               break;
+
+       default:
+               lbs_pr_debug(1, "Invalid Scan mode Ioctl Option\n");
+               ret = -EINVAL;
+               break;
+       }
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Get/Set Adhoc G Rate
+ *
+ *  @param priv                A pointer to wlan_private structure
+ *  @param wrq         A pointer to user data
+ *  @return            0--success, otherwise fail
+ */
+static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int data, data1;
+       int *val;
+
+       ENTER();
+
+       data1 = SUBCMD_DATA(wrq);
+       switch (data1) {
+       case 0:
+               adapter->adhoc_grate_enabled = 0;
+               break;
+       case 1:
+               adapter->adhoc_grate_enabled = 1;
+               break;
+       case 2:
+               break;
+       default:
+               return -EINVAL;
+       }
+       data = adapter->adhoc_grate_enabled;
+       val = (int *)wrq->u.name;
+       *val = data;
+       LEAVE();
+       return 0;
+}
+
+static inline int hex2int(char c)
+{
+       if (c >= '0' && c <= '9')
+               return (c - '0');
+       if (c >= 'a' && c <= 'f')
+               return (c - 'a' + 10);
+       if (c >= 'A' && c <= 'F')
+               return (c - 'A' + 10);
+       return -1;
+}
+
+/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx")
+   into binary format (6 bytes).
+
+   This function expects that each byte is represented with 2 characters
+   (e.g., 11:2:11:11:11:11 is invalid)
+
+ */
+static char *eth_str2addr(char *ethstr, u8 * addr)
+{
+       int i, val, val2;
+       char *pos = ethstr;
+
+       /* get rid of initial blanks */
+       while (*pos == ' ' || *pos == '\t')
+               ++pos;
+
+       for (i = 0; i < 6; i++) {
+               val = hex2int(*pos++);
+               if (val < 0)
+                       return NULL;
+               val2 = hex2int(*pos++);
+               if (val2 < 0)
+                       return NULL;
+               addr[i] = (val * 16 + val2) & 0xff;
+
+               if (i < 5 && *pos++ != ':')
+                       return NULL;
+       }
+       return pos;
+}
+
+/* this writes xx:xx:xx:xx:xx:xx into ethstr
+   (ethstr must have space for 18 chars) */
+static int eth_addr2str(u8 * addr, char *ethstr)
+{
+       int i;
+       char *pos = ethstr;
+
+       for (i = 0; i < 6; i++) {
+               sprintf(pos, "%02x", addr[i] & 0xff);
+               pos += 2;
+               if (i < 5)
+                       *pos++ = ':';
+       }
+       return 17;
+}
+
+/**
+ *  @brief          Add an entry to the BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char ethaddrs_str[18];
+       char *pos;
+       u8 ethaddr[ETH_ALEN];
+
+       ENTER();
+       if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
+                          sizeof(ethaddrs_str)))
+               return -EFAULT;
+
+       if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
+               lbs_pr_info("BT_ADD: Invalid MAC address\n");
+               return -EINVAL;
+       }
+
+       lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str);
+       LEAVE();
+       return (libertas_prepare_and_send_command(priv, cmd_bt_access,
+                                     cmd_act_bt_access_add,
+                                     cmd_option_waitforrsp, 0, ethaddr));
+}
+
+/**
+ *  @brief          Delete an entry from the BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char ethaddrs_str[18];
+       u8 ethaddr[ETH_ALEN];
+       char *pos;
+
+       ENTER();
+       if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
+                          sizeof(ethaddrs_str)))
+               return -EFAULT;
+
+       if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
+               lbs_pr_info("Invalid MAC address\n");
+               return -EINVAL;
+       }
+
+       lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str);
+
+       return (libertas_prepare_and_send_command(priv,
+                                     cmd_bt_access,
+                                     cmd_act_bt_access_del,
+                                     cmd_option_waitforrsp, 0, ethaddr));
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief          Reset all entries from the BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_bt_reset_ioctl(wlan_private * priv)
+{
+       ENTER();
+
+       lbs_pr_alert( "BT: resetting\n");
+
+       return (libertas_prepare_and_send_command(priv,
+                                     cmd_bt_access,
+                                     cmd_act_bt_access_reset,
+                                     cmd_option_waitforrsp, 0, NULL));
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief          List an entry from the BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       int pos;
+       char *addr1;
+       struct iwreq *wrq = (struct iwreq *)req;
+       /* used to pass id and store the bt entry returned by the FW */
+       union {
+               int id;
+               char addr1addr2[2 * ETH_ALEN];
+       } param;
+       static char outstr[64];
+       char *pbuf = outstr;
+       int ret;
+
+       ENTER();
+
+       if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) {
+               lbs_pr_debug(1, "Copy from user failed\n");
+               return -1;
+       }
+       param.id = simple_strtoul(outstr, NULL, 10);
+       pos = sprintf(pbuf, "%d: ", param.id);
+       pbuf += pos;
+
+       ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
+                                   cmd_act_bt_access_list,
+                                   cmd_option_waitforrsp, 0,
+                                   (char *)&param);
+
+       if (ret == 0) {
+               addr1 = param.addr1addr2;
+
+               pos = sprintf(pbuf, "ignoring traffic from ");
+               pbuf += pos;
+               pos = eth_addr2str(addr1, pbuf);
+               pbuf += pos;
+       } else {
+               sprintf(pbuf, "(null)");
+               pbuf += pos;
+       }
+
+       wrq->u.data.length = strlen(outstr);
+       if (copy_to_user(wrq->u.data.pointer, (char *)outstr,
+                        wrq->u.data.length)) {
+               lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n");
+               return -EFAULT;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief          Find the next parameter in an input string
+ *  @param ptr      A pointer to the input parameter string
+ *  @return         A pointer to the next parameter, or 0 if no parameters left.
+ */
+static char * next_param(char * ptr)
+{
+       if (!ptr) return NULL;
+       while (*ptr == ' ' || *ptr == '\t') ++ptr;
+       return (*ptr == '\0') ? NULL : ptr;
+}
+
+/**
+ *  @brief          Add an entry to the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[128];
+       static struct cmd_ds_fwt_access fwt_access;
+       char *ptr;
+
+       ENTER();
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+               lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
+               return -EINVAL;
+       }
+
+       if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+               lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
+               return -EINVAL;
+       }
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.metric =
+                       cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+       else
+               fwt_access.metric = FWT_DEFAULT_METRIC;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.dir = FWT_DEFAULT_DIR;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.ssn =
+                       cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+       else
+               fwt_access.ssn = FWT_DEFAULT_SSN;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.dsn =
+                       cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+       else
+               fwt_access.dsn = FWT_DEFAULT_DSN;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.ttl = FWT_DEFAULT_TTL;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.expiration =
+                       cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+       else
+               fwt_access.expiration = FWT_DEFAULT_EXPIRATION;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.snr =
+                       cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+       else
+               fwt_access.snr = FWT_DEFAULT_SNR;
+
+#ifdef DEBUG
+       {
+               char ethaddr1_str[18], ethaddr2_str[18];
+               eth_addr2str(fwt_access.da, ethaddr1_str);
+               eth_addr2str(fwt_access.ra, ethaddr2_str);
+               lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
+                      fwt_access.dir, ethaddr2_str);
+               lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
+                      fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
+                      fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
+                      fwt_access.sleepmode, fwt_access.snr);
+       }
+#endif
+
+       LEAVE();
+       return (libertas_prepare_and_send_command(priv, cmd_fwt_access,
+                                                 cmd_act_fwt_access_add,
+                                                 cmd_option_waitforrsp, 0,
+                                                 (void *)&fwt_access));
+}
+
+/**
+ *  @brief          Delete an entry from the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[64];
+       static struct cmd_ds_fwt_access fwt_access;
+       char *ptr;
+
+       ENTER();
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+               lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
+               return -EINVAL;
+       }
+
+       if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+               lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
+               return -EINVAL;
+       }
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.dir = FWT_DEFAULT_DIR;
+
+#ifdef DEBUG
+       {
+               char ethaddr1_str[18], ethaddr2_str[18];
+               lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str);
+               eth_addr2str(fwt_access.da, ethaddr1_str);
+               eth_addr2str(fwt_access.ra, ethaddr2_str);
+               lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
+                      ethaddr2_str, fwt_access.dir);
+       }
+#endif
+
+       LEAVE();
+       return (libertas_prepare_and_send_command(priv,
+                                                 cmd_fwt_access,
+                                                 cmd_act_fwt_access_del,
+                                                 cmd_option_waitforrsp, 0,
+                                                 (void *)&fwt_access));
+}
+
+
+/**
+ *  @brief             Print route parameters
+ *  @param fwt_access  struct cmd_ds_fwt_access with route info
+ *  @param buf         destination buffer for route info
+ */
+static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
+{
+       buf += sprintf(buf, " ");
+       buf += eth_addr2str(fwt_access.da, buf);
+       buf += sprintf(buf, " ");
+       buf += eth_addr2str(fwt_access.ra, buf);
+       buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
+       buf += sprintf(buf, " %u", fwt_access.dir);
+       buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
+       buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
+       buf += sprintf(buf, " %u", fwt_access.hopcount);
+       buf += sprintf(buf, " %u", fwt_access.ttl);
+       buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
+       buf += sprintf(buf, " %u", fwt_access.sleepmode);
+       buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr));
+}
+
+/**
+ *  @brief          Lookup an entry in the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[64];
+       char *ptr;
+       static struct cmd_ds_fwt_access fwt_access;
+       static char out_str[128];
+       int ret;
+
+       ENTER();
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+               lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
+               return -EINVAL;
+       }
+
+#ifdef DEBUG
+       {
+               char ethaddr1_str[18];
+               lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str);
+               eth_addr2str(fwt_access.da, ethaddr1_str);
+               lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
+       }
+#endif
+
+       ret = libertas_prepare_and_send_command(priv,
+                                               cmd_fwt_access,
+                                               cmd_act_fwt_access_lookup,
+                                               cmd_option_waitforrsp, 0,
+                                               (void *)&fwt_access);
+
+       if (ret == 0)
+               print_route(fwt_access, out_str);
+       else
+               sprintf(out_str, "(null)");
+
+       wrq->u.data.length = strlen(out_str);
+       if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+                        wrq->u.data.length)) {
+               lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n");
+               return -EFAULT;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief          Reset all entries from the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_reset_ioctl(wlan_private * priv)
+{
+       lbs_pr_debug(1, "FWT: resetting\n");
+
+       return (libertas_prepare_and_send_command(priv,
+                                     cmd_fwt_access,
+                                     cmd_act_fwt_access_reset,
+                                     cmd_option_waitforrsp, 0, NULL));
+}
+
+/**
+ *  @brief          List an entry from the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[8];
+       static struct cmd_ds_fwt_access fwt_access;
+       char *ptr = in_str;
+       static char out_str[128];
+       char *pbuf = out_str;
+       int ret;
+
+       ENTER();
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+       {
+               lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str);
+               lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
+       }
+#endif
+
+       ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+                                   cmd_act_fwt_access_list,
+                                   cmd_option_waitforrsp, 0, (void *)&fwt_access);
+
+       if (ret == 0)
+               print_route(fwt_access, pbuf);
+       else
+               pbuf += sprintf(pbuf, " (null)");
+
+       wrq->u.data.length = strlen(out_str);
+       if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+                        wrq->u.data.length)) {
+               lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n");
+               return -EFAULT;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief          List an entry from the FRT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[64];
+       static struct cmd_ds_fwt_access fwt_access;
+       char *ptr = in_str;
+       static char out_str[128];
+       char *pbuf = out_str;
+       int ret;
+
+       ENTER();
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+       {
+               lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str);
+               lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
+       }
+#endif
+
+       ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+                                   cmd_act_fwt_access_list_route,
+                                   cmd_option_waitforrsp, 0, (void *)&fwt_access);
+
+       if (ret == 0) {
+               pbuf += sprintf(pbuf, " ");
+               pbuf += eth_addr2str(fwt_access.da, pbuf);
+               pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric));
+               pbuf += sprintf(pbuf, " %u", fwt_access.dir);
+               /* note that the firmware returns the nid in the id field */
+               pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id));
+               pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn));
+               pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn));
+               pbuf += sprintf(pbuf, "  hop %u", fwt_access.hopcount);
+               pbuf += sprintf(pbuf, "  ttl %u", fwt_access.ttl);
+               pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration));
+       } else
+               pbuf += sprintf(pbuf, " (null)");
+
+       wrq->u.data.length = strlen(out_str);
+       if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+                        wrq->u.data.length)) {
+               lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n");
+               return -EFAULT;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief          List an entry from the FNT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[8];
+       static struct cmd_ds_fwt_access fwt_access;
+       char *ptr = in_str;
+       static char out_str[128];
+       char *pbuf = out_str;
+       int ret;
+
+       ENTER();
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       memset(&fwt_access, 0, sizeof(fwt_access));
+       fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+       {
+               lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str);
+               lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
+       }
+#endif
+
+       ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+                                   cmd_act_fwt_access_list_neighbor,
+                                   cmd_option_waitforrsp, 0,
+                                   (void *)&fwt_access);
+
+       if (ret == 0) {
+               pbuf += sprintf(pbuf, " ra ");
+               pbuf += eth_addr2str(fwt_access.ra, pbuf);
+               pbuf += sprintf(pbuf, "  slp %u", fwt_access.sleepmode);
+               pbuf += sprintf(pbuf, "  snr %u", le32_to_cpu(fwt_access.snr));
+               pbuf += sprintf(pbuf, "  ref %u", le32_to_cpu(fwt_access.references));
+       } else
+               pbuf += sprintf(pbuf, " (null)");
+
+       wrq->u.data.length = strlen(out_str);
+       if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+                        wrq->u.data.length)) {
+               lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n");
+               return -EFAULT;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief          Cleans up the route (FRT) and neighbor (FNT) tables
+ *                  (Garbage Collection)
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       static struct cmd_ds_fwt_access fwt_access;
+       int ret;
+
+       ENTER();
+
+       lbs_pr_debug(1, "FWT: cleaning up\n");
+
+       memset(&fwt_access, 0, sizeof(fwt_access));
+
+       ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+                                   cmd_act_fwt_access_cleanup,
+                                   cmd_option_waitforrsp, 0,
+                                   (void *)&fwt_access);
+
+       if (ret == 0)
+               req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
+       else
+               return -EFAULT;
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief          Gets firmware internal time (debug purposes)
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       static struct cmd_ds_fwt_access fwt_access;
+       int ret;
+
+       ENTER();
+
+       lbs_pr_debug(1, "FWT: getting time\n");
+
+       memset(&fwt_access, 0, sizeof(fwt_access));
+
+       ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+                                   cmd_act_fwt_access_time,
+                                   cmd_option_waitforrsp, 0,
+                                   (void *)&fwt_access);
+
+       if (ret == 0)
+               req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
+       else
+               return -EFAULT;
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief          Gets mesh ttl from firmware
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
+{
+       struct cmd_ds_mesh_access mesh_access;
+       int ret;
+
+       ENTER();
+
+       memset(&mesh_access, 0, sizeof(mesh_access));
+
+       ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
+                                   cmd_act_mesh_get_ttl,
+                                   cmd_option_waitforrsp, 0,
+                                   (void *)&mesh_access);
+
+       if (ret == 0) {
+               req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0]));
+       }
+       else
+               return -EFAULT;
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief          Gets mesh ttl from firmware
+ *  @param priv     A pointer to wlan_private structure
+ *  @param ttl      New ttl value
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
+{
+       struct cmd_ds_mesh_access mesh_access;
+       int ret;
+
+       ENTER();
+
+       if( (ttl > 0xff) || (ttl < 0) )
+               return -EINVAL;
+
+       memset(&mesh_access, 0, sizeof(mesh_access));
+       mesh_access.data[0] = ttl;
+
+       ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
+                                               cmd_act_mesh_set_ttl,
+                                               cmd_option_waitforrsp, 0,
+                                               (void *)&mesh_access);
+
+       if (ret != 0)
+               ret = -EFAULT;
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief ioctl function - entry point
+ *
+ *  @param dev         A pointer to net_device structure
+ *  @param req         A pointer to ifreq structure
+ *  @param cmd                 command
+ *  @return            0--success, otherwise fail
+ */
+int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+       int subcmd = 0;
+       int idata = 0;
+       int *pdata;
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct iwreq *wrq = (struct iwreq *)req;
+
+       ENTER();
+
+       lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+       switch (cmd) {
+       case WLANSCAN_TYPE:
+               lbs_pr_debug(1, "Scan type Ioctl\n");
+               ret = wlan_scan_type_ioctl(priv, wrq);
+               break;
+
+       case WLAN_SETNONE_GETNONE:      /* set WPA mode on/off ioctl #20 */
+               switch (wrq->u.data.flags) {
+               case WLANDEAUTH:
+                       lbs_pr_debug(1, "Deauth\n");
+                       libertas_send_deauth(priv);
+                       break;
+
+               case WLANADHOCSTOP:
+                       lbs_pr_debug(1, "Adhoc stop\n");
+                       ret = libertas_do_adhocstop_ioctl(priv);
+                       break;
+
+               case WLANRADIOON:
+                       wlan_radio_ioctl(priv, 1);
+                       break;
+
+               case WLANRADIOOFF:
+                       wlan_radio_ioctl(priv, 0);
+                       break;
+               case WLANWLANIDLEON:
+                       libertas_idle_on(priv);
+                       break;
+               case WLANWLANIDLEOFF:
+                       libertas_idle_off(priv);
+                       break;
+               case WLAN_SUBCMD_BT_RESET:      /* bt_reset */
+                       wlan_bt_reset_ioctl(priv);
+                       break;
+               case WLAN_SUBCMD_FWT_RESET:     /* fwt_reset */
+                       wlan_fwt_reset_ioctl(priv);
+                       break;
+               }               /* End of switch */
+               break;
+
+       case WLANSETWPAIE:
+               ret = wlan_setwpaie_ioctl(priv, req);
+               break;
+       case WLAN_SETINT_GETINT:
+               /* The first 4 bytes of req->ifr_data is sub-ioctl number
+                * after 4 bytes sits the payload.
+                */
+               subcmd = (int)req->ifr_data;    //from iwpriv subcmd
+               switch (subcmd) {
+               case WLANNF:
+                       ret = wlan_get_nf(priv, wrq);
+                       break;
+               case WLANRSSI:
+                       ret = wlan_get_rssi(priv, wrq);
+                       break;
+               case WLANENABLE11D:
+                       ret = libertas_cmd_enable_11d(priv, wrq);
+                       break;
+               case WLANADHOCGRATE:
+                       ret = wlan_do_set_grate_ioctl(priv, wrq);
+                       break;
+               case WLAN_SUBCMD_SET_PRESCAN:
+                       ret = wlan_subcmd_setprescan_ioctl(priv, wrq);
+                       break;
+               }
+               break;
+
+       case WLAN_SETONEINT_GETONEINT:
+               switch (wrq->u.data.flags) {
+               case WLAN_BEACON_INTERVAL:
+                       ret = wlan_beacon_interval(priv, wrq);
+                       break;
+
+               case WLAN_LISTENINTRVL:
+                       if (!wrq->u.data.length) {
+                               int data;
+                               lbs_pr_debug(1, "Get locallisteninterval value\n");
+#define GET_ONE_INT    1
+                               data = adapter->locallisteninterval;
+                               if (copy_to_user(wrq->u.data.pointer,
+                                                &data, sizeof(int))) {
+                                       lbs_pr_debug(1, "Copy to user failed\n");
+                                       return -EFAULT;
+                               }
+
+                               wrq->u.data.length = GET_ONE_INT;
+                       } else {
+                               int data;
+                               if (copy_from_user
+                                   (&data, wrq->u.data.pointer, sizeof(int))) {
+                                       lbs_pr_debug(1, "Copy from user failed\n");
+                                       return -EFAULT;
+                               }
+
+                               lbs_pr_debug(1, "Set locallisteninterval = %d\n",
+                                      data);
+#define MAX_U16_VAL    65535
+                               if (data > MAX_U16_VAL) {
+                                       lbs_pr_debug(1, "Exceeds U16 value\n");
+                                       return -EINVAL;
+                               }
+                               adapter->locallisteninterval = data;
+                       }
+                       break;
+               case WLAN_TXCONTROL:
+                       ret = wlan_txcontrol(priv, wrq);        //adds for txcontrol ioctl
+                       break;
+
+               case WLAN_NULLPKTINTERVAL:
+                       ret = wlan_null_pkt_interval(priv, wrq);
+                       break;
+
+               default:
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
+               break;
+
+       case WLAN_SETONEINT_GETNONE:
+               /* The first 4 bytes of req->ifr_data is sub-ioctl number
+                * after 4 bytes sits the payload.
+                */
+               subcmd = wrq->u.data.flags;     //from wpa_supplicant subcmd
+
+               if (!subcmd)
+                       subcmd = (int)req->ifr_data;    //from iwpriv subcmd
+
+               switch (subcmd) {
+               case WLAN_SUBCMD_SETRXANTENNA:  /* SETRXANTENNA */
+                       idata = SUBCMD_DATA(wrq);
+                       ret = setrxantenna(priv, idata);
+                       break;
+               case WLAN_SUBCMD_SETTXANTENNA:  /* SETTXANTENNA */
+                       idata = SUBCMD_DATA(wrq);
+                       ret = settxantenna(priv, idata);
+                       break;
+               case WLAN_SET_ATIM_WINDOW:
+                       adapter->atimwindow = SUBCMD_DATA(wrq);
+                       adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50);
+                       break;
+               case WLANSETBCNAVG:
+                       adapter->bcn_avg_factor = SUBCMD_DATA(wrq);
+                       if (adapter->bcn_avg_factor == 0)
+                               adapter->bcn_avg_factor =
+                                   DEFAULT_BCN_AVG_FACTOR;
+                       if (adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR)
+                               adapter->bcn_avg_factor =
+                                   DEFAULT_BCN_AVG_FACTOR;
+                       break;
+               case WLANSETDATAAVG:
+                       adapter->data_avg_factor = SUBCMD_DATA(wrq);
+                       if (adapter->data_avg_factor == 0)
+                               adapter->data_avg_factor =
+                                   DEFAULT_DATA_AVG_FACTOR;
+                       if (adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR)
+                               adapter->data_avg_factor =
+                                   DEFAULT_DATA_AVG_FACTOR;
+                       break;
+               case WLANSETREGION:
+                       idata = SUBCMD_DATA(wrq);
+                       ret = wlan_set_region(priv, (u16) idata);
+                       break;
+
+               case WLAN_SET_LISTEN_INTERVAL:
+                       idata = SUBCMD_DATA(wrq);
+                       adapter->listeninterval = (u16) idata;
+                       break;
+
+               case WLAN_SET_MULTIPLE_DTIM:
+                       ret = wlan_set_multiple_dtim_ioctl(priv, req);
+                       break;
+
+               case WLANSETAUTHALG:
+                       ret = wlan_setauthalg_ioctl(priv, req);
+                       break;
+
+               case WLANSET8021XAUTHALG:
+                       ret = wlan_set8021xauthalg_ioctl(priv, req);
+                       break;
+
+               case WLANSETENCRYPTIONMODE:
+                       ret = wlan_setencryptionmode_ioctl(priv, req);
+                       break;
+
+               case WLAN_SET_LINKMODE:
+                       ret = wlan_set_linkmode_ioctl(priv, req);
+                       break;
+
+               case WLAN_SET_RADIOMODE:
+                       ret = wlan_set_radiomode_ioctl(priv, req);
+                       break;
+
+               case WLAN_SET_DEBUGMODE:
+                       ret = wlan_set_debugmode_ioctl(priv, req);
+                       break;
+
+               case WLAN_SUBCMD_MESH_SET_TTL:
+                       idata = SUBCMD_DATA(wrq);
+                       ret = wlan_mesh_set_ttl_ioctl(priv, idata);
+                       break;
+
+               default:
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
+
+               break;
+
+       case WLAN_SETNONE_GETTWELVE_CHAR:       /* Get Antenna settings */
+               /*
+                * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
+                * in flags of iwreq structure, otherwise it will be in
+                * mode member of iwreq structure.
+                */
+               switch ((int)wrq->u.data.flags) {
+               case WLAN_SUBCMD_GETRXANTENNA:  /* Get Rx Antenna */
+                       ret = wlan_subcmd_getrxantenna_ioctl(priv, req);
+                       break;
+
+               case WLAN_SUBCMD_GETTXANTENNA:  /* Get Tx Antenna */
+                       ret = wlan_subcmd_gettxantenna_ioctl(priv, req);
+                       break;
+
+               case WLAN_GET_TSF:
+                       ret = wlan_get_tsf_ioctl(priv, wrq);
+                       break;
+               }
+               break;
+
+       case WLAN_SET128CHAR_GET128CHAR:
+               switch ((int)wrq->u.data.flags) {
+
+               case WLANSCAN_MODE:
+                       lbs_pr_debug(1, "Scan mode Ioctl\n");
+                       ret = wlan_scan_mode_ioctl(priv, wrq);
+                       break;
+
+               case WLAN_GET_ADHOC_STATUS:
+                       ret = wlan_get_adhoc_status_ioctl(priv, wrq);
+                       break;
+               case WLAN_SUBCMD_BT_ADD:
+                       ret = wlan_bt_add_ioctl(priv, req);
+                       break;
+               case WLAN_SUBCMD_BT_DEL:
+                       ret = wlan_bt_del_ioctl(priv, req);
+                       break;
+               case WLAN_SUBCMD_BT_LIST:
+                       ret = wlan_bt_list_ioctl(priv, req);
+                       break;
+               case WLAN_SUBCMD_FWT_ADD:
+                       ret = wlan_fwt_add_ioctl(priv, req);
+                       break;
+               case WLAN_SUBCMD_FWT_DEL:
+                       ret = wlan_fwt_del_ioctl(priv, req);
+                       break;
+               case WLAN_SUBCMD_FWT_LOOKUP:
+                       ret = wlan_fwt_lookup_ioctl(priv, req);
+                       break;
+               case WLAN_SUBCMD_FWT_LIST_NEIGHBOR:
+                       ret = wlan_fwt_list_neighbor_ioctl(priv, req);
+                       break;
+               case WLAN_SUBCMD_FWT_LIST:
+                       ret = wlan_fwt_list_ioctl(priv, req);
+                       break;
+               case WLAN_SUBCMD_FWT_LIST_ROUTE:
+                       ret = wlan_fwt_list_route_ioctl(priv, req);
+                       break;
+               }
+               break;
+
+       case WLAN_SETNONE_GETONEINT:
+               switch ((int)req->ifr_data) {
+               case WLANGETBCNAVG:
+                       pdata = (int *)wrq->u.name;
+                       *pdata = (int)adapter->bcn_avg_factor;
+                       break;
+
+               case WLANGETREGION:
+                       pdata = (int *)wrq->u.name;
+                       *pdata = (int)adapter->regioncode;
+                       break;
+
+               case WLAN_GET_LISTEN_INTERVAL:
+                       pdata = (int *)wrq->u.name;
+                       *pdata = (int)adapter->listeninterval;
+                       break;
+
+               case WLAN_GET_LINKMODE:
+                       req->ifr_data = (char *)((u32) adapter->linkmode);
+                       break;
+
+               case WLAN_GET_RADIOMODE:
+                       req->ifr_data = (char *)((u32) adapter->radiomode);
+                       break;
+
+               case WLAN_GET_DEBUGMODE:
+                       req->ifr_data = (char *)((u32) adapter->debugmode);
+                       break;
+
+               case WLAN_GET_MULTIPLE_DTIM:
+                       pdata = (int *)wrq->u.name;
+                       *pdata = (int)adapter->multipledtim;
+                       break;
+               case WLAN_GET_TX_RATE:
+                       ret = wlan_get_txrate_ioctl(priv, req);
+                       break;
+               case WLAN_SUBCMD_FWT_CLEANUP:   /* fwt_cleanup */
+                       ret = wlan_fwt_cleanup_ioctl(priv, req);
+                       break;
+
+               case WLAN_SUBCMD_FWT_TIME:      /* fwt_time */
+                       ret = wlan_fwt_time_ioctl(priv, req);
+                       break;
+
+               case WLAN_SUBCMD_MESH_GET_TTL:
+                       ret = wlan_mesh_get_ttl_ioctl(priv, req);
+                       break;
+
+               default:
+                       ret = -EOPNOTSUPP;
+
+               }
+
+               break;
+
+       case WLANGETLOG:
+               ret = wlan_do_getlog_ioctl(priv, wrq);
+               break;
+
+       case WLAN_SET_GET_SIXTEEN_INT:
+               switch ((int)wrq->u.data.flags) {
+               case WLAN_TPCCFG:
+                       {
+                               int data[5];
+                               struct cmd_ds_802_11_tpc_cfg cfg;
+                               memset(&cfg, 0, sizeof(cfg));
+                               if ((wrq->u.data.length > 1)
+                                   && (wrq->u.data.length != 5))
+                                       return -1;
+
+                               if (wrq->u.data.length == 0) {
+                                       cfg.action =
+                                           cpu_to_le16
+                                           (cmd_act_get);
+                               } else {
+                                       if (copy_from_user
+                                           (data, wrq->u.data.pointer,
+                                            sizeof(int) * 5)) {
+                                               lbs_pr_debug(1,
+                                                      "Copy from user failed\n");
+                                               return -EFAULT;
+                                       }
+
+                                       cfg.action =
+                                           cpu_to_le16
+                                           (cmd_act_set);
+                                       cfg.enable = data[0];
+                                       cfg.usesnr = data[1];
+                                       cfg.P0 = data[2];
+                                       cfg.P1 = data[3];
+                                       cfg.P2 = data[4];
+                               }
+
+                               ret =
+                                   libertas_prepare_and_send_command(priv,
+                                                         cmd_802_11_tpc_cfg,
+                                                         0,
+                                                         cmd_option_waitforrsp,
+                                                         0, (void *)&cfg);
+
+                               data[0] = cfg.enable;
+                               data[1] = cfg.usesnr;
+                               data[2] = cfg.P0;
+                               data[3] = cfg.P1;
+                               data[4] = cfg.P2;
+                               if (copy_to_user
+                                   (wrq->u.data.pointer, data,
+                                    sizeof(int) * 5)) {
+                                       lbs_pr_debug(1, "Copy to user failed\n");
+                                       return -EFAULT;
+                               }
+
+                               wrq->u.data.length = 5;
+                       }
+                       break;
+
+               case WLAN_POWERCFG:
+                       {
+                               int data[4];
+                               struct cmd_ds_802_11_pwr_cfg cfg;
+                               memset(&cfg, 0, sizeof(cfg));
+                               if ((wrq->u.data.length > 1)
+                                   && (wrq->u.data.length != 4))
+                                       return -1;
+                               if (wrq->u.data.length == 0) {
+                                       cfg.action =
+                                           cpu_to_le16
+                                           (cmd_act_get);
+                               } else {
+                                       if (copy_from_user
+                                           (data, wrq->u.data.pointer,
+                                            sizeof(int) * 4)) {
+                                               lbs_pr_debug(1,
+                                                      "Copy from user failed\n");
+                                               return -EFAULT;
+                                       }
+
+                                       cfg.action =
+                                           cpu_to_le16
+                                           (cmd_act_set);
+                                       cfg.enable = data[0];
+                                       cfg.PA_P0 = data[1];
+                                       cfg.PA_P1 = data[2];
+                                       cfg.PA_P2 = data[3];
+                               }
+                               ret =
+                                   libertas_prepare_and_send_command(priv,
+                                                         cmd_802_11_pwr_cfg,
+                                                         0,
+                                                         cmd_option_waitforrsp,
+                                                         0, (void *)&cfg);
+                               data[0] = cfg.enable;
+                               data[1] = cfg.PA_P0;
+                               data[2] = cfg.PA_P1;
+                               data[3] = cfg.PA_P2;
+                               if (copy_to_user
+                                   (wrq->u.data.pointer, data,
+                                    sizeof(int) * 4)) {
+                                       lbs_pr_debug(1, "Copy to user failed\n");
+                                       return -EFAULT;
+                               }
+
+                               wrq->u.data.length = 4;
+                       }
+                       break;
+               case WLAN_AUTO_FREQ_SET:
+                       {
+                               int data[3];
+                               struct cmd_ds_802_11_afc afc;
+                               memset(&afc, 0, sizeof(afc));
+                               if (wrq->u.data.length != 3)
+                                       return -1;
+                               if (copy_from_user
+                                   (data, wrq->u.data.pointer,
+                                    sizeof(int) * 3)) {
+                                       lbs_pr_debug(1, "Copy from user failed\n");
+                                       return -EFAULT;
+                               }
+                               afc.afc_auto = data[0];
+
+                               if (afc.afc_auto != 0) {
+                                       afc.threshold = data[1];
+                                       afc.period = data[2];
+                               } else {
+                                       afc.timing_offset = data[1];
+                                       afc.carrier_offset = data[2];
+                               }
+                               ret =
+                                   libertas_prepare_and_send_command(priv,
+                                                         cmd_802_11_set_afc,
+                                                         0,
+                                                         cmd_option_waitforrsp,
+                                                         0, (void *)&afc);
+                       }
+                       break;
+               case WLAN_AUTO_FREQ_GET:
+                       {
+                               int data[3];
+                               struct cmd_ds_802_11_afc afc;
+                               memset(&afc, 0, sizeof(afc));
+                               ret =
+                                   libertas_prepare_and_send_command(priv,
+                                                         cmd_802_11_get_afc,
+                                                         0,
+                                                         cmd_option_waitforrsp,
+                                                         0, (void *)&afc);
+                               data[0] = afc.afc_auto;
+                               data[1] = afc.timing_offset;
+                               data[2] = afc.carrier_offset;
+                               if (copy_to_user
+                                   (wrq->u.data.pointer, data,
+                                    sizeof(int) * 3)) {
+                                       lbs_pr_debug(1, "Copy to user failed\n");
+                                       return -EFAULT;
+                               }
+
+                               wrq->u.data.length = 3;
+                       }
+                       break;
+               case WLAN_SCANPROBES:
+                       {
+                               int data;
+                               if (wrq->u.data.length > 0) {
+                                       if (copy_from_user
+                                           (&data, wrq->u.data.pointer,
+                                            sizeof(int))) {
+                                               lbs_pr_debug(1,
+                                                      "Copy from user failed\n");
+                                               return -EFAULT;
+                                       }
+
+                                       adapter->scanprobes = data;
+                               } else {
+                                       data = adapter->scanprobes;
+                                       if (copy_to_user
+                                           (wrq->u.data.pointer, &data,
+                                            sizeof(int))) {
+                                               lbs_pr_debug(1,
+                                                      "Copy to user failed\n");
+                                               return -EFAULT;
+                                       }
+                               }
+                               wrq->u.data.length = 1;
+                       }
+                       break;
+               case WLAN_LED_GPIO_CTRL:
+                       {
+                               int i;
+                               int data[16];
+
+                               struct cmd_ds_802_11_led_ctrl ctrl;
+                               struct mrvlietypes_ledgpio *gpio =
+                                   (struct mrvlietypes_ledgpio *) ctrl.data;
+
+                               memset(&ctrl, 0, sizeof(ctrl));
+                               if (wrq->u.data.length > MAX_LEDS * 2)
+                                       return -ENOTSUPP;
+                               if ((wrq->u.data.length % 2) != 0)
+                                       return -ENOTSUPP;
+                               if (wrq->u.data.length == 0) {
+                                       ctrl.action =
+                                           cpu_to_le16
+                                           (cmd_act_get);
+                               } else {
+                                       if (copy_from_user
+                                           (data, wrq->u.data.pointer,
+                                            sizeof(int) *
+                                            wrq->u.data.length)) {
+                                               lbs_pr_debug(1,
+                                                      "Copy from user failed\n");
+                                               return -EFAULT;
+                                       }
+
+                                       ctrl.action =
+                                           cpu_to_le16
+                                           (cmd_act_set);
+                                       ctrl.numled = cpu_to_le16(0);
+                                       gpio->header.type =
+                                           cpu_to_le16(TLV_TYPE_LED_GPIO);
+                                       gpio->header.len = wrq->u.data.length;
+                                       for (i = 0; i < wrq->u.data.length;
+                                            i += 2) {
+                                               gpio->ledpin[i / 2].led =
+                                                   data[i];
+                                               gpio->ledpin[i / 2].pin =
+                                                   data[i + 1];
+                                       }
+                               }
+                               ret =
+                                   libertas_prepare_and_send_command(priv,
+                                                         cmd_802_11_led_gpio_ctrl,
+                                                         0,
+                                                         cmd_option_waitforrsp,
+                                                         0, (void *)&ctrl);
+                               for (i = 0; i < gpio->header.len; i += 2) {
+                                       data[i] = gpio->ledpin[i / 2].led;
+                                       data[i + 1] = gpio->ledpin[i / 2].pin;
+                               }
+                               if (copy_to_user(wrq->u.data.pointer, data,
+                                                sizeof(int) *
+                                                gpio->header.len)) {
+                                       lbs_pr_debug(1, "Copy to user failed\n");
+                                       return -EFAULT;
+                               }
+
+                               wrq->u.data.length = gpio->header.len;
+                       }
+                       break;
+               case WLAN_ADAPT_RATESET:
+                       ret = wlan_adapt_rateset(priv, wrq);
+                       break;
+               case WLAN_INACTIVITY_TIMEOUT:
+                       ret = wlan_inactivity_timeout(priv, wrq);
+                       break;
+               case WLANSNR:
+                       ret = wlan_get_snr(priv, wrq);
+                       break;
+               case WLAN_GET_RXINFO:
+                       ret = wlan_get_rxinfo(priv, wrq);
+               }
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       LEAVE();
+       return ret;
+}
+
+
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
new file mode 100644 (file)
index 0000000..11682cb
--- /dev/null
@@ -0,0 +1,1055 @@
+/**
+  *  Functions implementing wlan infrastructure and adhoc join routines,
+  *  IOCTL handlers as well as command preperation and response routines
+  *  for sending adhoc start, adhoc join, and association commands
+  *  to the firmware.
+  */
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "decl.h"
+#include "join.h"
+#include "dev.h"
+
+/**
+ *  @brief This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates need to be taken
+ *   care, either before or after calling this function
+ *
+ *  @param adapter     A pointer to wlan_adapter structure
+ *  @param rate1       the buffer which keeps input and output
+ *  @param rate1_size  the size of rate1 buffer
+ *  @param rate2       the buffer which keeps rate2
+ *  @param rate2_size  the size of rate2 buffer.
+ *
+ *  @return            0 or -1
+ */
+static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
+                           int rate1_size, u8 * rate2, int rate2_size)
+{
+       u8 *ptr = rate1;
+       int ret = 0;
+       u8 tmp[30];
+       int i;
+
+       memset(&tmp, 0, sizeof(tmp));
+       memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
+       memset(rate1, 0, rate1_size);
+
+       /* Mask the top bit of the original values */
+       for (i = 0; tmp[i] && i < sizeof(tmp); i++)
+               tmp[i] &= 0x7F;
+
+       for (i = 0; rate2[i] && i < rate2_size; i++) {
+               /* Check for Card Rate in tmp, excluding the top bit */
+               if (strchr(tmp, rate2[i] & 0x7F)) {
+                       /* values match, so copy the Card Rate to rate1 */
+                       *rate1++ = rate2[i];
+               }
+       }
+
+       lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
+       lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
+       lbs_dbg_hex("Common rates:", ptr, rate1_size);
+       lbs_pr_debug(1, "Tx datarate is set to 0x%X\n", adapter->datarate);
+
+       if (!adapter->is_datarate_auto) {
+               while (*ptr) {
+                       if ((*ptr & 0x7f) == adapter->datarate) {
+                               ret = 0;
+                               goto done;
+                       }
+                       ptr++;
+               }
+               lbs_pr_alert( "Previously set fixed data rate %#x isn't "
+                      "compatible with the network.\n", adapter->datarate);
+
+               ret = -1;
+               goto done;
+       }
+
+       ret = 0;
+done:
+       return ret;
+}
+
+int libertas_send_deauth(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       if (adapter->inframode == wlan802_11infrastructure &&
+           adapter->connect_status == libertas_connected)
+               ret = libertas_send_deauthentication(priv);
+       else
+               ret = -ENOTSUPP;
+
+       return ret;
+}
+
+int libertas_do_adhocstop_ioctl(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       if (adapter->inframode == wlan802_11ibss &&
+           adapter->connect_status == libertas_connected)
+               ret = libertas_stop_adhoc_network(priv);
+       else
+               ret = -ENOTSUPP;
+
+       return ret;
+}
+
+/**
+ *  @brief Associate to a specific BSS discovered in a scan
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param pbssdesc  Pointer to the BSS descriptor to associate with.
+ *
+ *  @return          0-success, otherwise fail
+ */
+int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret;
+
+       ENTER();
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
+                                   0, cmd_option_waitforrsp,
+                                   0, pbssdesc->macaddress);
+
+       if (ret) {
+               LEAVE();
+               return ret;
+       }
+
+       /* set preamble to firmware */
+       if (adapter->capinfo.shortpreamble && pbssdesc->cap.shortpreamble)
+               adapter->preamble = cmd_type_short_preamble;
+       else
+               adapter->preamble = cmd_type_long_preamble;
+
+       libertas_set_radio_control(priv);
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
+                                   0, cmd_option_waitforrsp, 0, pbssdesc);
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Start an Adhoc Network
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param adhocssid    The ssid of the Adhoc Network
+ *  @return             0--success, -1--fail
+ */
+int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *adhocssid)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       adapter->adhoccreate = 1;
+
+       if (!adapter->capinfo.shortpreamble) {
+               lbs_pr_debug(1, "AdhocStart: Long preamble\n");
+               adapter->preamble = cmd_type_long_preamble;
+       } else {
+               lbs_pr_debug(1, "AdhocStart: Short preamble\n");
+               adapter->preamble = cmd_type_short_preamble;
+       }
+
+       libertas_set_radio_control(priv);
+
+       lbs_pr_debug(1, "Adhoc channel = %d\n", adapter->adhocchannel);
+       lbs_pr_debug(1, "curbssparams.channel = %d\n",
+              adapter->curbssparams.channel);
+       lbs_pr_debug(1, "curbssparams.band = %d\n", adapter->curbssparams.band);
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
+                                   0, cmd_option_waitforrsp, 0, adhocssid);
+
+       return ret;
+}
+
+/**
+ *  @brief Join an adhoc network found in a previous scan
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param pbssdesc     Pointer to a BSS descriptor found in a previous scan
+ *                      to attempt to join
+ *
+ *  @return             0--success, -1--fail
+ */
+int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor * pbssdesc)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid =%s\n",
+              adapter->curbssparams.ssid.ssid);
+       lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid_len =%u\n",
+              adapter->curbssparams.ssid.ssidlength);
+       lbs_pr_debug(1, "libertas_join_adhoc_network: ssid =%s\n", pbssdesc->ssid.ssid);
+       lbs_pr_debug(1, "libertas_join_adhoc_network: ssid len =%u\n",
+              pbssdesc->ssid.ssidlength);
+
+       /* check if the requested SSID is already joined */
+       if (adapter->curbssparams.ssid.ssidlength
+           && !libertas_SSID_cmp(&pbssdesc->ssid, &adapter->curbssparams.ssid)
+           && (adapter->curbssparams.bssdescriptor.inframode ==
+               wlan802_11ibss)) {
+
+        lbs_pr_debug(1,
+                      "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+                      "not attempting to re-join");
+
+               return -1;
+       }
+
+       /*Use shortpreamble only when both creator and card supports
+          short preamble */
+       if (!pbssdesc->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
+               lbs_pr_debug(1, "AdhocJoin: Long preamble\n");
+               adapter->preamble = cmd_type_long_preamble;
+       } else {
+               lbs_pr_debug(1, "AdhocJoin: Short preamble\n");
+               adapter->preamble = cmd_type_short_preamble;
+       }
+
+       libertas_set_radio_control(priv);
+
+       lbs_pr_debug(1, "curbssparams.channel = %d\n",
+              adapter->curbssparams.channel);
+       lbs_pr_debug(1, "curbssparams.band = %c\n", adapter->curbssparams.band);
+
+       adapter->adhoccreate = 0;
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
+                                   0, cmd_option_waitforrsp,
+                                   OID_802_11_SSID, pbssdesc);
+
+       return ret;
+}
+
+int libertas_stop_adhoc_network(wlan_private * priv)
+{
+       return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
+                                    0, cmd_option_waitforrsp, 0, NULL);
+}
+
+/**
+ *  @brief Send Deauthentication Request
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @return          0--success, -1--fail
+ */
+int libertas_send_deauthentication(wlan_private * priv)
+{
+       return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
+                                    0, cmd_option_waitforrsp, 0, NULL);
+}
+
+/**
+ *  @brief Set Idle Off
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             0 --success, otherwise fail
+ */
+int libertas_idle_off(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       const u8 zeromac[] = { 0, 0, 0, 0, 0, 0 };
+       int i;
+
+       ENTER();
+
+       if (adapter->connect_status == libertas_disconnected) {
+               if (adapter->inframode == wlan802_11infrastructure) {
+                       if (memcmp(adapter->previousbssid, zeromac,
+                                  sizeof(zeromac)) != 0) {
+
+                               lbs_pr_debug(1, "Previous SSID = %s\n",
+                                      adapter->previousssid.ssid);
+                               lbs_pr_debug(1, "Previous BSSID = "
+                                      "%02x:%02x:%02x:%02x:%02x:%02x:\n",
+                                      adapter->previousbssid[0],
+                                      adapter->previousbssid[1],
+                                      adapter->previousbssid[2],
+                                      adapter->previousbssid[3],
+                                      adapter->previousbssid[4],
+                                      adapter->previousbssid[5]);
+
+                               i = libertas_find_SSID_in_list(adapter,
+                                                  &adapter->previousssid,
+                                                  adapter->previousbssid,
+                                                  adapter->inframode);
+
+                               if (i < 0) {
+                                       libertas_send_specific_BSSID_scan(priv,
+                                                             adapter->
+                                                             previousbssid,
+                                                             1);
+                                       i = libertas_find_SSID_in_list(adapter,
+                                                          &adapter->
+                                                          previousssid,
+                                                          adapter->
+                                                          previousbssid,
+                                                          adapter->
+                                                          inframode);
+                               }
+
+                               if (i < 0) {
+                                       /* If the BSSID could not be found, try just the SSID */
+                                       i = libertas_find_SSID_in_list(adapter,
+                                                          &adapter->
+                                                          previousssid, NULL,
+                                                          adapter->
+                                                          inframode);
+                               }
+
+                               if (i < 0) {
+                                       libertas_send_specific_SSID_scan(priv,
+                                                            &adapter->
+                                                            previousssid,
+                                                            1);
+                                       i = libertas_find_SSID_in_list(adapter,
+                                                          &adapter->
+                                                          previousssid, NULL,
+                                                          adapter->
+                                                          inframode);
+                               }
+
+                               if (i >= 0) {
+                                       ret =
+                                           wlan_associate(priv,
+                                                          &adapter->
+                                                          scantable[i]);
+                               }
+                       }
+               } else if (adapter->inframode == wlan802_11ibss) {
+                       ret = libertas_prepare_and_send_command(priv,
+                                                   cmd_802_11_ad_hoc_start,
+                                                   0,
+                                                   cmd_option_waitforrsp,
+                                                   0, &adapter->previousssid);
+               }
+       }
+       /* else it is connected */
+
+       lbs_pr_debug(1, "\nwlanidle is off");
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Set Idle On
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             0 --success, otherwise fail
+ */
+int libertas_idle_on(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       if (adapter->connect_status == libertas_connected) {
+               if (adapter->inframode == wlan802_11infrastructure) {
+                       lbs_pr_debug(1, "Previous SSID = %s\n",
+                              adapter->previousssid.ssid);
+                       memmove(&adapter->previousssid,
+                               &adapter->curbssparams.ssid,
+                               sizeof(struct WLAN_802_11_SSID));
+                       libertas_send_deauth(priv);
+
+               } else if (adapter->inframode == wlan802_11ibss) {
+                       ret = libertas_stop_adhoc_network(priv);
+               }
+
+       }
+
+       lbs_pr_debug(1, "\nwlanidle is on");
+
+       return ret;
+}
+
+/**
+ *  @brief This function prepares command of authenticate.
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param cmd       A pointer to cmd_ds_command structure
+ *  @param pdata_buf Void cast of pointer to a BSSID to authenticate with
+ *
+ *  @return         0 or -1
+ */
+int libertas_cmd_80211_authenticate(wlan_private * priv,
+                                struct cmd_ds_command *cmd,
+                                void *pdata_buf)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ds_802_11_authenticate *pauthenticate =
+           &cmd->params.auth;
+       u8 *bssid = pdata_buf;
+
+       cmd->command = cpu_to_le16(cmd_802_11_authenticate);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
+                            + S_DS_GEN);
+
+       pauthenticate->authtype = adapter->secinfo.authmode;
+       memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
+
+       lbs_pr_debug(1, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n",
+              bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
+
+       return 0;
+}
+
+int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+                                  struct cmd_ds_command *cmd)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
+
+       ENTER();
+
+       cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
+                            S_DS_GEN);
+
+       /* set AP MAC address */
+       memmove(dauth->macaddr, adapter->curbssparams.bssid,
+               ETH_ALEN);
+
+       /* Reason code 3 = Station is leaving */
+#define REASON_CODE_STA_LEAVING 3
+       dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
+
+       LEAVE();
+       return 0;
+}
+
+int libertas_cmd_80211_associate(wlan_private * priv,
+                             struct cmd_ds_command *cmd, void *pdata_buf)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
+       int ret = 0;
+       struct bss_descriptor *pbssdesc;
+       u8 *card_rates;
+       u8 *pos;
+       int card_rates_size;
+       u16 tmpcap;
+       struct mrvlietypes_ssidparamset *ssid;
+       struct mrvlietypes_phyparamset *phy;
+       struct mrvlietypes_ssparamset *ss;
+       struct mrvlietypes_ratesparamset *rates;
+       struct mrvlietypes_rsnparamset *rsn;
+
+       ENTER();
+
+       pbssdesc = pdata_buf;
+       pos = (u8 *) passo;
+
+       if (!adapter) {
+               ret = -1;
+               goto done;
+       }
+
+       cmd->command = cpu_to_le16(cmd_802_11_associate);
+
+       /* Save so we know which BSS Desc to use in the response handler */
+       adapter->pattemptedbssdesc = pbssdesc;
+
+       memcpy(passo->peerstaaddr,
+              pbssdesc->macaddress, sizeof(passo->peerstaaddr));
+       pos += sizeof(passo->peerstaaddr);
+
+       /* set the listen interval */
+       passo->listeninterval = adapter->listeninterval;
+
+       pos += sizeof(passo->capinfo);
+       pos += sizeof(passo->listeninterval);
+       pos += sizeof(passo->bcnperiod);
+       pos += sizeof(passo->dtimperiod);
+
+       ssid = (struct mrvlietypes_ssidparamset *) pos;
+       ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
+       ssid->header.len = pbssdesc->ssid.ssidlength;
+       memcpy(ssid->ssid, pbssdesc->ssid.ssid, ssid->header.len);
+       pos += sizeof(ssid->header) + ssid->header.len;
+       ssid->header.len = cpu_to_le16(ssid->header.len);
+
+       phy = (struct mrvlietypes_phyparamset *) pos;
+       phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
+       phy->header.len = sizeof(phy->fh_ds.dsparamset);
+       memcpy(&phy->fh_ds.dsparamset,
+              &pbssdesc->phyparamset.dsparamset.currentchan,
+              sizeof(phy->fh_ds.dsparamset));
+       pos += sizeof(phy->header) + phy->header.len;
+       phy->header.len = cpu_to_le16(phy->header.len);
+
+       ss = (struct mrvlietypes_ssparamset *) pos;
+       ss->header.type = cpu_to_le16(TLV_TYPE_CF);
+       ss->header.len = sizeof(ss->cf_ibss.cfparamset);
+       pos += sizeof(ss->header) + ss->header.len;
+       ss->header.len = cpu_to_le16(ss->header.len);
+
+       rates = (struct mrvlietypes_ratesparamset *) pos;
+       rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
+
+       memcpy(&rates->rates, &pbssdesc->libertas_supported_rates, WLAN_SUPPORTED_RATES);
+
+       card_rates = libertas_supported_rates;
+       card_rates_size = sizeof(libertas_supported_rates);
+
+       if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
+                            card_rates, card_rates_size)) {
+               ret = -1;
+               goto done;
+       }
+
+       rates->header.len = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
+       adapter->curbssparams.numofrates = rates->header.len;
+
+       pos += sizeof(rates->header) + rates->header.len;
+       rates->header.len = cpu_to_le16(rates->header.len);
+
+       if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+               rsn = (struct mrvlietypes_rsnparamset *) pos;
+               rsn->header.type = (u16) adapter->wpa_ie[0];    /* WPA_IE or WPA2_IE */
+               rsn->header.type = cpu_to_le16(rsn->header.type);
+               rsn->header.len = (u16) adapter->wpa_ie[1];
+               memcpy(rsn->rsnie, &adapter->wpa_ie[2], rsn->header.len);
+               lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
+                       sizeof(rsn->header) + rsn->header.len);
+               pos += sizeof(rsn->header) + rsn->header.len;
+               rsn->header.len = cpu_to_le16(rsn->header.len);
+       }
+
+       /* update curbssparams */
+       adapter->curbssparams.channel =
+           (pbssdesc->phyparamset.dsparamset.currentchan);
+
+       /* Copy the infra. association rates into Current BSS state structure */
+       memcpy(&adapter->curbssparams.datarates, &rates->rates,
+              min_t(size_t, sizeof(adapter->curbssparams.datarates), rates->header.len));
+
+       lbs_pr_debug(1, "ASSOC_CMD: rates->header.len = %d\n", rates->header.len);
+
+       /* set IBSS field */
+       if (pbssdesc->inframode == wlan802_11infrastructure) {
+#define CAPINFO_ESS_MODE 1
+               passo->capinfo.ess = CAPINFO_ESS_MODE;
+       }
+
+       if (libertas_parse_dnld_countryinfo_11d(priv)) {
+               ret = -1;
+               goto done;
+       }
+
+       cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
+
+       /* set the capability info at last */
+       memcpy(&tmpcap, &pbssdesc->cap, sizeof(passo->capinfo));
+       tmpcap &= CAPINFO_MASK;
+       lbs_pr_debug(1, "ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+              tmpcap, CAPINFO_MASK);
+       tmpcap = cpu_to_le16(tmpcap);
+       memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
+
+      done:
+       LEAVE();
+       return ret;
+}
+
+int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+                                struct cmd_ds_command *cmd, void *pssid)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
+       int ret = 0;
+       int cmdappendsize = 0;
+       int i;
+       u16 tmpcap;
+       struct bss_descriptor *pbssdesc;
+       struct WLAN_802_11_SSID *ssid = pssid;
+
+       ENTER();
+
+       if (!adapter) {
+               ret = -1;
+               goto done;
+       }
+
+       cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
+
+       pbssdesc = &adapter->curbssparams.bssdescriptor;
+       adapter->pattemptedbssdesc = pbssdesc;
+
+       /*
+        * Fill in the parameters for 2 data structures:
+        *   1. cmd_ds_802_11_ad_hoc_start command
+        *   2. adapter->scantable[i]
+        *
+        * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
+        *   probe delay, and cap info.
+        *
+        * Firmware will fill up beacon period, DTIM, Basic rates
+        *   and operational rates.
+        */
+
+       memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
+
+       memcpy(adhs->SSID, ssid->ssid, ssid->ssidlength);
+
+       lbs_pr_debug(1, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID);
+
+       memset(pbssdesc->ssid.ssid, 0, IW_ESSID_MAX_SIZE);
+       memcpy(pbssdesc->ssid.ssid, ssid->ssid, ssid->ssidlength);
+
+       pbssdesc->ssid.ssidlength = ssid->ssidlength;
+
+       /* set the BSS type */
+       adhs->bsstype = cmd_bss_type_ibss;
+       pbssdesc->inframode = wlan802_11ibss;
+       adhs->beaconperiod = adapter->beaconperiod;
+
+       /* set Physical param set */
+#define DS_PARA_IE_ID   3
+#define DS_PARA_IE_LEN  1
+
+       adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
+       adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
+
+       WARN_ON(!adapter->adhocchannel);
+
+       lbs_pr_debug(1, "ADHOC_S_CMD: Creating ADHOC on channel %d\n",
+              adapter->adhocchannel);
+
+       adapter->curbssparams.channel = adapter->adhocchannel;
+
+       pbssdesc->channel = adapter->adhocchannel;
+       adhs->phyparamset.dsparamset.currentchan = adapter->adhocchannel;
+
+       memcpy(&pbssdesc->phyparamset,
+              &adhs->phyparamset, sizeof(union ieeetypes_phyparamset));
+
+       /* set IBSS param set */
+#define IBSS_PARA_IE_ID   6
+#define IBSS_PARA_IE_LEN  2
+
+       adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
+       adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
+       adhs->ssparamset.ibssparamset.atimwindow = adapter->atimwindow;
+       memcpy(&pbssdesc->ssparamset,
+              &adhs->ssparamset, sizeof(union IEEEtypes_ssparamset));
+
+       /* set capability info */
+       adhs->cap.ess = 0;
+       adhs->cap.ibss = 1;
+       pbssdesc->cap.ibss = 1;
+
+       /* probedelay */
+       adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
+
+       /* set up privacy in adapter->scantable[i] */
+       if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
+
+#define AD_HOC_CAP_PRIVACY_ON 1
+               lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus set, privacy to WEP\n");
+               pbssdesc->privacy = wlan802_11privfilter8021xWEP;
+               adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+       } else {
+               lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus NOT set, Setting "
+                      "privacy to ACCEPT ALL\n");
+               pbssdesc->privacy = wlan802_11privfilteracceptall;
+       }
+
+       memset(adhs->datarate, 0, sizeof(adhs->datarate));
+
+       if (adapter->adhoc_grate_enabled) {
+               memcpy(adhs->datarate, libertas_adhoc_rates_g,
+                      min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
+       } else {
+               memcpy(adhs->datarate, libertas_adhoc_rates_b,
+                      min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
+       }
+
+       /* Find the last non zero */
+       for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
+
+       adapter->curbssparams.numofrates = i;
+
+       /* Copy the ad-hoc creating rates into Current BSS state structure */
+       memcpy(&adapter->curbssparams.datarates,
+              &adhs->datarate, adapter->curbssparams.numofrates);
+
+       lbs_pr_debug(1, "ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
+              adhs->datarate[0], adhs->datarate[1],
+              adhs->datarate[2], adhs->datarate[3]);
+
+       lbs_pr_debug(1, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+       if (libertas_create_dnld_countryinfo_11d(priv)) {
+               lbs_pr_debug(1, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+               ret = -1;
+               goto done;
+       }
+
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start)
+                            + S_DS_GEN + cmdappendsize);
+
+       memcpy(&tmpcap, &adhs->cap, sizeof(u16));
+       tmpcap = cpu_to_le16(tmpcap);
+       memcpy(&adhs->cap, &tmpcap, sizeof(u16));
+
+       ret = 0;
+done:
+       LEAVE();
+       return ret;
+}
+
+int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+                               struct cmd_ds_command *cmd)
+{
+       cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
+       cmd->size = cpu_to_le16(S_DS_GEN);
+
+       return 0;
+}
+
+int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+                               struct cmd_ds_command *cmd, void *pdata_buf)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
+       struct bss_descriptor *pbssdesc = pdata_buf;
+       int cmdappendsize = 0;
+       int ret = 0;
+       u8 *card_rates;
+       int card_rates_size;
+       u16 tmpcap;
+       int i;
+
+       ENTER();
+
+       adapter->pattemptedbssdesc = pbssdesc;
+
+       cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
+
+       padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
+
+       padhocjoin->bssdescriptor.beaconperiod = pbssdesc->beaconperiod;
+
+       memcpy(&padhocjoin->bssdescriptor.BSSID,
+              &pbssdesc->macaddress, ETH_ALEN);
+
+       memcpy(&padhocjoin->bssdescriptor.SSID,
+              &pbssdesc->ssid.ssid, pbssdesc->ssid.ssidlength);
+
+       memcpy(&padhocjoin->bssdescriptor.phyparamset,
+              &pbssdesc->phyparamset, sizeof(union ieeetypes_phyparamset));
+
+       memcpy(&padhocjoin->bssdescriptor.ssparamset,
+              &pbssdesc->ssparamset, sizeof(union IEEEtypes_ssparamset));
+
+       memcpy(&tmpcap, &pbssdesc->cap, sizeof(struct ieeetypes_capinfo));
+       tmpcap &= CAPINFO_MASK;
+
+       lbs_pr_debug(1, "ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+              tmpcap, CAPINFO_MASK);
+       memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
+              sizeof(struct ieeetypes_capinfo));
+
+       /* information on BSSID descriptor passed to FW */
+    lbs_pr_debug(1,
+              "ADHOC_J_CMD: BSSID = %2x-%2x-%2x-%2x-%2x-%2x, SSID = %s\n",
+              padhocjoin->bssdescriptor.BSSID[0],
+              padhocjoin->bssdescriptor.BSSID[1],
+              padhocjoin->bssdescriptor.BSSID[2],
+              padhocjoin->bssdescriptor.BSSID[3],
+              padhocjoin->bssdescriptor.BSSID[4],
+              padhocjoin->bssdescriptor.BSSID[5],
+              padhocjoin->bssdescriptor.SSID);
+
+       lbs_pr_debug(1, "ADHOC_J_CMD: Data Rate = %x\n",
+              (u32) padhocjoin->bssdescriptor.datarates);
+
+       /* failtimeout */
+       padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+
+       /* probedelay */
+       padhocjoin->probedelay =
+           cpu_to_le16(cmd_scan_probe_delay_time);
+
+       /* Copy Data rates from the rates recorded in scan response */
+       memset(padhocjoin->bssdescriptor.datarates, 0,
+              sizeof(padhocjoin->bssdescriptor.datarates));
+       memcpy(padhocjoin->bssdescriptor.datarates, pbssdesc->datarates,
+              min(sizeof(padhocjoin->bssdescriptor.datarates),
+                  sizeof(pbssdesc->datarates)));
+
+       card_rates = libertas_supported_rates;
+       card_rates_size = sizeof(libertas_supported_rates);
+
+       adapter->curbssparams.channel = pbssdesc->channel;
+
+       if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
+                            sizeof(padhocjoin->bssdescriptor.datarates),
+                            card_rates, card_rates_size)) {
+               lbs_pr_debug(1, "ADHOC_J_CMD: get_common_rates returns error.\n");
+               ret = -1;
+               goto done;
+       }
+
+       /* Find the last non zero */
+       for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
+            && padhocjoin->bssdescriptor.datarates[i]; i++) ;
+
+       adapter->curbssparams.numofrates = i;
+
+       /*
+        * Copy the adhoc joining rates to Current BSS State structure
+        */
+       memcpy(adapter->curbssparams.datarates,
+              padhocjoin->bssdescriptor.datarates,
+              adapter->curbssparams.numofrates);
+
+       padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
+           cpu_to_le16(pbssdesc->atimwindow);
+
+       if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
+               padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+       }
+
+       if (adapter->psmode == wlan802_11powermodemax_psp) {
+               /* wake up first */
+               enum WLAN_802_11_POWER_MODE Localpsmode;
+
+               Localpsmode = wlan802_11powermodecam;
+               ret = libertas_prepare_and_send_command(priv,
+                                           cmd_802_11_ps_mode,
+                                           cmd_act_set,
+                                           0, 0, &Localpsmode);
+
+               if (ret) {
+                       ret = -1;
+                       goto done;
+               }
+       }
+
+       if (libertas_parse_dnld_countryinfo_11d(priv)) {
+               ret = -1;
+               goto done;
+       }
+
+       cmd->size =
+           cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join)
+                            + S_DS_GEN + cmdappendsize);
+
+       memcpy(&tmpcap, &padhocjoin->bssdescriptor.cap,
+              sizeof(struct ieeetypes_capinfo));
+       tmpcap = cpu_to_le16(tmpcap);
+
+       memcpy(&padhocjoin->bssdescriptor.cap,
+              &tmpcap, sizeof(struct ieeetypes_capinfo));
+
+      done:
+       LEAVE();
+       return ret;
+}
+
+int libertas_ret_80211_associate(wlan_private * priv,
+                             struct cmd_ds_command *resp)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       union iwreq_data wrqu;
+       struct ieeetypes_assocrsp *passocrsp;
+       struct bss_descriptor *pbssdesc;
+
+       ENTER();
+
+       passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
+
+       if (passocrsp->statuscode) {
+
+               libertas_mac_event_disconnected(priv);
+
+        lbs_pr_debug(1,
+                      "ASSOC_RESP: Association failed, status code = %d\n",
+                      passocrsp->statuscode);
+
+               ret = -1;
+               goto done;
+       }
+
+       lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
+               le16_to_cpu(resp->size) - S_DS_GEN);
+
+       /* Send a Media Connected event, according to the Spec */
+       adapter->connect_status = libertas_connected;
+
+       /* Set the attempted BSSID Index to current */
+       pbssdesc = adapter->pattemptedbssdesc;
+
+       lbs_pr_debug(1, "ASSOC_RESP: %s\n", pbssdesc->ssid.ssid);
+
+       /* Set the new SSID to current SSID */
+       memcpy(&adapter->curbssparams.ssid,
+              &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
+
+       /* Set the new BSSID (AP's MAC address) to current BSSID */
+       memcpy(adapter->curbssparams.bssid,
+              pbssdesc->macaddress, ETH_ALEN);
+
+       /* Make a copy of current BSSID descriptor */
+       memcpy(&adapter->curbssparams.bssdescriptor,
+              pbssdesc, sizeof(struct bss_descriptor));
+
+       lbs_pr_debug(1, "ASSOC_RESP: currentpacketfilter is %x\n",
+              adapter->currentpacketfilter);
+
+       adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
+       adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
+
+       memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
+       memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
+       adapter->nextSNRNF = 0;
+       adapter->numSNRNF = 0;
+
+       netif_carrier_on(priv->wlan_dev.netdev);
+       netif_wake_queue(priv->wlan_dev.netdev);
+
+       lbs_pr_debug(1, "ASSOC_RESP: Associated \n");
+
+       memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+      done:
+       LEAVE();
+       return ret;
+}
+
+int libertas_ret_80211_disassociate(wlan_private * priv,
+                                struct cmd_ds_command *resp)
+{
+       ENTER();
+
+       libertas_mac_event_disconnected(priv);
+
+       LEAVE();
+       return 0;
+}
+
+int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+                                struct cmd_ds_command *resp)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       u16 command = le16_to_cpu(resp->command);
+       u16 result = le16_to_cpu(resp->result);
+       struct cmd_ds_802_11_ad_hoc_result *padhocresult;
+       union iwreq_data wrqu;
+       struct bss_descriptor *pbssdesc;
+
+       ENTER();
+
+       padhocresult = &resp->params.result;
+
+       lbs_pr_debug(1, "ADHOC_S_RESP: size = %d\n", le16_to_cpu(resp->size));
+       lbs_pr_debug(1, "ADHOC_S_RESP: command = %x\n", command);
+       lbs_pr_debug(1, "ADHOC_S_RESP: result = %x\n", result);
+
+       pbssdesc = adapter->pattemptedbssdesc;
+
+       /*
+        * Join result code 0 --> SUCCESS
+        */
+       if (result) {
+               lbs_pr_debug(1, "ADHOC_RESP failed\n");
+               if (adapter->connect_status == libertas_connected) {
+                       libertas_mac_event_disconnected(priv);
+               }
+
+               memset(&adapter->curbssparams.bssdescriptor,
+                      0x00, sizeof(adapter->curbssparams.bssdescriptor));
+
+               LEAVE();
+               return -1;
+       }
+
+       /*
+        * Now the join cmd should be successful
+        * If BSSID has changed use SSID to compare instead of BSSID
+        */
+       lbs_pr_debug(1, "ADHOC_J_RESP  %s\n", pbssdesc->ssid.ssid);
+
+       /* Send a Media Connected event, according to the Spec */
+       adapter->connect_status = libertas_connected;
+
+       if (command == cmd_ret_802_11_ad_hoc_start) {
+               /* Update the created network descriptor with the new BSSID */
+               memcpy(pbssdesc->macaddress,
+                      padhocresult->BSSID, ETH_ALEN);
+       } else {
+
+               /* Make a copy of current BSSID descriptor, only needed for join since
+                *   the current descriptor is already being used for adhoc start
+                */
+               memmove(&adapter->curbssparams.bssdescriptor,
+                       pbssdesc, sizeof(struct bss_descriptor));
+       }
+
+       /* Set the BSSID from the joined/started descriptor */
+       memcpy(&adapter->curbssparams.bssid,
+              pbssdesc->macaddress, ETH_ALEN);
+
+       /* Set the new SSID to current SSID */
+       memcpy(&adapter->curbssparams.ssid,
+              &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
+
+       netif_carrier_on(priv->wlan_dev.netdev);
+       netif_wake_queue(priv->wlan_dev.netdev);
+
+       memset(&wrqu, 0, sizeof(wrqu));
+       memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+       lbs_pr_debug(1, "ADHOC_RESP: - Joined/Started Ad Hoc\n");
+       lbs_pr_debug(1, "ADHOC_RESP: channel = %d\n", adapter->adhocchannel);
+       lbs_pr_debug(1, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+              padhocresult->BSSID[0], padhocresult->BSSID[1],
+              padhocresult->BSSID[2], padhocresult->BSSID[3],
+              padhocresult->BSSID[4], padhocresult->BSSID[5]);
+
+       LEAVE();
+       return ret;
+}
+
+int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+                               struct cmd_ds_command *resp)
+{
+       ENTER();
+
+       libertas_mac_event_disconnected(priv);
+
+       LEAVE();
+       return 0;
+}
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
new file mode 100644 (file)
index 0000000..8efa245
--- /dev/null
@@ -0,0 +1,64 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+  * Interface for the wlan infrastructure and adhoc join routines
+  *
+  * Driver interface functions and type declarations for the join module
+  *   implemented in wlan_join.c.  Process all start/join requests for
+  *   both adhoc and infrastructure networks
+  */
+#ifndef _WLAN_JOIN_H
+#define _WLAN_JOIN_H
+
+#include "defs.h"
+
+struct cmd_ds_command;
+extern int libertas_cmd_80211_authenticate(wlan_private * priv,
+                                       struct cmd_ds_command *cmd,
+                                       void *pdata_buf);
+extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+                                      struct cmd_ds_command *cmd,
+                                      void *pdata_buf);
+extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+                                      struct cmd_ds_command *cmd);
+extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+                                       struct cmd_ds_command *cmd,
+                                       void *pssid);
+extern int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+                                         struct cmd_ds_command *cmd);
+extern int libertas_cmd_80211_associate(wlan_private * priv,
+                                    struct cmd_ds_command *cmd,
+                                    void *pdata_buf);
+
+extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+                                       struct cmd_ds_command *resp);
+extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+                                      struct cmd_ds_command *resp);
+extern int libertas_ret_80211_disassociate(wlan_private * priv,
+                                       struct cmd_ds_command *resp);
+extern int libertas_ret_80211_associate(wlan_private * priv,
+                                    struct cmd_ds_command *resp);
+
+extern int libertas_idle_on(wlan_private * priv);
+extern int libertas_idle_off(wlan_private * priv);
+
+extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+extern int libertas_reassociation_thread(void *data);
+
+struct WLAN_802_11_SSID;
+struct bss_descriptor;
+
+extern int libertas_start_adhoc_network(wlan_private * priv,
+                            struct WLAN_802_11_SSID *adhocssid);
+extern int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor *pbssdesc);
+extern int libertas_stop_adhoc_network(wlan_private * priv);
+
+extern int libertas_send_deauthentication(wlan_private * priv);
+extern int libertas_send_deauth(wlan_private * priv);
+
+extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+
+int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc);
+
+#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
new file mode 100644 (file)
index 0000000..dcbf102
--- /dev/null
@@ -0,0 +1,1258 @@
+/**
+  * This file contains the major functions in WLAN
+  * driver. It includes init, exit, open, close and main
+  * thread etc..
+  */
+
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "dev.h"
+#include "fw.h"
+#include "wext.h"
+#include "debugfs.h"
+#include "assoc.h"
+
+#ifdef ENABLE_PM
+static struct pm_dev *wlan_pm_dev = NULL;
+#endif
+
+#define WLAN_TX_PWR_DEFAULT            20      /*100mW */
+#define WLAN_TX_PWR_US_DEFAULT         20      /*100mW */
+#define WLAN_TX_PWR_JP_DEFAULT         16      /*50mW */
+#define WLAN_TX_PWR_FR_DEFAULT         20      /*100mW */
+#define WLAN_TX_PWR_EMEA_DEFAULT       20      /*100mW */
+
+/* Format { channel, frequency (MHz), maxtxpower } */
+/* band: 'B/G', region: USA FCC/Canada IC */
+static struct chan_freq_power channel_freq_power_US_BG[] = {
+       {1, 2412, WLAN_TX_PWR_US_DEFAULT},
+       {2, 2417, WLAN_TX_PWR_US_DEFAULT},
+       {3, 2422, WLAN_TX_PWR_US_DEFAULT},
+       {4, 2427, WLAN_TX_PWR_US_DEFAULT},
+       {5, 2432, WLAN_TX_PWR_US_DEFAULT},
+       {6, 2437, WLAN_TX_PWR_US_DEFAULT},
+       {7, 2442, WLAN_TX_PWR_US_DEFAULT},
+       {8, 2447, WLAN_TX_PWR_US_DEFAULT},
+       {9, 2452, WLAN_TX_PWR_US_DEFAULT},
+       {10, 2457, WLAN_TX_PWR_US_DEFAULT},
+       {11, 2462, WLAN_TX_PWR_US_DEFAULT}
+};
+
+/* band: 'B/G', region: Europe ETSI */
+static struct chan_freq_power channel_freq_power_EU_BG[] = {
+       {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
+       {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
+       {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
+       {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
+       {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
+       {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
+       {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
+       {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
+       {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
+       {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
+       {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
+       {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
+       {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
+};
+
+/* band: 'B/G', region: Spain */
+static struct chan_freq_power channel_freq_power_SPN_BG[] = {
+       {10, 2457, WLAN_TX_PWR_DEFAULT},
+       {11, 2462, WLAN_TX_PWR_DEFAULT}
+};
+
+/* band: 'B/G', region: France */
+static struct chan_freq_power channel_freq_power_FR_BG[] = {
+       {10, 2457, WLAN_TX_PWR_FR_DEFAULT},
+       {11, 2462, WLAN_TX_PWR_FR_DEFAULT},
+       {12, 2467, WLAN_TX_PWR_FR_DEFAULT},
+       {13, 2472, WLAN_TX_PWR_FR_DEFAULT}
+};
+
+/* band: 'B/G', region: Japan */
+static struct chan_freq_power channel_freq_power_JPN_BG[] = {
+       {1, 2412, WLAN_TX_PWR_JP_DEFAULT},
+       {2, 2417, WLAN_TX_PWR_JP_DEFAULT},
+       {3, 2422, WLAN_TX_PWR_JP_DEFAULT},
+       {4, 2427, WLAN_TX_PWR_JP_DEFAULT},
+       {5, 2432, WLAN_TX_PWR_JP_DEFAULT},
+       {6, 2437, WLAN_TX_PWR_JP_DEFAULT},
+       {7, 2442, WLAN_TX_PWR_JP_DEFAULT},
+       {8, 2447, WLAN_TX_PWR_JP_DEFAULT},
+       {9, 2452, WLAN_TX_PWR_JP_DEFAULT},
+       {10, 2457, WLAN_TX_PWR_JP_DEFAULT},
+       {11, 2462, WLAN_TX_PWR_JP_DEFAULT},
+       {12, 2467, WLAN_TX_PWR_JP_DEFAULT},
+       {13, 2472, WLAN_TX_PWR_JP_DEFAULT},
+       {14, 2484, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/**
+ * the structure for channel, frequency and power
+ */
+struct region_cfp_table {
+       u8 region;
+       struct chan_freq_power *cfp_BG;
+       int cfp_no_BG;
+};
+
+/**
+ * the structure for the mapping between region and CFP
+ */
+static struct region_cfp_table region_cfp_table[] = {
+       {0x10,                  /*US FCC */
+        channel_freq_power_US_BG,
+        sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+        }
+       ,
+       {0x20,                  /*CANADA IC */
+        channel_freq_power_US_BG,
+        sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+        }
+       ,
+       {0x30, /*EU*/ channel_freq_power_EU_BG,
+        sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power),
+        }
+       ,
+       {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
+        sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power),
+        }
+       ,
+       {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
+        sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power),
+        }
+       ,
+       {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
+        sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power),
+        }
+       ,
+/*Add new region here */
+};
+
+/**
+ * the rates supported by the card
+ */
+u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
+    { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+       0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
+
+/**
+ * the rates supported
+ */
+u8 libertas_supported_rates[G_SUPPORTED_RATES] =
+    { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0 };
+
+/**
+ * the rates supported for ad-hoc G mode
+ */
+u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] =
+    { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0 };
+
+/**
+ * the rates supported for ad-hoc B mode
+ */
+u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 };
+
+/**
+ * the global variable of a pointer to wlan_private
+ * structure variable
+ */
+static wlan_private *wlanpriv = NULL;
+
+#define MAX_DEVS 5
+static struct net_device *libertas_devs[MAX_DEVS];
+static int libertas_found = 0;
+
+/**
+ * the table to keep region code
+ */
+u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+    { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
+
+static u8 *default_fw_name = "usb8388.bin";
+
+/**
+ * Attributes exported through sysfs
+ */
+
+/**
+ * @brief Get function for sysfs attribute libertas_mpp
+ */
+static ssize_t libertas_mpp_get(struct device * dev,
+               struct device_attribute *attr, char * buf) {
+       struct cmd_ds_mesh_access mesh_access;
+
+       memset(&mesh_access, 0, sizeof(mesh_access));
+       libertas_prepare_and_send_command(to_net_dev(dev)->priv,
+                       cmd_mesh_access,
+                       cmd_act_mesh_get_mpp,
+                       cmd_option_waitforrsp, 0, (void *)&mesh_access);
+
+       return snprintf(buf, 3, "%d\n", mesh_access.data[0]);
+}
+
+/**
+ * @brief Set function for sysfs attribute libertas_mpp
+ */
+static ssize_t libertas_mpp_set(struct device * dev,
+               struct device_attribute *attr, const char * buf, size_t count) {
+       struct cmd_ds_mesh_access mesh_access;
+
+
+       memset(&mesh_access, 0, sizeof(mesh_access));
+       sscanf(buf, "%d", &(mesh_access.data[0]));
+       libertas_prepare_and_send_command((to_net_dev(dev))->priv,
+                       cmd_mesh_access,
+                       cmd_act_mesh_set_mpp,
+                       cmd_option_waitforrsp, 0, (void *)&mesh_access);
+       return strlen(buf);
+}
+
+/**
+ * libertas_mpp attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/libertas-mpp)
+ */
+static DEVICE_ATTR(libertas_mpp, 0644, libertas_mpp_get,
+               libertas_mpp_set );
+
+/**
+ *  @brief Check if the device can be open and wait if necessary.
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return       0
+ *
+ * For USB adapter, on some systems the device open handler will be
+ * called before FW ready. Use the following flag check and wait
+ * function to work around the issue.
+ *
+ */
+static int pre_open_check(struct net_device *dev) {
+       wlan_private *priv = (wlan_private *) dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       int i = 0;
+
+       while (!adapter->fw_ready && i < 20) {
+               i++;
+               msleep_interruptible(100);
+       }
+       if (!adapter->fw_ready) {
+               lbs_pr_info("FW not ready, pre_open_check() return failure\n");
+               LEAVE();
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ *  @brief This function opens the device
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return       0
+ */
+static int wlan_dev_open(struct net_device *dev)
+{
+       wlan_private *priv = (wlan_private *) dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+
+       priv->open = 1;
+
+       if (adapter->connect_status == libertas_connected) {
+               netif_carrier_on(priv->wlan_dev.netdev);
+       } else
+               netif_carrier_off(priv->wlan_dev.netdev);
+
+       LEAVE();
+       return 0;
+}
+/**
+ *  @brief This function opens the mshX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return       0
+ */
+static int mesh_open(struct net_device *dev)
+{
+       wlan_private *priv = (wlan_private *) dev->priv ;
+
+       if(pre_open_check(dev) == -1)
+               return -1;
+       priv->mesh_open = 1 ;
+       netif_start_queue(priv->mesh_dev);
+       if (priv->infra_open == 0)
+               return wlan_dev_open(priv->wlan_dev.netdev) ;
+       return 0;
+}
+
+/**
+ *  @brief This function opens the ethX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return       0
+ */
+static int wlan_open(struct net_device *dev)
+{
+       wlan_private *priv = (wlan_private *) dev->priv ;
+
+       if(pre_open_check(dev) == -1)
+               return -1;
+       priv->infra_open = 1 ;
+       netif_wake_queue(priv->wlan_dev.netdev);
+       if (priv->open == 0)
+               return wlan_dev_open(priv->wlan_dev.netdev) ;
+       return 0;
+}
+
+static int wlan_dev_close(struct net_device *dev)
+{
+       wlan_private *priv = dev->priv;
+
+       ENTER();
+
+       netif_carrier_off(priv->wlan_dev.netdev);
+       priv->open = 0;
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief This function closes the mshX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return       0
+ */
+static int mesh_close(struct net_device *dev)
+{
+       wlan_private *priv = (wlan_private *) (dev->priv);
+
+       priv->mesh_open = 0;
+       netif_stop_queue(priv->mesh_dev);
+       if (priv->infra_open == 0)
+               return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
+       else
+               return 0;
+}
+
+/**
+ *  @brief This function closes the ethX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return       0
+ */
+static int wlan_close(struct net_device *dev) {
+       wlan_private *priv = (wlan_private *) dev->priv;
+
+       netif_stop_queue(priv->wlan_dev.netdev);
+       priv->infra_open = 0;
+       if (priv->mesh_open == 0)
+               return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
+       else
+               return 0;
+}
+
+
+#ifdef ENABLE_PM
+
+/**
+ *  @brief This function is a callback function. it is called by
+ *  kernel to enter or exit power saving mode.
+ *
+ *  @param pmdev   A pointer to pm_dev
+ *  @param pmreq   pm_request_t
+ *  @param pmdata  A pointer to pmdata
+ *  @return       0 or -1
+ */
+static int wlan_pm_callback(struct pm_dev *pmdev, pm_request_t pmreq,
+                           void *pmdata)
+{
+       wlan_private *priv = wlanpriv;
+       wlan_adapter *adapter = priv->adapter;
+       struct net_device *dev = priv->wlan_dev.netdev;
+
+       lbs_pr_debug(1, "WPRM_PM_CALLBACK: pmreq = %d.\n", pmreq);
+
+       switch (pmreq) {
+       case PM_SUSPEND:
+               lbs_pr_debug(1, "WPRM_PM_CALLBACK: enter PM_SUSPEND.\n");
+
+               /* in associated mode */
+               if (adapter->connect_status == libertas_connected) {
+                       if ((adapter->psstate != PS_STATE_SLEEP)
+                           ) {
+                               lbs_pr_debug(1,
+                                      "wlan_pm_callback: can't enter sleep mode\n");
+                               return -1;
+                       } else {
+
+                               /*
+                                * Detach the network interface
+                                * if the network is running
+                                */
+                               if (netif_running(dev)) {
+                                       netif_device_detach(dev);
+                                       lbs_pr_debug(1,
+                                              "netif_device_detach().\n");
+                               }
+                               libertas_sbi_suspend(priv);
+                       }
+                       break;
+               }
+
+               /* in non associated mode */
+
+               /*
+                * Detach the network interface
+                * if the network is running
+                */
+               if (netif_running(dev))
+                       netif_device_detach(dev);
+
+               /*
+                * Storing and restoring of the regs be taken care
+                * at the driver rest will be done at wlan driver
+                * this makes driver independent of the card
+                */
+
+               libertas_sbi_suspend(priv);
+
+               break;
+
+       case PM_RESUME:
+               /* in associated mode */
+               if (adapter->connect_status == libertas_connected) {
+                       {
+                               /*
+                                * Bring the inteface up first
+                                * This case should not happen still ...
+                                */
+                               libertas_sbi_resume(priv);
+
+                               /*
+                                * Attach the network interface
+                                * if the network is running
+                                */
+                               if (netif_running(dev)) {
+                                       netif_device_attach(dev);
+                                       lbs_pr_debug(1,
+                                              "after netif_device_attach().\n");
+                               }
+                               lbs_pr_debug(1,
+                                      "After netif attach, in associated mode.\n");
+                       }
+                       break;
+               }
+
+               /* in non associated mode */
+
+               /*
+                * Bring the inteface up first
+                * This case should not happen still ...
+                */
+
+               libertas_sbi_resume(priv);
+
+               if (netif_running(dev))
+                       netif_device_attach(dev);
+
+               lbs_pr_debug(1, "after netif attach, in NON associated mode.\n");
+               break;
+       }
+
+       return 0;
+}
+#endif                         /* ENABLE_PM */
+
+static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+
+       ENTER();
+
+       if (priv->wlan_dev.dnld_sent || priv->adapter->TxLockFlag) {
+               priv->stats.tx_dropped++;
+               goto done;
+       }
+
+       netif_stop_queue(priv->wlan_dev.netdev);
+
+       if (libertas_process_tx(priv, skb) == 0)
+               dev->trans_start = jiffies;
+done:
+       LEAVE();
+       return ret;
+}
+
+/**
+ * @brief Mark mesh packets and handover them to wlan_hard_start_xmit
+ *
+ */
+static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       wlan_private *priv = dev->priv;
+       ENTER();
+       SET_MESH_FRAME(skb);
+       LEAVE();
+
+       return wlan_hard_start_xmit(skb, priv->wlan_dev.netdev);
+}
+
+/**
+ * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
+ *
+ */
+static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+       ENTER();
+       UNSET_MESH_FRAME(skb);
+       LEAVE();
+       return wlan_hard_start_xmit(skb, dev);
+}
+
+static void wlan_tx_timeout(struct net_device *dev)
+{
+       wlan_private *priv = (wlan_private *) dev->priv;
+
+       ENTER();
+
+       lbs_pr_err("tx watch dog timeout!\n");
+
+       priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+       dev->trans_start = jiffies;
+
+       if (priv->adapter->currenttxskb) {
+               if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+                       /* If we are here, we have not received feedback from
+                          the previous packet.  Assume TX_FAIL and move on. */
+                       priv->adapter->eventcause = 0x01000000;
+                       libertas_send_tx_feedback(priv);
+               } else
+                       wake_up_interruptible(&priv->mainthread.waitq);
+       } else if (priv->adapter->connect_status == libertas_connected)
+               netif_wake_queue(priv->wlan_dev.netdev);
+
+       LEAVE();
+}
+
+/**
+ *  @brief This function returns the network statistics
+ *
+ *  @param dev     A pointer to wlan_private structure
+ *  @return       A pointer to net_device_stats structure
+ */
+static struct net_device_stats *wlan_get_stats(struct net_device *dev)
+{
+       wlan_private *priv = (wlan_private *) dev->priv;
+
+       return &priv->stats;
+}
+
+static int wlan_set_mac_address(struct net_device *dev, void *addr)
+{
+       int ret = 0;
+       wlan_private *priv = (wlan_private *) dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct sockaddr *phwaddr = addr;
+
+       ENTER();
+
+       memset(adapter->current_addr, 0, ETH_ALEN);
+
+       /* dev->dev_addr is 8 bytes */
+       lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+       lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+       memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
+                                   cmd_act_set,
+                                   cmd_option_waitforrsp, 0, NULL);
+
+       if (ret) {
+               lbs_pr_debug(1, "set mac address failed.\n");
+               ret = -1;
+               goto done;
+       }
+
+       lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+       memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
+       memcpy(((wlan_private *) dev->priv)->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+
+done:
+       LEAVE();
+       return ret;
+}
+
+static int wlan_copy_multicast_address(wlan_adapter * adapter,
+                                    struct net_device *dev)
+{
+       int i = 0;
+       struct dev_mc_list *mcptr = dev->mc_list;
+
+       for (i = 0; i < dev->mc_count; i++) {
+               memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
+               mcptr = mcptr->next;
+       }
+
+       return i;
+
+}
+
+static void wlan_set_multicast_list(struct net_device *dev)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       int oldpacketfilter;
+
+       ENTER();
+
+       oldpacketfilter = adapter->currentpacketfilter;
+
+       if (dev->flags & IFF_PROMISC) {
+               lbs_pr_debug(1, "enable Promiscuous mode\n");
+               adapter->currentpacketfilter |=
+                   cmd_act_mac_promiscuous_enable;
+               adapter->currentpacketfilter &=
+                   ~(cmd_act_mac_all_multicast_enable |
+                     cmd_act_mac_multicast_enable);
+       } else {
+               /* Multicast */
+               adapter->currentpacketfilter &=
+                   ~cmd_act_mac_promiscuous_enable;
+
+               if (dev->flags & IFF_ALLMULTI || dev->mc_count >
+                   MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+                       lbs_pr_debug(1, "Enabling All Multicast!\n");
+                       adapter->currentpacketfilter |=
+                           cmd_act_mac_all_multicast_enable;
+                       adapter->currentpacketfilter &=
+                           ~cmd_act_mac_multicast_enable;
+               } else {
+                       adapter->currentpacketfilter &=
+                           ~cmd_act_mac_all_multicast_enable;
+
+                       if (!dev->mc_count) {
+                               lbs_pr_debug(1, "No multicast addresses - "
+                                      "disabling multicast!\n");
+                               adapter->currentpacketfilter &=
+                                   ~cmd_act_mac_multicast_enable;
+                       } else {
+                               int i;
+
+                               adapter->currentpacketfilter |=
+                                   cmd_act_mac_multicast_enable;
+
+                               adapter->nr_of_multicastmacaddr =
+                                   wlan_copy_multicast_address(adapter, dev);
+
+                               lbs_pr_debug(1, "Multicast addresses: %d\n",
+                                      dev->mc_count);
+
+                               for (i = 0; i < dev->mc_count; i++) {
+                                       lbs_pr_debug(1, "Multicast address %d:"
+                                              "%x %x %x %x %x %x\n", i,
+                                              adapter->multicastlist[i][0],
+                                              adapter->multicastlist[i][1],
+                                              adapter->multicastlist[i][2],
+                                              adapter->multicastlist[i][3],
+                                              adapter->multicastlist[i][4],
+                                              adapter->multicastlist[i][5]);
+                               }
+                               /* set multicast addresses to firmware */
+                               libertas_prepare_and_send_command(priv,
+                                                     cmd_mac_multicast_adr,
+                                                     cmd_act_set, 0, 0,
+                                                     NULL);
+                       }
+               }
+       }
+
+       if (adapter->currentpacketfilter != oldpacketfilter) {
+               libertas_set_mac_packet_filter(priv);
+       }
+
+       LEAVE();
+}
+
+/**
+ *  @brief This function hanldes the major job in WLAN driver.
+ *  it handles the event generated by firmware, rx data received
+ *  from firmware and tx data sent from kernel.
+ *
+ *  @param data    A pointer to wlan_thread structure
+ *  @return       0
+ */
+static int wlan_service_main_thread(void *data)
+{
+       struct wlan_thread *thread = data;
+       wlan_private *priv = thread->priv;
+       wlan_adapter *adapter = priv->adapter;
+       wait_queue_t wait;
+       u8 ireg = 0;
+
+       ENTER();
+
+       wlan_activate_thread(thread);
+
+       init_waitqueue_entry(&wait, current);
+
+       for (;;) {
+               lbs_pr_debug(1, "main-thread 111: intcounter=%d "
+                      "currenttxskb=%p dnld_sent=%d\n",
+                      adapter->intcounter,
+                      adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+               add_wait_queue(&thread->waitq, &wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+               spin_lock_irq(&adapter->driver_lock);
+               if ((adapter->psstate == PS_STATE_SLEEP) ||
+                   (!adapter->intcounter
+                    && (priv->wlan_dev.dnld_sent || adapter->cur_cmd ||
+                        list_empty(&adapter->cmdpendingq)))) {
+                       lbs_pr_debug(1,
+                              "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
+                              adapter->connect_status, adapter->intcounter,
+                              adapter->psmode, adapter->psstate);
+                       spin_unlock_irq(&adapter->driver_lock);
+                       schedule();
+               } else
+                       spin_unlock_irq(&adapter->driver_lock);
+
+
+               lbs_pr_debug(1,
+                      "main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
+                      "dnld_sent=%d\n", adapter->intcounter,
+                      adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+               set_current_state(TASK_RUNNING);
+               remove_wait_queue(&thread->waitq, &wait);
+               try_to_freeze();
+
+               lbs_pr_debug(1, "main-thread 333: intcounter=%d currenttxskb=%p "
+                      "dnld_sent=%d\n",
+                      adapter->intcounter,
+                      adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+               if (kthread_should_stop()
+                   || adapter->surpriseremoved) {
+                       lbs_pr_debug(1,
+                              "main-thread: break from main thread: surpriseremoved=0x%x\n",
+                              adapter->surpriseremoved);
+                       break;
+               }
+
+
+               spin_lock_irq(&adapter->driver_lock);
+               if (adapter->intcounter) {
+                       u8 int_status;
+                       adapter->intcounter = 0;
+                       int_status = libertas_sbi_get_int_status(priv, &ireg);
+
+                       if (int_status) {
+                               lbs_pr_debug(1,
+                                      "main-thread: reading HOST_INT_STATUS_REG failed\n");
+                               spin_unlock_irq(&adapter->driver_lock);
+                               continue;
+                       }
+                       adapter->hisregcpy |= ireg;
+               }
+
+               lbs_pr_debug(1, "main-thread 444: intcounter=%d currenttxskb=%p "
+                      "dnld_sent=%d\n",
+                      adapter->intcounter,
+                      adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+               /* command response? */
+               if (adapter->hisregcpy & his_cmdupldrdy) {
+                       lbs_pr_debug(1, "main-thread: cmd response ready.\n");
+
+                       adapter->hisregcpy &= ~his_cmdupldrdy;
+                       spin_unlock_irq(&adapter->driver_lock);
+                       libertas_process_rx_command(priv);
+                       spin_lock_irq(&adapter->driver_lock);
+               }
+
+               /* Any Card Event */
+               if (adapter->hisregcpy & his_cardevent) {
+                       lbs_pr_debug(1, "main-thread: Card Event Activity.\n");
+
+                       adapter->hisregcpy &= ~his_cardevent;
+
+                       if (libertas_sbi_read_event_cause(priv)) {
+                               lbs_pr_alert(
+                                      "main-thread: libertas_sbi_read_event_cause failed.\n");
+                               spin_unlock_irq(&adapter->driver_lock);
+                               continue;
+                       }
+                       spin_unlock_irq(&adapter->driver_lock);
+                       libertas_process_event(priv);
+               } else
+                       spin_unlock_irq(&adapter->driver_lock);
+
+               /* Check if we need to confirm Sleep Request received previously */
+               if (adapter->psstate == PS_STATE_PRE_SLEEP) {
+                       if (!priv->wlan_dev.dnld_sent && !adapter->cur_cmd) {
+                               if (adapter->connect_status ==
+                                   libertas_connected) {
+                                       lbs_pr_debug(1,
+                                              "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
+                                              "dnld_sent=%d cur_cmd=%p, confirm now\n",
+                                              adapter->intcounter,
+                                              adapter->currenttxskb,
+                                              priv->wlan_dev.dnld_sent,
+                                              adapter->cur_cmd);
+
+                                       libertas_ps_confirm_sleep(priv,
+                                                      (u16) adapter->psmode);
+                               } else {
+                                       /* workaround for firmware sending
+                                        * deauth/linkloss event immediately
+                                        * after sleep request, remove this
+                                        * after firmware fixes it
+                                        */
+                                       adapter->psstate = PS_STATE_AWAKE;
+                                       lbs_pr_alert(
+                                              "main-thread: ignore PS_SleepConfirm in non-connected state\n");
+                               }
+                       }
+               }
+
+               /* The PS state is changed during processing of Sleep Request
+                * event above
+                */
+               if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
+                   (priv->adapter->psstate == PS_STATE_PRE_SLEEP))
+                       continue;
+
+               /* Execute the next command */
+               if (!priv->wlan_dev.dnld_sent && !priv->adapter->cur_cmd)
+                       libertas_execute_next_command(priv);
+
+               /* Wake-up command waiters which can't sleep in
+                * libertas_prepare_and_send_command
+                */
+               if (!adapter->nr_cmd_pending)
+                       wake_up_all(&adapter->cmd_pending);
+
+               libertas_tx_runqueue(priv);
+       }
+
+       del_timer(&adapter->command_timer);
+       adapter->nr_cmd_pending = 0;
+       wake_up_all(&adapter->cmd_pending);
+       wlan_deactivate_thread(thread);
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the wlan_priv and initialize the device.
+ *
+ *  @param card    A pointer to card
+ *  @return       A pointer to wlan_private structure
+ */
+wlan_private *wlan_add_card(void *card)
+{
+       struct net_device *dev = NULL;
+       struct net_device *mesh_dev = NULL;
+       wlan_private *priv = NULL;
+
+       ENTER();
+
+       /* Allocate an Ethernet device and register it */
+       if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
+               lbs_pr_alert( "Init ethernet device failed!\n");
+               return NULL;
+       }
+
+       priv = dev->priv;
+
+       /* allocate buffer for wlan_adapter */
+       if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
+               lbs_pr_alert( "Allocate buffer for wlan_adapter failed!\n");
+               goto err_kmalloc;
+       }
+
+       /* Allocate a virtual mesh device */
+       if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) {
+               lbs_pr_debug(1, "Init ethernet device failed!\n");
+               return NULL;
+       }
+
+       /* Both intervaces share the priv structure */
+       mesh_dev->priv = priv;
+
+       /* init wlan_adapter */
+       memset(priv->adapter, 0, sizeof(wlan_adapter));
+
+       priv->wlan_dev.netdev = dev;
+       priv->wlan_dev.card = card;
+       priv->mesh_open = 0;
+       priv->infra_open = 0;
+       priv->mesh_dev = mesh_dev;
+       wlanpriv = priv;
+
+       SET_MODULE_OWNER(dev);
+       SET_MODULE_OWNER(mesh_dev);
+
+       /* Setup the OS Interface to our functions */
+       dev->open = wlan_open;
+       dev->hard_start_xmit = wlan_pre_start_xmit;
+       dev->stop = wlan_close;
+       dev->do_ioctl = libertas_do_ioctl;
+       dev->set_mac_address = wlan_set_mac_address;
+       mesh_dev->open = mesh_open;
+       mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
+       mesh_dev->stop = mesh_close;
+       mesh_dev->do_ioctl = libertas_do_ioctl;
+       memcpy(mesh_dev->dev_addr, wlanpriv->wlan_dev.netdev->dev_addr,
+                       sizeof(wlanpriv->wlan_dev.netdev->dev_addr));
+
+#define        WLAN_WATCHDOG_TIMEOUT   (5 * HZ)
+
+       dev->tx_timeout = wlan_tx_timeout;
+       dev->get_stats = wlan_get_stats;
+       dev->watchdog_timeo = WLAN_WATCHDOG_TIMEOUT;
+       dev->ethtool_ops = &libertas_ethtool_ops;
+       mesh_dev->get_stats = wlan_get_stats;
+       mesh_dev->ethtool_ops = &libertas_ethtool_ops;
+
+#ifdef WIRELESS_EXT
+       dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
+       mesh_dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
+#endif
+#define NETIF_F_DYNALLOC 16
+       dev->features |= NETIF_F_DYNALLOC;
+       dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+       dev->set_multicast_list = wlan_set_multicast_list;
+
+       INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
+       INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
+
+       spin_lock_init(&priv->adapter->driver_lock);
+       init_waitqueue_head(&priv->adapter->cmd_pending);
+       priv->adapter->nr_cmd_pending = 0;
+
+       lbs_pr_debug(1, "Starting kthread...\n");
+       priv->mainthread.priv = priv;
+       wlan_create_thread(wlan_service_main_thread,
+                          &priv->mainthread, "wlan_main_service");
+
+       priv->assoc_thread =
+               create_singlethread_workqueue("libertas_assoc");
+       INIT_DELAYED_WORK(&priv->assoc_work, wlan_association_worker);
+
+       /*
+        * Register the device. Fillup the private data structure with
+        * relevant information from the card and request for the required
+        * IRQ.
+        */
+       if (libertas_sbi_register_dev(priv) < 0) {
+               lbs_pr_info("failed to register wlan device!\n");
+               goto err_registerdev;
+       }
+
+       /* init FW and HW */
+       if (libertas_init_fw(priv)) {
+               lbs_pr_debug(1, "Firmware Init failed\n");
+               goto err_registerdev;
+       }
+
+       if (register_netdev(dev)) {
+               lbs_pr_err("Cannot register network device!\n");
+               goto err_init_fw;
+       }
+
+       /* Register virtual mesh interface */
+       if (register_netdev(mesh_dev)) {
+               lbs_pr_info("Cannot register mesh virtual interface!\n");
+               goto err_init_fw;
+       }
+
+       lbs_pr_info("%s: Marvell Wlan 802.11 adapter ", dev->name);
+
+       libertas_debugfs_init_one(priv, dev);
+
+       if (libertas_found == MAX_DEVS)
+               goto err_init_fw;
+       libertas_devs[libertas_found] = dev;
+       libertas_found++;
+#ifdef ENABLE_PM
+       if (!(wlan_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, wlan_pm_callback)))
+               lbs_pr_alert( "failed to register PM callback\n");
+#endif
+       if (device_create_file(&(mesh_dev->dev), &dev_attr_libertas_mpp))
+               goto err_create_file;
+
+       LEAVE();
+       return priv;
+
+err_create_file:
+       device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp);
+err_init_fw:
+       libertas_sbi_unregister_dev(priv);
+err_registerdev:
+       destroy_workqueue(priv->assoc_thread);
+       /* Stop the thread servicing the interrupts */
+       wake_up_interruptible(&priv->mainthread.waitq);
+       wlan_terminate_thread(&priv->mainthread);
+       kfree(priv->adapter);
+err_kmalloc:
+       free_netdev(dev);
+       free_netdev(mesh_dev);
+       wlanpriv = NULL;
+
+       LEAVE();
+       return NULL;
+}
+
+static void wake_pending_cmdnodes(wlan_private *priv)
+{
+       struct cmd_ctrl_node *cmdnode;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+       list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+               cmdnode->cmdwaitqwoken = 1;
+               wake_up_interruptible(&cmdnode->cmdwait_q);
+       }
+       spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+}
+
+
+int wlan_remove_card(void *card)
+{
+       wlan_private *priv = libertas_sbi_get_priv(card);
+       wlan_adapter *adapter;
+       struct net_device *dev;
+       struct net_device *mesh_dev;
+       union iwreq_data wrqu;
+       int i;
+
+       ENTER();
+
+       if (!priv) {
+               LEAVE();
+               return 0;
+       }
+
+       adapter = priv->adapter;
+
+       if (!adapter) {
+               LEAVE();
+               return 0;
+       }
+
+       dev = priv->wlan_dev.netdev;
+       mesh_dev = priv->mesh_dev;
+
+       netif_stop_queue(mesh_dev);
+       netif_stop_queue(priv->wlan_dev.netdev);
+       netif_carrier_off(priv->wlan_dev.netdev);
+
+       wake_pending_cmdnodes(priv);
+
+       device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp);
+       unregister_netdev(mesh_dev);
+       unregister_netdev(dev);
+
+       cancel_delayed_work(&priv->assoc_work);
+       destroy_workqueue(priv->assoc_thread);
+
+       if (adapter->psmode == wlan802_11powermodemax_psp) {
+               adapter->psmode = wlan802_11powermodecam;
+               libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+       }
+
+       memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+#ifdef ENABLE_PM
+       pm_unregister(wlan_pm_dev);
+#endif
+
+       adapter->surpriseremoved = 1;
+
+       /* Stop the thread servicing the interrupts */
+       wlan_terminate_thread(&priv->mainthread);
+
+       libertas_debugfs_remove_one(priv);
+
+       lbs_pr_debug(1, "Free adapter\n");
+       libertas_free_adapter(priv);
+
+       for (i = 0; i<libertas_found; i++) {
+               if (libertas_devs[i]==priv->wlan_dev.netdev) {
+                       libertas_devs[i] = libertas_devs[--libertas_found];
+                       libertas_devs[libertas_found] = NULL ;
+                       break ;
+               }
+       }
+
+       lbs_pr_debug(1, "Unregister finish\n");
+
+       priv->wlan_dev.netdev = NULL;
+       priv->mesh_dev = NULL ;
+       free_netdev(mesh_dev);
+       free_netdev(dev);
+       wlanpriv = NULL;
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief This function finds the CFP in
+ *  region_cfp_table based on region and band parameter.
+ *
+ *  @param region  The region code
+ *  @param band           The band
+ *  @param cfp_no  A pointer to CFP number
+ *  @return       A pointer to CFP
+ */
+struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
+{
+       int i, end;
+
+       ENTER();
+
+       end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table);
+
+       for (i = 0; i < end ; i++) {
+               lbs_pr_debug(1, "region_cfp_table[i].region=%d\n",
+                       region_cfp_table[i].region);
+               if (region_cfp_table[i].region == region) {
+                       *cfp_no = region_cfp_table[i].cfp_no_BG;
+                       LEAVE();
+                       return region_cfp_table[i].cfp_BG;
+               }
+       }
+
+       LEAVE();
+       return NULL;
+}
+
+int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int i = 0;
+
+       struct chan_freq_power *cfp;
+       int cfp_no;
+
+       ENTER();
+
+       memset(adapter->region_channel, 0, sizeof(adapter->region_channel));
+
+       {
+               cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
+               if (cfp != NULL) {
+                       adapter->region_channel[i].nrcfp = cfp_no;
+                       adapter->region_channel[i].CFP = cfp;
+               } else {
+                       lbs_pr_debug(1, "wrong region code %#x in band B-G\n",
+                              region);
+                       return -1;
+               }
+               adapter->region_channel[i].valid = 1;
+               adapter->region_channel[i].region = region;
+               adapter->region_channel[i].band = band;
+               i++;
+       }
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief This function handles the interrupt. it will change PS
+ *  state if applicable. it will wake up main_thread to handle
+ *  the interrupt event as well.
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return       n/a
+ */
+void libertas_interrupt(struct net_device *dev)
+{
+       wlan_private *priv = dev->priv;
+
+       ENTER();
+
+       lbs_pr_debug(1, "libertas_interrupt: intcounter=%d\n",
+              priv->adapter->intcounter);
+
+       priv->adapter->intcounter++;
+
+       if (priv->adapter->psstate == PS_STATE_SLEEP) {
+               priv->adapter->psstate = PS_STATE_AWAKE;
+               netif_wake_queue(dev);
+       }
+
+       wake_up_interruptible(&priv->mainthread.waitq);
+
+       LEAVE();
+}
+
+static int wlan_init_module(void)
+{
+       int ret = 0;
+
+       ENTER();
+
+       if (libertas_fw_name == NULL) {
+               libertas_fw_name = default_fw_name;
+       }
+
+       libertas_debugfs_init();
+
+       if (libertas_sbi_register()) {
+               ret = -1;
+               libertas_debugfs_remove();
+               goto done;
+       }
+
+done:
+       LEAVE();
+       return ret;
+}
+
+static void wlan_cleanup_module(void)
+{
+       int i;
+
+       ENTER();
+
+       for (i = 0; i<libertas_found; i++) {
+               wlan_private *priv = libertas_devs[i]->priv;
+               reset_device(priv);
+       }
+
+       libertas_sbi_unregister();
+       libertas_debugfs_remove();
+
+       LEAVE();
+}
+
+module_init(wlan_init_module);
+module_exit(wlan_cleanup_module);
+
+MODULE_DESCRIPTION("M-WLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
new file mode 100644 (file)
index 0000000..5d118f4
--- /dev/null
@@ -0,0 +1,57 @@
+#include <net/ieee80211_radiotap.h>
+
+struct tx_radiotap_hdr {
+       struct ieee80211_radiotap_header hdr;
+       u8 rate;
+       u8 txpower;
+       u8 rts_retries;
+       u8 data_retries;
+#if 0
+       u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12];
+#endif
+} __attribute__ ((packed));
+
+#define TX_RADIOTAP_PRESENT (                          \
+       (1 << IEEE80211_RADIOTAP_RATE) |                \
+       (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) |        \
+       (1 << IEEE80211_RADIOTAP_RTS_RETRIES) |         \
+       (1 << IEEE80211_RADIOTAP_DATA_RETRIES)  |       \
+       0)
+
+#define IEEE80211_FC_VERSION_MASK    0x0003
+#define IEEE80211_FC_TYPE_MASK       0x000c
+#define IEEE80211_FC_TYPE_MGT        0x0000
+#define IEEE80211_FC_TYPE_CTL        0x0004
+#define IEEE80211_FC_TYPE_DATA       0x0008
+#define IEEE80211_FC_SUBTYPE_MASK    0x00f0
+#define IEEE80211_FC_TOFROMDS_MASK   0x0300
+#define IEEE80211_FC_TODS_MASK       0x0100
+#define IEEE80211_FC_FROMDS_MASK     0x0200
+#define IEEE80211_FC_NODS            0x0000
+#define IEEE80211_FC_TODS            0x0100
+#define IEEE80211_FC_FROMDS          0x0200
+#define IEEE80211_FC_DSTODS          0x0300
+
+struct rx_radiotap_hdr {
+       struct ieee80211_radiotap_header hdr;
+       u8 flags;
+       u8 rate;
+       u16 chan_freq;
+       u16 chan_flags;
+       u8 antenna;
+       u8 antsignal;
+       u16 rx_flags;
+#if 0
+       u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18];
+#endif
+} __attribute__ ((packed));
+
+#define RX_RADIOTAP_PRESENT (                  \
+       (1 << IEEE80211_RADIOTAP_FLAGS) |       \
+       (1 << IEEE80211_RADIOTAP_RATE) |        \
+       (1 << IEEE80211_RADIOTAP_CHANNEL) |     \
+       (1 << IEEE80211_RADIOTAP_ANTENNA) |     \
+       (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\
+       (1 << IEEE80211_RADIOTAP_RX_FLAGS) |    \
+       0)
+
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
new file mode 100644 (file)
index 0000000..7e3f78f
--- /dev/null
@@ -0,0 +1,459 @@
+/**
+  * This file contains the handling of RX in wlan driver.
+  */
+#include <linux/etherdevice.h>
+#include <linux/types.h>
+
+#include "hostcmd.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "dev.h"
+#include "wext.h"
+
+struct eth803hdr {
+       u8 dest_addr[6];
+       u8 src_addr[6];
+       u16 h803_len;
+} __attribute__ ((packed));
+
+struct rfc1042hdr {
+       u8 llc_dsap;
+       u8 llc_ssap;
+       u8 llc_ctrl;
+       u8 snap_oui[3];
+       u16 snap_type;
+} __attribute__ ((packed));
+
+struct rxpackethdr {
+       struct rxpd rx_pd;
+       struct eth803hdr eth803_hdr;
+       struct rfc1042hdr rfc1042_hdr;
+} __attribute__ ((packed));
+
+struct rx80211packethdr {
+       struct rxpd rx_pd;
+       void *eth80211_hdr;
+} __attribute__ ((packed));
+
+static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb);
+
+/**
+ *  @brief This function computes the avgSNR .
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return       avgSNR
+ */
+static u8 wlan_getavgsnr(wlan_private * priv)
+{
+       u8 i;
+       u16 temp = 0;
+       wlan_adapter *adapter = priv->adapter;
+       if (adapter->numSNRNF == 0)
+               return 0;
+       for (i = 0; i < adapter->numSNRNF; i++)
+               temp += adapter->rawSNR[i];
+       return (u8) (temp / adapter->numSNRNF);
+
+}
+
+/**
+ *  @brief This function computes the AvgNF
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return       AvgNF
+ */
+static u8 wlan_getavgnf(wlan_private * priv)
+{
+       u8 i;
+       u16 temp = 0;
+       wlan_adapter *adapter = priv->adapter;
+       if (adapter->numSNRNF == 0)
+               return 0;
+       for (i = 0; i < adapter->numSNRNF; i++)
+               temp += adapter->rawNF[i];
+       return (u8) (temp / adapter->numSNRNF);
+
+}
+
+/**
+ *  @brief This function save the raw SNR/NF to our internel buffer
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param prxpd   A pointer to rxpd structure of received packet
+ *  @return       n/a
+ */
+static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
+{
+       wlan_adapter *adapter = priv->adapter;
+       if (adapter->numSNRNF < adapter->data_avg_factor)
+               adapter->numSNRNF++;
+       adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
+       adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
+       adapter->nextSNRNF++;
+       if (adapter->nextSNRNF >= adapter->data_avg_factor)
+               adapter->nextSNRNF = 0;
+       return;
+}
+
+/**
+ *  @brief This function computes the RSSI in received packet.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param prxpd   A pointer to rxpd structure of received packet
+ *  @return       n/a
+ */
+static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd)
+{
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       lbs_pr_debug(1, "rxpd: SNR = %d, NF = %d\n", p_rx_pd->snr, p_rx_pd->nf);
+       lbs_pr_debug(1, "Before computing SNR: SNR- avg = %d, NF-avg = %d\n",
+              adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+              adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+       adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
+       adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
+       wlan_save_rawSNRNF(priv, p_rx_pd);
+
+       adapter->rxpd_rate = p_rx_pd->rx_rate;
+
+       adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
+       adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
+       lbs_pr_debug(1, "After computing SNR: SNR-avg = %d, NF-avg = %d\n",
+              adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+              adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+       adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
+           CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+                    adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+
+       adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
+           CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+                    adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+       LEAVE();
+}
+
+int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
+{
+       lbs_pr_debug(1, "skb->data=%p\n", skb->data);
+
+       if(IS_MESH_FRAME(skb))
+               skb->dev = priv->mesh_dev;
+       else
+               skb->dev = priv->wlan_dev.netdev;
+       skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev);
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       netif_rx(skb);
+
+       return 0;
+}
+
+/**
+ *  @brief This function processes received packet and forwards it
+ *  to kernel/upper layer
+ *
+ *  @param priv    A pointer to wlan_private
+ *  @param skb     A pointer to skb which includes the received packet
+ *  @return       0 or -1
+ */
+int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       struct rxpackethdr *p_rx_pkt;
+       struct rxpd *p_rx_pd;
+
+       int hdrchop;
+       struct ethhdr *p_ethhdr;
+
+       const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+       ENTER();
+
+       if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
+               lbs_dbg_hex("RX packet: ", skb->data,
+                        min_t(unsigned int, skb->len, 100));
+
+       if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+               return process_rxed_802_11_packet(priv, skb);
+
+       p_rx_pkt = (struct rxpackethdr *) skb->data;
+       p_rx_pd = &p_rx_pkt->rx_pd;
+       if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
+               SET_MESH_FRAME(skb);
+       else
+               UNSET_MESH_FRAME(skb);
+
+       lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
+                min_t(unsigned int, skb->len, 100));
+
+       if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+               lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
+               priv->stats.rx_length_errors++;
+               ret = 0;
+               goto done;
+       }
+
+       /*
+        * Check rxpd status and update 802.3 stat,
+        */
+       if (!(p_rx_pd->status & MRVDRV_RXPD_STATUS_OK)) {
+               lbs_pr_debug(1, "RX error: frame received with bad status\n");
+               lbs_pr_alert("rxpd Not OK\n");
+               priv->stats.rx_errors++;
+               ret = 0;
+               goto done;
+       }
+
+       lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
+              skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+       lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
+               sizeof(p_rx_pkt->eth803_hdr.dest_addr));
+       lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
+               sizeof(p_rx_pkt->eth803_hdr.src_addr));
+
+       if (memcmp(&p_rx_pkt->rfc1042_hdr,
+                  rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+               /*
+                *  Replace the 803 header and rfc1042 header (llc/snap) with an
+                *    EthernetII header, keep the src/dst and snap_type (ethertype)
+                *
+                *  The firmware only passes up SNAP frames converting
+                *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+                *
+                *  To create the Ethernet II, just move the src, dst address right
+                *    before the snap_type.
+                */
+               p_ethhdr = (struct ethhdr *)
+                   ((u8 *) & p_rx_pkt->eth803_hdr
+                    + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
+                    - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
+                    - sizeof(p_rx_pkt->eth803_hdr.src_addr)
+                    - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
+
+               memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
+                      sizeof(p_ethhdr->h_source));
+               memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
+                      sizeof(p_ethhdr->h_dest));
+
+               /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
+                *   that was removed
+                */
+               hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
+       } else {
+               lbs_dbg_hex("RX Data: LLC/SNAP",
+                       (u8 *) & p_rx_pkt->rfc1042_hdr,
+                       sizeof(p_rx_pkt->rfc1042_hdr));
+
+               /* Chop off the rxpd */
+               hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt;
+       }
+
+       /* Chop off the leading header bytes so the skb points to the start of
+        *   either the reconstructed EthII frame or the 802.2/llc/snap frame
+        */
+       skb_pull(skb, hdrchop);
+
+       /* Take the data rate from the rxpd structure
+        * only if the rate is auto
+        */
+       if (adapter->is_datarate_auto)
+               adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate);
+
+       wlan_compute_rssi(priv, p_rx_pd);
+
+       lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
+       if (libertas_upload_rx_packet(priv, skb)) {
+               lbs_pr_debug(1, "RX error: libertas_upload_rx_packet"
+                      " returns failure\n");
+               ret = -1;
+               goto done;
+       }
+       priv->stats.rx_bytes += skb->len;
+       priv->stats.rx_packets++;
+
+       ret = 0;
+done:
+       LEAVE();
+
+       return ret;
+}
+
+/**
+ *  @brief This function converts Tx/Rx rates from the Marvell WLAN format
+ *  (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
+ *
+ *  @param rate    Input rate
+ *  @return       Output Rate (0 if invalid)
+ */
+static u8 convert_mv_rate_to_radiotap(u8 rate)
+{
+       switch (rate) {
+       case 0:         /*   1 Mbps */
+               return 2;
+       case 1:         /*   2 Mbps */
+               return 4;
+       case 2:         /* 5.5 Mbps */
+               return 11;
+       case 3:         /*  11 Mbps */
+               return 22;
+       case 4:         /*   6 Mbps */
+               return 12;
+       case 5:         /*   9 Mbps */
+               return 18;
+       case 6:         /*  12 Mbps */
+               return 24;
+       case 7:         /*  18 Mbps */
+               return 36;
+       case 8:         /*  24 Mbps */
+               return 48;
+       case 9:         /*  36 Mbps */
+               return 72;
+       case 10:                /*  48 Mbps */
+               return 96;
+       case 11:                /*  54 Mbps */
+               return 108;
+       }
+       lbs_pr_alert( "Invalid Marvell WLAN rate (%i)\n", rate);
+       return 0;
+}
+
+/**
+ *  @brief This function processes a received 802.11 packet and forwards it
+ *  to kernel/upper layer
+ *
+ *  @param priv    A pointer to wlan_private
+ *  @param skb     A pointer to skb which includes the received packet
+ *  @return       0 or -1
+ */
+static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       struct rx80211packethdr *p_rx_pkt;
+       struct rxpd *prxpd;
+       struct rx_radiotap_hdr radiotap_hdr;
+       struct rx_radiotap_hdr *pradiotap_hdr;
+
+       ENTER();
+
+       p_rx_pkt = (struct rx80211packethdr *) skb->data;
+       prxpd = &p_rx_pkt->rx_pd;
+
+       // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
+
+       if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+               lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
+               priv->stats.rx_length_errors++;
+               ret = 0;
+               goto done;
+       }
+
+       /*
+        * Check rxpd status and update 802.3 stat,
+        */
+       if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) {
+               //lbs_pr_debug(1, "RX error: frame received with bad status\n");
+               priv->stats.rx_errors++;
+       }
+
+       lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
+              skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+       /* create the exported radio header */
+       switch (priv->adapter->radiomode) {
+       case WLAN_RADIOMODE_NONE:
+               /* no radio header */
+               /* chop the rxpd */
+               skb_pull(skb, sizeof(struct rxpd));
+               break;
+
+       case WLAN_RADIOMODE_RADIOTAP:
+               /* radiotap header */
+               radiotap_hdr.hdr.it_version = 0;
+               /* XXX must check this value for pad */
+               radiotap_hdr.hdr.it_pad = 0;
+               radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr);
+               radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT;
+               /* unknown values */
+               radiotap_hdr.flags = 0;
+               radiotap_hdr.chan_freq = 0;
+               radiotap_hdr.chan_flags = 0;
+               radiotap_hdr.antenna = 0;
+               /* known values */
+               radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
+               /* XXX must check no carryout */
+               radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
+               radiotap_hdr.rx_flags = 0;
+               if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK))
+                       radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
+               //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
+
+               // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100));
+
+               /* chop the rxpd */
+               skb_pull(skb, sizeof(struct rxpd));
+
+               /* add space for the new radio header */
+               if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
+                   pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0,
+                                    GFP_ATOMIC)) {
+                       lbs_pr_alert( "%s: couldn't pskb_expand_head\n",
+                              __func__);
+               }
+
+               pradiotap_hdr =
+                   (struct rx_radiotap_hdr *)skb_push(skb,
+                                                    sizeof(struct
+                                                           rx_radiotap_hdr));
+               memcpy(pradiotap_hdr, &radiotap_hdr,
+                      sizeof(struct rx_radiotap_hdr));
+               //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
+               break;
+
+       default:
+               /* unknown header */
+               lbs_pr_alert( "Unknown radiomode (%i)\n",
+                      priv->adapter->radiomode);
+               /* don't export any header */
+               /* chop the rxpd */
+               skb_pull(skb, sizeof(struct rxpd));
+               break;
+       }
+
+       /* Take the data rate from the rxpd structure
+        * only if the rate is auto
+        */
+       if (adapter->is_datarate_auto) {
+               adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate);
+       }
+
+       wlan_compute_rssi(priv, prxpd);
+
+       lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
+
+       if (libertas_upload_rx_packet(priv, skb)) {
+               lbs_pr_debug(1, "RX error: libertas_upload_rx_packet "
+                       "returns failure\n");
+               ret = -1;
+               goto done;
+       }
+
+       priv->stats.rx_bytes += skb->len;
+       priv->stats.rx_packets++;
+
+       ret = 0;
+done:
+       LEAVE();
+
+       skb->protocol = __constant_htons(0x0019);       /* ETH_P_80211_RAW */
+
+       return (ret);
+}
diff --git a/drivers/net/wireless/libertas/sbi.h b/drivers/net/wireless/libertas/sbi.h
new file mode 100644 (file)
index 0000000..59d3a59
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+  * This file contains IF layer definitions.
+  */
+
+#ifndef        _SBI_H_
+#define        _SBI_H_
+
+#include <linux/interrupt.h>
+
+#include "defs.h"
+
+/** INT status Bit Definition*/
+#define his_cmddnldrdy                 0x01
+#define his_cardevent                  0x02
+#define his_cmdupldrdy                 0x04
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN                   32
+#endif
+
+#define SBI_EVENT_CAUSE_SHIFT          3
+
+/* Probe and Check if the card is present*/
+int libertas_sbi_register_dev(wlan_private * priv);
+int libertas_sbi_unregister_dev(wlan_private *);
+int libertas_sbi_get_int_status(wlan_private * priv, u8 *);
+int libertas_sbi_register(void);
+void libertas_sbi_unregister(void);
+int libertas_sbi_prog_firmware(wlan_private *);
+
+int libertas_sbi_read_event_cause(wlan_private *);
+int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
+wlan_private *libertas_sbi_get_priv(void *card);
+
+#ifdef ENABLE_PM
+int libertas_sbi_suspend(wlan_private *);
+int libertas_sbi_resume(wlan_private *);
+#endif
+
+#endif                         /* _SBI_H */
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
new file mode 100644 (file)
index 0000000..e187062
--- /dev/null
@@ -0,0 +1,2044 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+  * Functions implementing wlan scan IOCTL and firmware command APIs
+  *
+  * IOCTL handlers as well as command preperation and response routines
+  *  for sending scan commands to the firmware.
+  */
+#include <linux/ctype.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+
+#include <net/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "decl.h"
+#include "dev.h"
+#include "scan.h"
+
+//! Approximate amount of data needed to pass a scan result back to iwlist
+#define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \
+                             + IW_ESSID_MAX_SIZE        \
+                             + IW_EV_UINT_LEN           \
+                             + IW_EV_FREQ_LEN           \
+                             + IW_EV_QUAL_LEN           \
+                             + IW_ESSID_MAX_SIZE        \
+                             + IW_EV_PARAM_LEN          \
+                             + 40)     /* 40 for WPAIE */
+
+//! Memory needed to store a max sized channel List TLV for a firmware scan
+#define CHAN_TLV_MAX_SIZE  (sizeof(struct mrvlietypesheader)    \
+                            + (MRVDRV_MAX_CHANNELS_PER_SCAN     \
+                               * sizeof(struct chanscanparamset)))
+
+//! Memory needed to store a max number/size SSID TLV for a firmware scan
+#define SSID_TLV_MAX_SIZE  (1 * sizeof(struct mrvlietypes_ssidparamset))
+
+//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
+#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config)  \
+                            + sizeof(struct mrvlietypes_numprobes)   \
+                            + CHAN_TLV_MAX_SIZE                 \
+                            + SSID_TLV_MAX_SIZE)
+
+//! The maximum number of channels the firmware can scan per command
+#define MRVDRV_MAX_CHANNELS_PER_SCAN   14
+
+/**
+ * @brief Number of channels to scan per firmware scan command issuance.
+ *
+ *  Number restricted to prevent hitting the limit on the amount of scan data
+ *  returned in a single firmware scan command.
+ */
+#define MRVDRV_CHANNELS_PER_SCAN_CMD   4
+
+//! Scan time specified in the channel TLV for each channel for passive scans
+#define MRVDRV_PASSIVE_SCAN_CHAN_TIME  100
+
+//! Scan time specified in the channel TLV for each channel for active scans
+#define MRVDRV_ACTIVE_SCAN_CHAN_TIME   100
+
+//! Macro to enable/disable SSID checking before storing a scan table
+#ifdef DISCARD_BAD_SSID
+#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.ssid)
+#else
+#define CHECK_SSID_IS_VALID(x) 1
+#endif
+
+/**
+ *  @brief Check if a scanned network compatible with the driver settings
+ *
+ *   WEP     WPA     WPA2    ad-hoc  encrypt                      Network
+ * enabled enabled  enabled   AES     mode   privacy  WPA  WPA2  Compatible
+ *    0       0        0       0      NONE      0      0    0   yes No security
+ *    1       0        0       0      NONE      1      0    0   yes Static WEP
+ *    0       1        0       0       x        1x     1    x   yes WPA
+ *    0       0        1       0       x        1x     x    1   yes WPA2
+ *    0       0        0       1      NONE      1      0    0   yes Ad-hoc AES
+ *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
+ *
+ *
+ *  @param adapter A pointer to wlan_adapter
+ *  @param index   Index in scantable to check against current driver settings
+ *  @param mode    Network mode: Infrastructure or IBSS
+ *
+ *  @return        Index in scantable, or error code if negative
+ */
+static int is_network_compatible(wlan_adapter * adapter, int index, int mode)
+{
+       ENTER();
+
+       if (adapter->scantable[index].inframode == mode) {
+               if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+                   && !adapter->secinfo.WPAenabled
+                   && !adapter->secinfo.WPA2enabled
+                   && adapter->scantable[index].wpa_supplicant.wpa_ie[0] !=
+                   WPA_IE
+                   && adapter->scantable[index].wpa2_supplicant.wpa_ie[0] !=
+                   WPA2_IE && adapter->secinfo.Encryptionmode == CIPHER_NONE
+                   && !adapter->scantable[index].privacy) {
+                       /* no security */
+                       LEAVE();
+                       return index;
+               } else if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled
+                          && !adapter->secinfo.WPAenabled
+                          && !adapter->secinfo.WPA2enabled
+                          && adapter->scantable[index].privacy) {
+                       /* static WEP enabled */
+                       LEAVE();
+                       return index;
+               } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+                          && adapter->secinfo.WPAenabled
+                          && !adapter->secinfo.WPA2enabled
+                          && (adapter->scantable[index].wpa_supplicant.
+                              wpa_ie[0]
+                              == WPA_IE)
+                          /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+                             && adapter->scantable[index].privacy */
+                   ) {
+                       /* WPA enabled */
+            lbs_pr_debug(1,
+                              "is_network_compatible() WPA: index=%d wpa_ie=%#x "
+                              "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
+                              "privacy=%#x\n", index,
+                              adapter->scantable[index].wpa_supplicant.
+                              wpa_ie[0],
+                              adapter->scantable[index].wpa2_supplicant.
+                              wpa_ie[0],
+                              (adapter->secinfo.WEPstatus ==
+                               wlan802_11WEPenabled) ? "e" : "d",
+                              (adapter->secinfo.WPAenabled) ? "e" : "d",
+                              (adapter->secinfo.WPA2enabled) ? "e" : "d",
+                              adapter->secinfo.Encryptionmode,
+                              adapter->scantable[index].privacy);
+                       LEAVE();
+                       return index;
+               } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+                          && !adapter->secinfo.WPAenabled
+                          && adapter->secinfo.WPA2enabled
+                          && (adapter->scantable[index].wpa2_supplicant.
+                              wpa_ie[0]
+                              == WPA2_IE)
+                          /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+                             && adapter->scantable[index].privacy */
+                   ) {
+                       /* WPA2 enabled */
+            lbs_pr_debug(1,
+                              "is_network_compatible() WPA2: index=%d wpa_ie=%#x "
+                              "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
+                              "privacy=%#x\n", index,
+                              adapter->scantable[index].wpa_supplicant.
+                              wpa_ie[0],
+                              adapter->scantable[index].wpa2_supplicant.
+                              wpa_ie[0],
+                              (adapter->secinfo.WEPstatus ==
+                               wlan802_11WEPenabled) ? "e" : "d",
+                              (adapter->secinfo.WPAenabled) ? "e" : "d",
+                              (adapter->secinfo.WPA2enabled) ? "e" : "d",
+                              adapter->secinfo.Encryptionmode,
+                              adapter->scantable[index].privacy);
+                       LEAVE();
+                       return index;
+               } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+                          && !adapter->secinfo.WPAenabled
+                          && !adapter->secinfo.WPA2enabled
+                          && (adapter->scantable[index].wpa_supplicant.
+                              wpa_ie[0]
+                              != WPA_IE)
+                          && (adapter->scantable[index].wpa2_supplicant.
+                              wpa_ie[0]
+                              != WPA2_IE)
+                          && adapter->secinfo.Encryptionmode != CIPHER_NONE
+                          && adapter->scantable[index].privacy) {
+                       /* dynamic WEP enabled */
+            lbs_pr_debug(1,
+                              "is_network_compatible() dynamic WEP: index=%d "
+                              "wpa_ie=%#x wpa2_ie=%#x Encmode=%#x privacy=%#x\n",
+                              index,
+                              adapter->scantable[index].wpa_supplicant.
+                              wpa_ie[0],
+                              adapter->scantable[index].wpa2_supplicant.
+                              wpa_ie[0], adapter->secinfo.Encryptionmode,
+                              adapter->scantable[index].privacy);
+                       LEAVE();
+                       return index;
+               }
+
+               /* security doesn't match */
+        lbs_pr_debug(1,
+                      "is_network_compatible() FAILED: index=%d wpa_ie=%#x "
+                      "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x privacy=%#x\n",
+                      index,
+                      adapter->scantable[index].wpa_supplicant.wpa_ie[0],
+                      adapter->scantable[index].wpa2_supplicant.wpa_ie[0],
+                      (adapter->secinfo.WEPstatus ==
+                       wlan802_11WEPenabled) ? "e" : "d",
+                      (adapter->secinfo.WPAenabled) ? "e" : "d",
+                      (adapter->secinfo.WPA2enabled) ? "e" : "d",
+                      adapter->secinfo.Encryptionmode,
+                      adapter->scantable[index].privacy);
+               LEAVE();
+               return -ECONNREFUSED;
+       }
+
+       /* mode doesn't match */
+       LEAVE();
+       return -ENETUNREACH;
+}
+
+/**
+ *  @brief This function validates a SSID as being able to be printed
+ *
+ *  @param pssid   SSID structure to validate
+ *
+ *  @return        TRUE or FALSE
+ */
+static u8 ssid_valid(struct WLAN_802_11_SSID *pssid)
+{
+       int ssididx;
+
+       for (ssididx = 0; ssididx < pssid->ssidlength; ssididx++) {
+               if (!isprint(pssid->ssid[ssididx])) {
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+/**
+ *  @brief Post process the scan table after a new scan command has completed
+ *
+ *  Inspect each entry of the scan table and try to find an entry that
+ *    matches our current associated/joined network from the scan.  If
+ *    one is found, update the stored copy of the bssdescriptor for our
+ *    current network.
+ *
+ *  Debug dump the current scan table contents if compiled accordingly.
+ *
+ *  @param priv   A pointer to wlan_private structure
+ *
+ *  @return       void
+ */
+static void wlan_scan_process_results(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int foundcurrent;
+       int i;
+
+       foundcurrent = 0;
+
+       if (adapter->connect_status == libertas_connected) {
+               /* try to find the current BSSID in the new scan list */
+               for (i = 0; i < adapter->numinscantable; i++) {
+                       if (!libertas_SSID_cmp(&adapter->scantable[i].ssid,
+                                    &adapter->curbssparams.ssid) &&
+                           !memcmp(adapter->curbssparams.bssid,
+                                   adapter->scantable[i].macaddress,
+                                   ETH_ALEN)) {
+                               foundcurrent = 1;
+                       }
+               }
+
+               if (foundcurrent) {
+                       /* Make a copy of current BSSID descriptor */
+                       memcpy(&adapter->curbssparams.bssdescriptor,
+                              &adapter->scantable[i],
+                              sizeof(adapter->curbssparams.bssdescriptor));
+               }
+       }
+
+       for (i = 0; i < adapter->numinscantable; i++) {
+               lbs_pr_debug(1, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
+                      "RSSI[%03d], SSID[%s]\n",
+                      i,
+                      adapter->scantable[i].macaddress[0],
+                      adapter->scantable[i].macaddress[1],
+                      adapter->scantable[i].macaddress[2],
+                      adapter->scantable[i].macaddress[3],
+                      adapter->scantable[i].macaddress[4],
+                      adapter->scantable[i].macaddress[5],
+                      (s32) adapter->scantable[i].rssi,
+                      adapter->scantable[i].ssid.ssid);
+       }
+}
+
+/**
+ *  @brief Create a channel list for the driver to scan based on region info
+ *
+ *  Use the driver region/band information to construct a comprehensive list
+ *    of channels to scan.  This routine is used for any scan that is not
+ *    provided a specific channel list to scan.
+ *
+ *  @param priv          A pointer to wlan_private structure
+ *  @param scanchanlist  Output parameter: resulting channel list to scan
+ *  @param filteredscan  Flag indicating whether or not a BSSID or SSID filter
+ *                       is being sent in the command to firmware.  Used to
+ *                       increase the number of channels sent in a scan
+ *                       command and to disable the firmware channel scan
+ *                       filter.
+ *
+ *  @return              void
+ */
+static void wlan_scan_create_channel_list(wlan_private * priv,
+                                         struct chanscanparamset * scanchanlist,
+                                         u8 filteredscan)
+{
+
+       wlan_adapter *adapter = priv->adapter;
+       struct region_channel *scanregion;
+       struct chan_freq_power *cfp;
+       int rgnidx;
+       int chanidx;
+       int nextchan;
+       u8 scantype;
+
+       chanidx = 0;
+
+       /* Set the default scan type to the user specified type, will later
+        *   be changed to passive on a per channel basis if restricted by
+        *   regulatory requirements (11d or 11h)
+        */
+       scantype = adapter->scantype;
+
+       for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
+               if (priv->adapter->enable11d &&
+                   adapter->connect_status != libertas_connected) {
+                       /* Scan all the supported chan for the first scan */
+                       if (!adapter->universal_channel[rgnidx].valid)
+                               continue;
+                       scanregion = &adapter->universal_channel[rgnidx];
+
+                       /* clear the parsed_region_chan for the first scan */
+                       memset(&adapter->parsed_region_chan, 0x00,
+                              sizeof(adapter->parsed_region_chan));
+               } else {
+                       if (!adapter->region_channel[rgnidx].valid)
+                               continue;
+                       scanregion = &adapter->region_channel[rgnidx];
+               }
+
+               for (nextchan = 0;
+                    nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
+
+                       cfp = scanregion->CFP + nextchan;
+
+                       if (priv->adapter->enable11d) {
+                               scantype =
+                                   libertas_get_scan_type_11d(cfp->channel,
+                                                          &adapter->
+                                                          parsed_region_chan);
+                       }
+
+                       switch (scanregion->band) {
+                       case BAND_B:
+                       case BAND_G:
+                       default:
+                               scanchanlist[chanidx].radiotype =
+                                   cmd_scan_radio_type_bg;
+                               break;
+                       }
+
+                       if (scantype == cmd_scan_type_passive) {
+                               scanchanlist[chanidx].maxscantime =
+                                   cpu_to_le16
+                                   (MRVDRV_PASSIVE_SCAN_CHAN_TIME);
+                               scanchanlist[chanidx].chanscanmode.passivescan =
+                                   1;
+                       } else {
+                               scanchanlist[chanidx].maxscantime =
+                                   cpu_to_le16
+                                   (MRVDRV_ACTIVE_SCAN_CHAN_TIME);
+                               scanchanlist[chanidx].chanscanmode.passivescan =
+                                   0;
+                       }
+
+                       scanchanlist[chanidx].channumber = cfp->channel;
+
+                       if (filteredscan) {
+                               scanchanlist[chanidx].chanscanmode.
+                                   disablechanfilt = 1;
+                       }
+               }
+       }
+}
+
+/**
+ *  @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
+ *
+ *  Application layer or other functions can invoke wlan_scan_networks
+ *    with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+ *    This structure is used as the basis of one or many wlan_scan_cmd_config
+ *    commands that are sent to the command processing module and sent to
+ *    firmware.
+ *
+ *  Create a wlan_scan_cmd_config based on the following user supplied
+ *    parameters (if present):
+ *             - SSID filter
+ *             - BSSID filter
+ *             - Number of Probes to be sent
+ *             - channel list
+ *
+ *  If the SSID or BSSID filter is not present, disable/clear the filter.
+ *  If the number of probes is not set, use the adapter default setting
+ *  Qualify the channel
+ *
+ *  @param priv             A pointer to wlan_private structure
+ *  @param puserscanin      NULL or pointer to scan configuration parameters
+ *  @param ppchantlvout     Output parameter: Pointer to the start of the
+ *                          channel TLV portion of the output scan config
+ *  @param pscanchanlist    Output parameter: Pointer to the resulting channel
+ *                          list to scan
+ *  @param pmaxchanperscan  Output parameter: Number of channels to scan for
+ *                          each issuance of the firmware scan command
+ *  @param pfilteredscan    Output parameter: Flag indicating whether or not
+ *                          a BSSID or SSID filter is being sent in the
+ *                          command to firmware.  Used to increase the number
+ *                          of channels sent in a scan command and to
+ *                          disable the firmware channel scan filter.
+ *  @param pscancurrentonly Output parameter: Flag indicating whether or not
+ *                          we are only scanning our current active channel
+ *
+ *  @return                 resulting scan configuration
+ */
+static struct wlan_scan_cmd_config *
+wlan_scan_setup_scan_config(wlan_private * priv,
+                           const struct wlan_ioctl_user_scan_cfg * puserscanin,
+                           struct mrvlietypes_chanlistparamset ** ppchantlvout,
+                           struct chanscanparamset * pscanchanlist,
+                           int *pmaxchanperscan,
+                           u8 * pfilteredscan,
+                           u8 * pscancurrentonly)
+{
+       wlan_adapter *adapter = priv->adapter;
+       const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+       struct mrvlietypes_numprobes *pnumprobestlv;
+       struct mrvlietypes_ssidparamset *pssidtlv;
+       struct wlan_scan_cmd_config * pscancfgout = NULL;
+       u8 *ptlvpos;
+       u16 numprobes;
+       u16 ssidlen;
+       int chanidx;
+       int scantype;
+       int scandur;
+       int channel;
+       int radiotype;
+
+       pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
+       if (pscancfgout == NULL)
+               goto out;
+
+       /* The tlvbufferlen is calculated for each scan command.  The TLVs added
+        *   in this routine will be preserved since the routine that sends
+        *   the command will append channelTLVs at *ppchantlvout.  The difference
+        *   between the *ppchantlvout and the tlvbuffer start will be used
+        *   to calculate the size of anything we add in this routine.
+        */
+       pscancfgout->tlvbufferlen = 0;
+
+       /* Running tlv pointer.  Assigned to ppchantlvout at end of function
+        *  so later routines know where channels can be added to the command buf
+        */
+       ptlvpos = pscancfgout->tlvbuffer;
+
+       /*
+        * Set the initial scan paramters for progressive scanning.  If a specific
+        *   BSSID or SSID is used, the number of channels in the scan command
+        *   will be increased to the absolute maximum
+        */
+       *pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
+
+       /* Initialize the scan as un-filtered by firmware, set to TRUE below if
+        *   a SSID or BSSID filter is sent in the command
+        */
+       *pfilteredscan = 0;
+
+       /* Initialize the scan as not being only on the current channel.  If
+        *   the channel list is customized, only contains one channel, and
+        *   is the active channel, this is set true and data flow is not halted.
+        */
+       *pscancurrentonly = 0;
+
+       if (puserscanin) {
+
+               /* Set the bss type scan filter, use adapter setting if unset */
+               pscancfgout->bsstype =
+                   (puserscanin->bsstype ? puserscanin->bsstype : adapter->
+                    scanmode);
+
+               /* Set the number of probes to send, use adapter setting if unset */
+               numprobes = (puserscanin->numprobes ? puserscanin->numprobes :
+                            adapter->scanprobes);
+
+               /*
+                * Set the BSSID filter to the incoming configuration,
+                *   if non-zero.  If not set, it will remain disabled (all zeros).
+                */
+               memcpy(pscancfgout->specificBSSID,
+                      puserscanin->specificBSSID,
+                      sizeof(pscancfgout->specificBSSID));
+
+               ssidlen = strlen(puserscanin->specificSSID);
+
+               if (ssidlen) {
+                       pssidtlv =
+                           (struct mrvlietypes_ssidparamset *) pscancfgout->
+                           tlvbuffer;
+                       pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+                       pssidtlv->header.len = cpu_to_le16(ssidlen);
+                       memcpy(pssidtlv->ssid, puserscanin->specificSSID,
+                              ssidlen);
+                       ptlvpos += sizeof(pssidtlv->header) + ssidlen;
+               }
+
+               /*
+                *  The default number of channels sent in the command is low to
+                *    ensure the response buffer from the firmware does not truncate
+                *    scan results.  That is not an issue with an SSID or BSSID
+                *    filter applied to the scan results in the firmware.
+                */
+               if (ssidlen || (memcmp(pscancfgout->specificBSSID,
+                                      &zeromac, sizeof(zeromac)) != 0)) {
+                       *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
+                       *pfilteredscan = 1;
+               }
+       } else {
+               pscancfgout->bsstype = adapter->scanmode;
+               numprobes = adapter->scanprobes;
+       }
+
+       /* If the input config or adapter has the number of Probes set, add tlv */
+       if (numprobes) {
+               pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos;
+               pnumprobestlv->header.type =
+                   cpu_to_le16(TLV_TYPE_NUMPROBES);
+               pnumprobestlv->header.len = sizeof(pnumprobestlv->numprobes);
+               pnumprobestlv->numprobes = cpu_to_le16(numprobes);
+
+               ptlvpos +=
+                   sizeof(pnumprobestlv->header) + pnumprobestlv->header.len;
+
+               pnumprobestlv->header.len =
+                   cpu_to_le16(pnumprobestlv->header.len);
+       }
+
+       /*
+        * Set the output for the channel TLV to the address in the tlv buffer
+        *   past any TLVs that were added in this fuction (SSID, numprobes).
+        *   channel TLVs will be added past this for each scan command, preserving
+        *   the TLVs that were previously added.
+        */
+       *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
+
+       if (puserscanin && puserscanin->chanlist[0].channumber) {
+
+               lbs_pr_debug(1, "Scan: Using supplied channel list\n");
+
+               for (chanidx = 0;
+                    chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+                    && puserscanin->chanlist[chanidx].channumber; chanidx++) {
+
+                       channel = puserscanin->chanlist[chanidx].channumber;
+                       (pscanchanlist + chanidx)->channumber = channel;
+
+                       radiotype = puserscanin->chanlist[chanidx].radiotype;
+                       (pscanchanlist + chanidx)->radiotype = radiotype;
+
+                       scantype = puserscanin->chanlist[chanidx].scantype;
+
+                       if (scantype == cmd_scan_type_passive) {
+                               (pscanchanlist +
+                                chanidx)->chanscanmode.passivescan = 1;
+                       } else {
+                               (pscanchanlist +
+                                chanidx)->chanscanmode.passivescan = 0;
+                       }
+
+                       if (puserscanin->chanlist[chanidx].scantime) {
+                               scandur =
+                                   puserscanin->chanlist[chanidx].scantime;
+                       } else {
+                               if (scantype == cmd_scan_type_passive) {
+                                       scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+                               } else {
+                                       scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+                               }
+                       }
+
+                       (pscanchanlist + chanidx)->minscantime =
+                           cpu_to_le16(scandur);
+                       (pscanchanlist + chanidx)->maxscantime =
+                           cpu_to_le16(scandur);
+               }
+
+               /* Check if we are only scanning the current channel */
+               if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
+                                      ==
+                                      priv->adapter->curbssparams.channel)) {
+                       *pscancurrentonly = 1;
+                       lbs_pr_debug(1, "Scan: Scanning current channel only");
+               }
+
+       } else {
+               lbs_pr_debug(1, "Scan: Creating full region channel list\n");
+               wlan_scan_create_channel_list(priv, pscanchanlist,
+                                             *pfilteredscan);
+       }
+
+out:
+       return pscancfgout;
+}
+
+/**
+ *  @brief Construct and send multiple scan config commands to the firmware
+ *
+ *  Previous routines have created a wlan_scan_cmd_config with any requested
+ *   TLVs.  This function splits the channel TLV into maxchanperscan lists
+ *   and sends the portion of the channel TLV along with the other TLVs
+ *   to the wlan_cmd routines for execution in the firmware.
+ *
+ *  @param priv            A pointer to wlan_private structure
+ *  @param maxchanperscan  Maximum number channels to be included in each
+ *                         scan command sent to firmware
+ *  @param filteredscan    Flag indicating whether or not a BSSID or SSID
+ *                         filter is being used for the firmware command
+ *                         scan command sent to firmware
+ *  @param pscancfgout     Scan configuration used for this scan.
+ *  @param pchantlvout     Pointer in the pscancfgout where the channel TLV
+ *                         should start.  This is past any other TLVs that
+ *                         must be sent down in each firmware command.
+ *  @param pscanchanlist   List of channels to scan in maxchanperscan segments
+ *
+ *  @return                0 or error return otherwise
+ */
+static int wlan_scan_channel_list(wlan_private * priv,
+                                 int maxchanperscan,
+                                 u8 filteredscan,
+                                 struct wlan_scan_cmd_config * pscancfgout,
+                                 struct mrvlietypes_chanlistparamset * pchantlvout,
+                                 struct chanscanparamset * pscanchanlist)
+{
+       struct chanscanparamset *ptmpchan;
+       struct chanscanparamset *pstartchan;
+       u8 scanband;
+       int doneearly;
+       int tlvidx;
+       int ret = 0;
+
+       ENTER();
+
+       if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
+               lbs_pr_debug(1, "Scan: Null detect: %p, %p, %p\n",
+                      pscancfgout, pchantlvout, pscanchanlist);
+               return -1;
+       }
+
+       pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+
+       /* Set the temp channel struct pointer to the start of the desired list */
+       ptmpchan = pscanchanlist;
+
+       /* Loop through the desired channel list, sending a new firmware scan
+        *   commands for each maxchanperscan channels (or for 1,6,11 individually
+        *   if configured accordingly)
+        */
+       while (ptmpchan->channumber) {
+
+               tlvidx = 0;
+               pchantlvout->header.len = 0;
+               scanband = ptmpchan->radiotype;
+               pstartchan = ptmpchan;
+               doneearly = 0;
+
+               /* Construct the channel TLV for the scan command.  Continue to
+                *  insert channel TLVs until:
+                *    - the tlvidx hits the maximum configured per scan command
+                *    - the next channel to insert is 0 (end of desired channel list)
+                *    - doneearly is set (controlling individual scanning of 1,6,11)
+                */
+               while (tlvidx < maxchanperscan && ptmpchan->channumber
+                      && !doneearly) {
+
+            lbs_pr_debug(1,
+                    "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
+                ptmpchan->channumber, ptmpchan->radiotype,
+                ptmpchan->chanscanmode.passivescan,
+                ptmpchan->chanscanmode.disablechanfilt,
+                ptmpchan->maxscantime);
+
+                       /* Copy the current channel TLV to the command being prepared */
+                       memcpy(pchantlvout->chanscanparam + tlvidx,
+                              ptmpchan, sizeof(pchantlvout->chanscanparam));
+
+                       /* Increment the TLV header length by the size appended */
+                       pchantlvout->header.len +=
+                           sizeof(pchantlvout->chanscanparam);
+
+                       /*
+                        *  The tlv buffer length is set to the number of bytes of the
+                        *    between the channel tlv pointer and the start of the
+                        *    tlv buffer.  This compensates for any TLVs that were appended
+                        *    before the channel list.
+                        */
+                       pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
+                                                    - pscancfgout->tlvbuffer);
+
+                       /*  Add the size of the channel tlv header and the data length */
+                       pscancfgout->tlvbufferlen +=
+                           (sizeof(pchantlvout->header)
+                            + pchantlvout->header.len);
+
+                       /* Increment the index to the channel tlv we are constructing */
+                       tlvidx++;
+
+                       doneearly = 0;
+
+                       /* Stop the loop if the *current* channel is in the 1,6,11 set
+                        *   and we are not filtering on a BSSID or SSID.
+                        */
+                       if (!filteredscan && (ptmpchan->channumber == 1
+                                             || ptmpchan->channumber == 6
+                                             || ptmpchan->channumber == 11)) {
+                               doneearly = 1;
+                       }
+
+                       /* Increment the tmp pointer to the next channel to be scanned */
+                       ptmpchan++;
+
+                       /* Stop the loop if the *next* channel is in the 1,6,11 set.
+                        *  This will cause it to be the only channel scanned on the next
+                        *  interation
+                        */
+                       if (!filteredscan && (ptmpchan->channumber == 1
+                                             || ptmpchan->channumber == 6
+                                             || ptmpchan->channumber == 11)) {
+                               doneearly = 1;
+                       }
+               }
+
+               /* Send the scan command to the firmware with the specified cfg */
+               ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0,
+                                           0, 0, pscancfgout);
+       }
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Internal function used to start a scan based on an input config
+ *
+ *  Use the input user scan configuration information when provided in
+ *    order to send the appropriate scan commands to firmware to populate or
+ *    update the internal driver scan table
+ *
+ *  @param priv          A pointer to wlan_private structure
+ *  @param puserscanin   Pointer to the input configuration for the requested
+ *                       scan.
+ *
+ *  @return              0 or < 0 if error
+ */
+int wlan_scan_networks(wlan_private * priv,
+                             const struct wlan_ioctl_user_scan_cfg * puserscanin)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct mrvlietypes_chanlistparamset *pchantlvout;
+       struct chanscanparamset * scan_chan_list = NULL;
+       struct wlan_scan_cmd_config * scan_cfg = NULL;
+       u8 keeppreviousscan;
+       u8 filteredscan;
+       u8 scancurrentchanonly;
+       int maxchanperscan;
+       int ret;
+
+       ENTER();
+
+       scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
+                               WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
+       if (scan_chan_list == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       scan_cfg = wlan_scan_setup_scan_config(priv,
+                                              puserscanin,
+                                              &pchantlvout,
+                                              scan_chan_list,
+                                              &maxchanperscan,
+                                              &filteredscan,
+                                              &scancurrentchanonly);
+       if (scan_cfg == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       keeppreviousscan = 0;
+
+       if (puserscanin) {
+               keeppreviousscan = puserscanin->keeppreviousscan;
+       }
+
+       if (!keeppreviousscan) {
+               memset(adapter->scantable, 0x00,
+                      sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST);
+               adapter->numinscantable = 0;
+       }
+
+       /* Keep the data path active if we are only scanning our current channel */
+       if (!scancurrentchanonly) {
+               netif_stop_queue(priv->wlan_dev.netdev);
+               netif_carrier_off(priv->wlan_dev.netdev);
+       }
+
+       ret = wlan_scan_channel_list(priv,
+                                    maxchanperscan,
+                                    filteredscan,
+                                    scan_cfg,
+                                    pchantlvout,
+                                    scan_chan_list);
+
+       /*  Process the resulting scan table:
+        *    - Remove any bad ssids
+        *    - Update our current BSS information from scan data
+        */
+       wlan_scan_process_results(priv);
+
+       if (priv->adapter->connect_status == libertas_connected) {
+               netif_carrier_on(priv->wlan_dev.netdev);
+               netif_wake_queue(priv->wlan_dev.netdev);
+       }
+
+out:
+       if (scan_cfg)
+               kfree(scan_cfg);
+
+       if (scan_chan_list)
+               kfree(scan_chan_list);
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Inspect the scan response buffer for pointers to expected TLVs
+ *
+ *  TLVs can be included at the end of the scan response BSS information.
+ *    Parse the data in the buffer for pointers to TLVs that can potentially
+ *    be passed back in the response
+ *
+ *  @param ptlv        Pointer to the start of the TLV buffer to parse
+ *  @param tlvbufsize  size of the TLV buffer
+ *  @param ptsftlv     Output parameter: Pointer to the TSF TLV if found
+ *
+ *  @return            void
+ */
+static
+void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
+                                      int tlvbufsize,
+                                      struct mrvlietypes_tsftimestamp ** ptsftlv)
+{
+       struct mrvlietypes_data *pcurrenttlv;
+       int tlvbufleft;
+       u16 tlvtype;
+       u16 tlvlen;
+
+       pcurrenttlv = ptlv;
+       tlvbufleft = tlvbufsize;
+       *ptsftlv = NULL;
+
+       lbs_pr_debug(1, "SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
+       lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
+
+       while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
+               tlvtype = le16_to_cpu(pcurrenttlv->header.type);
+               tlvlen = le16_to_cpu(pcurrenttlv->header.len);
+
+               switch (tlvtype) {
+               case TLV_TYPE_TSFTIMESTAMP:
+                       *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
+                       break;
+
+               default:
+                       lbs_pr_debug(1, "SCAN_RESP: Unhandled TLV = %d\n",
+                              tlvtype);
+                       /* Give up, this seems corrupted */
+                       return;
+               }               /* switch */
+
+               tlvbufleft -= (sizeof(ptlv->header) + tlvlen);
+               pcurrenttlv =
+                   (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen);
+       }                       /* while */
+}
+
+/**
+ *  @brief Interpret a BSS scan response returned from the firmware
+ *
+ *  Parse the various fixed fields and IEs passed back for a a BSS probe
+ *   response or beacon from the scan command.  Record information as needed
+ *   in the scan table struct bss_descriptor for that entry.
+ *
+ *  @param pBSSIDEntry  Output parameter: Pointer to the BSS Entry
+ *
+ *  @return             0 or -1
+ */
+static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry,
+                                        u8 ** pbeaconinfo, int *bytesleft)
+{
+       enum ieeetypes_elementid elemID;
+       struct ieeetypes_fhparamset *pFH;
+       struct ieeetypes_dsparamset *pDS;
+       struct ieeetypes_cfparamset *pCF;
+       struct ieeetypes_ibssparamset *pibss;
+       struct ieeetypes_capinfo *pcap;
+       struct WLAN_802_11_FIXED_IEs fixedie;
+       u8 *pcurrentptr;
+       u8 *pRate;
+       u8 elemlen;
+       u8 bytestocopy;
+       u8 ratesize;
+       u16 beaconsize;
+       u8 founddatarateie;
+       int bytesleftforcurrentbeacon;
+
+       struct WPA_SUPPLICANT *pwpa_supplicant;
+       struct WPA_SUPPLICANT *pwpa2_supplicant;
+       struct IE_WPA *pIe;
+       const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 };
+
+       struct ieeetypes_countryinfoset *pcountryinfo;
+
+       ENTER();
+
+       founddatarateie = 0;
+       ratesize = 0;
+       beaconsize = 0;
+
+       if (*bytesleft >= sizeof(beaconsize)) {
+               /* Extract & convert beacon size from the command buffer */
+               memcpy(&beaconsize, *pbeaconinfo, sizeof(beaconsize));
+               beaconsize = le16_to_cpu(beaconsize);
+               *bytesleft -= sizeof(beaconsize);
+               *pbeaconinfo += sizeof(beaconsize);
+       }
+
+       if (beaconsize == 0 || beaconsize > *bytesleft) {
+
+               *pbeaconinfo += *bytesleft;
+               *bytesleft = 0;
+
+               return -1;
+       }
+
+       /* Initialize the current working beacon pointer for this BSS iteration */
+       pcurrentptr = *pbeaconinfo;
+
+       /* Advance the return beacon pointer past the current beacon */
+       *pbeaconinfo += beaconsize;
+       *bytesleft -= beaconsize;
+
+       bytesleftforcurrentbeacon = beaconsize;
+
+       pwpa_supplicant = &pBSSEntry->wpa_supplicant;
+       pwpa2_supplicant = &pBSSEntry->wpa2_supplicant;
+
+       memcpy(pBSSEntry->macaddress, pcurrentptr, ETH_ALEN);
+       lbs_pr_debug(1, "InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n",
+              pBSSEntry->macaddress[0], pBSSEntry->macaddress[1],
+              pBSSEntry->macaddress[2], pBSSEntry->macaddress[3],
+              pBSSEntry->macaddress[4], pBSSEntry->macaddress[5]);
+
+       pcurrentptr += ETH_ALEN;
+       bytesleftforcurrentbeacon -= ETH_ALEN;
+
+       if (bytesleftforcurrentbeacon < 12) {
+               lbs_pr_debug(1, "InterpretIE: Not enough bytes left\n");
+               return -1;
+       }
+
+       /*
+        * next 4 fields are RSSI, time stamp, beacon interval,
+        *   and capability information
+        */
+
+       /* RSSI is 1 byte long */
+       pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr));
+       lbs_pr_debug(1, "InterpretIE: RSSI=%02X\n", *pcurrentptr);
+       pcurrentptr += 1;
+       bytesleftforcurrentbeacon -= 1;
+
+       /* time stamp is 8 bytes long */
+       memcpy(fixedie.timestamp, pcurrentptr, 8);
+       memcpy(pBSSEntry->timestamp, pcurrentptr, 8);
+       pcurrentptr += 8;
+       bytesleftforcurrentbeacon -= 8;
+
+       /* beacon interval is 2 bytes long */
+       memcpy(&fixedie.beaconinterval, pcurrentptr, 2);
+       pBSSEntry->beaconperiod = le16_to_cpu(fixedie.beaconinterval);
+       pcurrentptr += 2;
+       bytesleftforcurrentbeacon -= 2;
+
+       /* capability information is 2 bytes long */
+       memcpy(&fixedie.capabilities, pcurrentptr, 2);
+       lbs_pr_debug(1, "InterpretIE: fixedie.capabilities=0x%X\n",
+              fixedie.capabilities);
+       fixedie.capabilities = le16_to_cpu(fixedie.capabilities);
+       pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities;
+       memcpy(&pBSSEntry->cap, pcap, sizeof(struct ieeetypes_capinfo));
+       pcurrentptr += 2;
+       bytesleftforcurrentbeacon -= 2;
+
+       /* rest of the current buffer are IE's */
+       lbs_pr_debug(1, "InterpretIE: IElength for this AP = %d\n",
+              bytesleftforcurrentbeacon);
+
+       lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr,
+               bytesleftforcurrentbeacon);
+
+       if (pcap->privacy) {
+               lbs_pr_debug(1, "InterpretIE: AP WEP enabled\n");
+               pBSSEntry->privacy = wlan802_11privfilter8021xWEP;
+       } else {
+               pBSSEntry->privacy = wlan802_11privfilteracceptall;
+       }
+
+       if (pcap->ibss == 1) {
+               pBSSEntry->inframode = wlan802_11ibss;
+       } else {
+               pBSSEntry->inframode = wlan802_11infrastructure;
+       }
+
+       /* process variable IE */
+       while (bytesleftforcurrentbeacon >= 2) {
+               elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
+               elemlen = *((u8 *) pcurrentptr + 1);
+
+               if (bytesleftforcurrentbeacon < elemlen) {
+                       lbs_pr_debug(1, "InterpretIE: error in processing IE, "
+                              "bytes left < IE length\n");
+                       bytesleftforcurrentbeacon = 0;
+                       continue;
+               }
+
+               switch (elemID) {
+
+               case SSID:
+                       pBSSEntry->ssid.ssidlength = elemlen;
+                       memcpy(pBSSEntry->ssid.ssid, (pcurrentptr + 2),
+                              elemlen);
+                       lbs_pr_debug(1, "ssid: %32s", pBSSEntry->ssid.ssid);
+                       break;
+
+               case SUPPORTED_RATES:
+                       memcpy(pBSSEntry->datarates, (pcurrentptr + 2),
+                              elemlen);
+                       memmove(pBSSEntry->libertas_supported_rates, (pcurrentptr + 2),
+                               elemlen);
+                       ratesize = elemlen;
+                       founddatarateie = 1;
+                       break;
+
+               case EXTRA_IE:
+                       lbs_pr_debug(1, "InterpretIE: EXTRA_IE Found!\n");
+                       pBSSEntry->extra_ie = 1;
+                       break;
+
+               case FH_PARAM_SET:
+                       pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
+                       memmove(&pBSSEntry->phyparamset.fhparamset, pFH,
+                               sizeof(struct ieeetypes_fhparamset));
+                       pBSSEntry->phyparamset.fhparamset.dwelltime
+                           =
+                           le16_to_cpu(pBSSEntry->phyparamset.fhparamset.
+                                            dwelltime);
+                       break;
+
+               case DS_PARAM_SET:
+                       pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
+
+                       pBSSEntry->channel = pDS->currentchan;
+
+                       memcpy(&pBSSEntry->phyparamset.dsparamset, pDS,
+                              sizeof(struct ieeetypes_dsparamset));
+                       break;
+
+               case CF_PARAM_SET:
+                       pCF = (struct ieeetypes_cfparamset *) pcurrentptr;
+
+                       memcpy(&pBSSEntry->ssparamset.cfparamset, pCF,
+                              sizeof(struct ieeetypes_cfparamset));
+                       break;
+
+               case IBSS_PARAM_SET:
+                       pibss = (struct ieeetypes_ibssparamset *) pcurrentptr;
+                       pBSSEntry->atimwindow =
+                           le32_to_cpu(pibss->atimwindow);
+
+                       memmove(&pBSSEntry->ssparamset.ibssparamset, pibss,
+                               sizeof(struct ieeetypes_ibssparamset));
+
+                       pBSSEntry->ssparamset.ibssparamset.atimwindow
+                           =
+                           le16_to_cpu(pBSSEntry->ssparamset.ibssparamset.
+                                            atimwindow);
+                       break;
+
+                       /* Handle Country Info IE */
+               case COUNTRY_INFO:
+                       pcountryinfo =
+                           (struct ieeetypes_countryinfoset *) pcurrentptr;
+
+                       if (pcountryinfo->len <
+                           sizeof(pcountryinfo->countrycode)
+                           || pcountryinfo->len > 254) {
+                               lbs_pr_debug(1, "InterpretIE: 11D- Err "
+                                      "CountryInfo len =%d min=%d max=254\n",
+                                      pcountryinfo->len,
+                                      sizeof(pcountryinfo->countrycode));
+                               LEAVE();
+                               return -1;
+                       }
+
+                       memcpy(&pBSSEntry->countryinfo,
+                              pcountryinfo, pcountryinfo->len + 2);
+                       lbs_dbg_hex("InterpretIE: 11D- CountryInfo:",
+                               (u8 *) pcountryinfo,
+                               (u32) (pcountryinfo->len + 2));
+                       break;
+
+               case EXTENDED_SUPPORTED_RATES:
+                       /*
+                        * only process extended supported rate
+                        * if data rate is already found.
+                        * data rate IE should come before
+                        * extended supported rate IE
+                        */
+                       if (founddatarateie) {
+                               if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) {
+                                       bytestocopy =
+                                           (WLAN_SUPPORTED_RATES - ratesize);
+                               } else {
+                                       bytestocopy = elemlen;
+                               }
+
+                               pRate = (u8 *) pBSSEntry->datarates;
+                               pRate += ratesize;
+                               memmove(pRate, (pcurrentptr + 2), bytestocopy);
+
+                               pRate = (u8 *) pBSSEntry->libertas_supported_rates;
+
+                               pRate += ratesize;
+                               memmove(pRate, (pcurrentptr + 2), bytestocopy);
+                       }
+                       break;
+
+               case VENDOR_SPECIFIC_221:
+#define IE_ID_LEN_FIELDS_BYTES 2
+                       pIe = (struct IE_WPA *)pcurrentptr;
+
+                       if (!memcmp(pIe->oui, oui01, sizeof(oui01))) {
+                               pwpa_supplicant->wpa_ie_len
+                                   = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES,
+                                         sizeof(pwpa_supplicant->wpa_ie));
+                               memcpy(pwpa_supplicant->wpa_ie,
+                                      pcurrentptr,
+                                      pwpa_supplicant->wpa_ie_len);
+                               lbs_dbg_hex("InterpretIE: Resp WPA_IE",
+                                       pwpa_supplicant->wpa_ie, elemlen);
+                       }
+                       break;
+               case WPA2_IE:
+                       pIe = (struct IE_WPA *)pcurrentptr;
+                       pwpa2_supplicant->wpa_ie_len
+                           = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES,
+                                 sizeof(pwpa2_supplicant->wpa_ie));
+                       memcpy(pwpa2_supplicant->wpa_ie,
+                              pcurrentptr, pwpa2_supplicant->wpa_ie_len);
+
+                       lbs_dbg_hex("InterpretIE: Resp WPA2_IE",
+                               pwpa2_supplicant->wpa_ie, elemlen);
+                       break;
+               case TIM:
+                       break;
+
+               case CHALLENGE_TEXT:
+                       break;
+               }
+
+               pcurrentptr += elemlen + 2;
+
+               /* need to account for IE ID and IE len */
+               bytesleftforcurrentbeacon -= (elemlen + 2);
+
+       }                       /* while (bytesleftforcurrentbeacon > 2) */
+
+       return 0;
+}
+
+/**
+ *  @brief Compare two SSIDs
+ *
+ *  @param ssid1    A pointer to ssid to compare
+ *  @param ssid2    A pointer to ssid to compare
+ *
+ *  @return         0--ssid is same, otherwise is different
+ */
+int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *ssid2)
+{
+       if (!ssid1 || !ssid2)
+               return -1;
+
+       if (ssid1->ssidlength != ssid2->ssidlength)
+               return -1;
+
+       return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssidlength);
+}
+
+/**
+ *  @brief This function finds a specific compatible BSSID in the scan list
+ *
+ *  @param adapter  A pointer to wlan_adapter
+ *  @param bssid    BSSID to find in the scan list
+ *  @param mode     Network mode: Infrastructure or IBSS
+ *
+ *  @return         index in BSSID list, or error return code (< 0)
+ */
+int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode)
+{
+       int ret = -ENETUNREACH;
+       int i;
+
+       if (!bssid)
+               return -EFAULT;
+
+       lbs_pr_debug(1, "FindBSSID: Num of BSSIDs = %d\n",
+              adapter->numinscantable);
+
+       /* Look through the scan table for a compatible match. The ret return
+        *   variable will be equal to the index in the scan table (greater
+        *   than zero) if the network is compatible.  The loop will continue
+        *   past a matched bssid that is not compatible in case there is an
+        *   AP with multiple SSIDs assigned to the same BSSID
+        */
+       for (i = 0; ret < 0 && i < adapter->numinscantable; i++) {
+               if (!memcmp(adapter->scantable[i].macaddress, bssid, ETH_ALEN)) {
+                       switch (mode) {
+                       case wlan802_11infrastructure:
+                       case wlan802_11ibss:
+                               ret = is_network_compatible(adapter, i, mode);
+                               break;
+                       default:
+                               ret = i;
+                               break;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+/**
+ *  @brief This function finds ssid in ssid list.
+ *
+ *  @param adapter  A pointer to wlan_adapter
+ *  @param ssid     SSID to find in the list
+ *  @param bssid    BSSID to qualify the SSID selection (if provided)
+ *  @param mode     Network mode: Infrastructure or IBSS
+ *
+ *  @return         index in BSSID list
+ */
+int libertas_find_SSID_in_list(wlan_adapter * adapter,
+                  struct WLAN_802_11_SSID *ssid, u8 * bssid, int mode)
+{
+       int net = -ENETUNREACH;
+       u8 bestrssi = 0;
+       int i;
+       int j;
+
+       lbs_pr_debug(1, "Num of Entries in Table = %d\n", adapter->numinscantable);
+
+       for (i = 0; i < adapter->numinscantable; i++) {
+               if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, ssid) &&
+                   (!bssid ||
+                    !memcmp(adapter->scantable[i].
+                            macaddress, bssid, ETH_ALEN))) {
+                       switch (mode) {
+                       case wlan802_11infrastructure:
+                       case wlan802_11ibss:
+                               j = is_network_compatible(adapter, i, mode);
+
+                               if (j >= 0) {
+                                       if (bssid) {
+                                               return i;
+                                       }
+
+                                       if (SCAN_RSSI
+                                           (adapter->scantable[i].rssi)
+                                           > bestrssi) {
+                                               bestrssi =
+                                                   SCAN_RSSI(adapter->
+                                                             scantable[i].
+                                                             rssi);
+                                               net = i;
+                                       }
+                               } else {
+                                       if (net == -ENETUNREACH) {
+                                               net = j;
+                                       }
+                               }
+                               break;
+                       case wlan802_11autounknown:
+                       default:
+                               if (SCAN_RSSI(adapter->scantable[i].rssi)
+                                   > bestrssi) {
+                                       bestrssi =
+                                           SCAN_RSSI(adapter->scantable[i].
+                                                     rssi);
+                                       net = i;
+                               }
+                               break;
+                       }
+               }
+       }
+
+       return net;
+}
+
+/**
+ *  @brief This function finds the best SSID in the Scan List
+ *
+ *  Search the scan table for the best SSID that also matches the current
+ *   adapter network preference (infrastructure or adhoc)
+ *
+ *  @param adapter  A pointer to wlan_adapter
+ *
+ *  @return         index in BSSID list
+ */
+int libertas_find_best_SSID_in_list(wlan_adapter * adapter,
+                                    enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode)
+{
+       int bestnet = -ENETUNREACH;
+       u8 bestrssi = 0;
+       int i;
+
+       ENTER();
+
+       lbs_pr_debug(1, "Num of BSSIDs = %d\n", adapter->numinscantable);
+
+       for (i = 0; i < adapter->numinscantable; i++) {
+               switch (mode) {
+               case wlan802_11infrastructure:
+               case wlan802_11ibss:
+                       if (is_network_compatible(adapter, i, mode) >= 0) {
+                               if (SCAN_RSSI(adapter->scantable[i].rssi) >
+                                   bestrssi) {
+                                       bestrssi =
+                                           SCAN_RSSI(adapter->scantable[i].
+                                                     rssi);
+                                       bestnet = i;
+                               }
+                       }
+                       break;
+               case wlan802_11autounknown:
+               default:
+                       if (SCAN_RSSI(adapter->scantable[i].rssi) > bestrssi) {
+                               bestrssi =
+                                   SCAN_RSSI(adapter->scantable[i].rssi);
+                               bestnet = i;
+                       }
+                       break;
+               }
+       }
+
+       LEAVE();
+       return bestnet;
+}
+
+/**
+ *  @brief Find the AP with specific ssid in the scan list
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param pSSID        A pointer to AP's ssid
+ *
+ *  @return             0--success, otherwise--fail
+ */
+int libertas_find_best_network_SSID(wlan_private * priv,
+                                    struct WLAN_802_11_SSID *pSSID,
+                                    enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
+                                    enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       struct bss_descriptor *preqbssid;
+       int i;
+
+       ENTER();
+
+       memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID));
+
+       wlan_scan_networks(priv, NULL);
+       if (adapter->surpriseremoved)
+               return -1;
+       wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
+
+       i = libertas_find_best_SSID_in_list(adapter, preferred_mode);
+       if (i < 0) {
+               ret = -1;
+               goto out;
+       }
+
+       preqbssid = &adapter->scantable[i];
+       memcpy(pSSID, &preqbssid->ssid,
+              sizeof(struct WLAN_802_11_SSID));
+       *out_mode = preqbssid->inframode;
+
+       if (!pSSID->ssidlength) {
+               ret = -1;
+       }
+
+out:
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Scan Network
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param vwrq         A pointer to iw_param structure
+ *  @param extra        A pointer to extra data buf
+ *
+ *  @return             0 --success, otherwise fail
+ */
+int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+                 struct iw_param *vwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       union iwreq_data wrqu;
+
+       ENTER();
+
+       if (!wlan_scan_networks(priv, NULL)) {
+               memset(&wrqu, 0, sizeof(union iwreq_data));
+               wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+                                   NULL);
+       }
+
+       if (adapter->surpriseremoved)
+               return -1;
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief Send a scan command for all available channels filtered on a spec
+ *
+ *  @param priv             A pointer to wlan_private structure
+ *  @param prequestedssid   A pointer to AP's ssid
+ *  @param keeppreviousscan Flag used to save/clear scan table before scan
+ *
+ *  @return                0-success, otherwise fail
+ */
+int libertas_send_specific_SSID_scan(wlan_private * priv,
+                        struct WLAN_802_11_SSID *prequestedssid,
+                        u8 keeppreviousscan)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct wlan_ioctl_user_scan_cfg scancfg;
+
+       ENTER();
+
+       if (prequestedssid == NULL) {
+               return -1;
+       }
+
+       memset(&scancfg, 0x00, sizeof(scancfg));
+
+       memcpy(scancfg.specificSSID, prequestedssid->ssid,
+              prequestedssid->ssidlength);
+       scancfg.keeppreviousscan = keeppreviousscan;
+
+       wlan_scan_networks(priv, &scancfg);
+       if (adapter->surpriseremoved)
+               return -1;
+       wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief scan an AP with specific BSSID
+ *
+ *  @param priv             A pointer to wlan_private structure
+ *  @param bssid            A pointer to AP's bssid
+ *  @param keeppreviousscan Flag used to save/clear scan table before scan
+ *
+ *  @return          0-success, otherwise fail
+ */
+int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppreviousscan)
+{
+       struct wlan_ioctl_user_scan_cfg scancfg;
+
+       ENTER();
+
+       if (bssid == NULL) {
+               return -1;
+       }
+
+       memset(&scancfg, 0x00, sizeof(scancfg));
+       memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID));
+       scancfg.keeppreviousscan = keeppreviousscan;
+
+       wlan_scan_networks(priv, &scancfg);
+       if (priv->adapter->surpriseremoved)
+               return -1;
+       wait_event_interruptible(priv->adapter->cmd_pending,
+               !priv->adapter->nr_cmd_pending);
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief  Retrieve the scan table entries via wireless tools IOCTL call
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *
+ *  @return             0 --success, otherwise fail
+ */
+int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+                 struct iw_point *dwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       char *current_ev = extra;
+       char *end_buf = extra + IW_SCAN_MAX_DATA;
+       struct chan_freq_power *cfp;
+       struct bss_descriptor *pscantable;
+       char *current_val;      /* For rates */
+       struct iw_event iwe;    /* Temporary buffer */
+       int i;
+       int j;
+       int rate;
+#define PERFECT_RSSI ((u8)50)
+#define WORST_RSSI   ((u8)0)
+#define RSSI_DIFF    ((u8)(PERFECT_RSSI - WORST_RSSI))
+       u8 rssi;
+
+       u8 buf[16 + 256 * 2];
+       u8 *ptr;
+
+       ENTER();
+
+       /*
+        * if there's either commands in the queue or one being
+        * processed return -EAGAIN for iwlist to retry later.
+        */
+    if (adapter->nr_cmd_pending)
+               return -EAGAIN;
+
+       if (adapter->connect_status == libertas_connected)
+               lbs_pr_debug(1, "Current ssid: %32s\n",
+                      adapter->curbssparams.ssid.ssid);
+
+       lbs_pr_debug(1, "Scan: Get: numinscantable = %d\n",
+              adapter->numinscantable);
+
+       /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP.
+        * The new API using SIOCGIWSCAN is only limited by buffer size
+        * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes
+        * which is 4096.
+        */
+       for (i = 0; i < adapter->numinscantable; i++) {
+               if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
+                       lbs_pr_debug(1, "i=%d break out: current_ev=%p end_buf=%p "
+                              "MAX_SCAN_CELL_SIZE=%d\n",
+                              i, current_ev, end_buf, MAX_SCAN_CELL_SIZE);
+                       break;
+               }
+
+               pscantable = &adapter->scantable[i];
+
+               lbs_pr_debug(1, "i=%d  ssid: %32s\n", i, pscantable->ssid.ssid);
+
+               cfp =
+                   libertas_find_cfp_by_band_and_channel(adapter, 0,
+                                                pscantable->channel);
+               if (!cfp) {
+                       lbs_pr_debug(1, "Invalid channel number %d\n",
+                              pscantable->channel);
+                       continue;
+               }
+
+               if (!ssid_valid(&adapter->scantable[i].ssid)) {
+                       continue;
+               }
+
+               /* First entry *MUST* be the AP MAC address */
+               iwe.cmd = SIOCGIWAP;
+               iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+               memcpy(iwe.u.ap_addr.sa_data,
+                      &adapter->scantable[i].macaddress, ETH_ALEN);
+
+               iwe.len = IW_EV_ADDR_LEN;
+               current_ev =
+                   iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+               //Add the ESSID
+               iwe.u.data.length = adapter->scantable[i].ssid.ssidlength;
+
+               if (iwe.u.data.length > 32) {
+                       iwe.u.data.length = 32;
+               }
+
+               iwe.cmd = SIOCGIWESSID;
+               iwe.u.data.flags = 1;
+               iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+                                                 adapter->scantable[i].ssid.
+                                                 ssid);
+
+               //Add mode
+               iwe.cmd = SIOCGIWMODE;
+               iwe.u.mode = adapter->scantable[i].inframode + 1;
+               iwe.len = IW_EV_UINT_LEN;
+               current_ev =
+                   iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+               //frequency
+               iwe.cmd = SIOCGIWFREQ;
+               iwe.u.freq.m = (long)cfp->freq * 100000;
+               iwe.u.freq.e = 1;
+               iwe.len = IW_EV_FREQ_LEN;
+               current_ev =
+                   iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+               /* Add quality statistics */
+               iwe.cmd = IWEVQUAL;
+               iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
+               iwe.u.qual.level = SCAN_RSSI(adapter->scantable[i].rssi);
+
+               rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
+               iwe.u.qual.qual =
+                   (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
+                    (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
+                   (RSSI_DIFF * RSSI_DIFF);
+               if (iwe.u.qual.qual > 100)
+                       iwe.u.qual.qual = 100;
+               else if (iwe.u.qual.qual < 1)
+                       iwe.u.qual.qual = 0;
+
+               if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+                       iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+               } else {
+                       iwe.u.qual.noise =
+                           CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+               }
+               if ((adapter->inframode == wlan802_11ibss) &&
+                   !libertas_SSID_cmp(&adapter->curbssparams.ssid,
+                            &adapter->scantable[i].ssid)
+                   && adapter->adhoccreate) {
+                       ret = libertas_prepare_and_send_command(priv,
+                                                   cmd_802_11_rssi,
+                                                   0,
+                                                   cmd_option_waitforrsp,
+                                                   0, NULL);
+
+                       if (!ret) {
+                               iwe.u.qual.level =
+                                   CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] /
+                                            AVG_SCALE,
+                                            adapter->NF[TYPE_RXPD][TYPE_AVG] /
+                                            AVG_SCALE);
+                       }
+               }
+               iwe.len = IW_EV_QUAL_LEN;
+               current_ev =
+                   iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+               /* Add encryption capability */
+               iwe.cmd = SIOCGIWENCODE;
+               if (adapter->scantable[i].privacy) {
+                       iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+               } else {
+                       iwe.u.data.flags = IW_ENCODE_DISABLED;
+               }
+               iwe.u.data.length = 0;
+               iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+                                                 adapter->scantable->ssid.
+                                                 ssid);
+
+               current_val = current_ev + IW_EV_LCP_LEN;
+
+               iwe.cmd = SIOCGIWRATE;
+
+               iwe.u.bitrate.fixed = 0;
+               iwe.u.bitrate.disabled = 0;
+               iwe.u.bitrate.value = 0;
+
+               /* Bit rate given in 500 kb/s units (+ 0x80) */
+               for (j = 0; j < sizeof(adapter->scantable[i].libertas_supported_rates);
+                    j++) {
+                       if (adapter->scantable[i].libertas_supported_rates[j] == 0) {
+                               break;
+                       }
+                       rate =
+                           (adapter->scantable[i].libertas_supported_rates[j] & 0x7F) *
+                           500000;
+                       if (rate > iwe.u.bitrate.value) {
+                               iwe.u.bitrate.value = rate;
+                       }
+
+                       iwe.u.bitrate.value =
+                           (adapter->scantable[i].libertas_supported_rates[j]
+                            & 0x7f) * 500000;
+                       iwe.len = IW_EV_PARAM_LEN;
+                       current_ev =
+                           iwe_stream_add_value(current_ev, current_val,
+                                                end_buf, &iwe, iwe.len);
+
+               }
+               if ((adapter->scantable[i].inframode == wlan802_11ibss)
+                   && !libertas_SSID_cmp(&adapter->curbssparams.ssid,
+                               &adapter->scantable[i].ssid)
+                   && adapter->adhoccreate) {
+                       iwe.u.bitrate.value = 22 * 500000;
+               }
+               iwe.len = IW_EV_PARAM_LEN;
+               current_ev =
+                   iwe_stream_add_value(current_ev, current_val, end_buf, &iwe,
+                                        iwe.len);
+
+               /* Add new value to event */
+               current_val = current_ev + IW_EV_LCP_LEN;
+
+               if (adapter->scantable[i].wpa2_supplicant.wpa_ie[0] == WPA2_IE) {
+                       memset(&iwe, 0, sizeof(iwe));
+                       memset(buf, 0, sizeof(buf));
+                       memcpy(buf, adapter->scantable[i].
+                                               wpa2_supplicant.wpa_ie,
+                                       adapter->scantable[i].wpa2_supplicant.
+                                               wpa_ie_len);
+                       iwe.cmd = IWEVGENIE;
+                       iwe.u.data.length = adapter->scantable[i].
+                                       wpa2_supplicant.wpa_ie_len;
+                       iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                                       &iwe, buf);
+               }
+               if (adapter->scantable[i].wpa_supplicant.wpa_ie[0] == WPA_IE) {
+                       memset(&iwe, 0, sizeof(iwe));
+                       memset(buf, 0, sizeof(buf));
+                       memcpy(buf, adapter->scantable[i].
+                                               wpa_supplicant.wpa_ie,
+                                       adapter->scantable[i].wpa_supplicant.
+                                               wpa_ie_len);
+                       iwe.cmd = IWEVGENIE;
+                       iwe.u.data.length = adapter->scantable[i].
+                                       wpa_supplicant.wpa_ie_len;
+                       iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                                       &iwe, buf);
+               }
+
+
+               if (adapter->scantable[i].extra_ie != 0) {
+                       memset(&iwe, 0, sizeof(iwe));
+                       memset(buf, 0, sizeof(buf));
+                       ptr = buf;
+                       ptr += sprintf(ptr, "extra_ie");
+                       iwe.u.data.length = strlen(buf);
+
+                       lbs_pr_debug(1, "iwe.u.data.length %d\n",
+                              iwe.u.data.length);
+                       lbs_pr_debug(1, "BUF: %s \n", buf);
+
+                       iwe.cmd = IWEVCUSTOM;
+                       iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+                       current_ev =
+                           iwe_stream_add_point(current_ev, end_buf, &iwe,
+                                                buf);
+               }
+
+               current_val = current_ev + IW_EV_LCP_LEN;
+
+               /*
+                * Check if we added any event
+                */
+               if ((current_val - current_ev) > IW_EV_LCP_LEN)
+                       current_ev = current_val;
+       }
+
+       dwrq->length = (current_ev - extra);
+       dwrq->flags = 0;
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief Prepare a scan command to be sent to the firmware
+ *
+ *  Use the wlan_scan_cmd_config sent to the command processing module in
+ *   the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command
+ *   struct to send to firmware.
+ *
+ *  The fixed fields specifying the BSS type and BSSID filters as well as a
+ *   variable number/length of TLVs are sent in the command to firmware.
+ *
+ *  @param priv       A pointer to wlan_private structure
+ *  @param cmd        A pointer to cmd_ds_command structure to be sent to
+ *                    firmware with the cmd_DS_801_11_SCAN structure
+ *  @param pdata_buf  Void pointer cast of a wlan_scan_cmd_config struct used
+ *                    to set the fields/TLVs for the command sent to firmware
+ *
+ *  @return           0 or -1
+ *
+ *  @sa wlan_scan_create_channel_list
+ */
+int libertas_cmd_80211_scan(wlan_private * priv,
+                        struct cmd_ds_command *cmd, void *pdata_buf)
+{
+       struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
+       struct wlan_scan_cmd_config *pscancfg;
+
+       ENTER();
+
+       pscancfg = pdata_buf;
+
+       /* Set fixed field variables in scan command */
+       pscan->bsstype = pscancfg->bsstype;
+       memcpy(pscan->BSSID, pscancfg->specificBSSID, sizeof(pscan->BSSID));
+       memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
+
+       cmd->command = cpu_to_le16(cmd_802_11_scan);
+
+       /* size is equal to the sizeof(fixed portions) + the TLV len + header */
+       cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
+                                    + sizeof(pscan->BSSID)
+                                    + pscancfg->tlvbufferlen + S_DS_GEN);
+
+       lbs_pr_debug(1, "SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
+              cmd->command, cmd->size, cmd->seqnum);
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief This function handles the command response of scan
+ *
+ *   The response buffer for the scan command has the following
+ *      memory layout:
+ *
+ *     .-----------------------------------------------------------.
+ *     |  header (4 * sizeof(u16)):  Standard command response hdr |
+ *     .-----------------------------------------------------------.
+ *     |  bufsize (u16) : sizeof the BSS Description data          |
+ *     .-----------------------------------------------------------.
+ *     |  NumOfSet (u8) : Number of BSS Descs returned             |
+ *     .-----------------------------------------------------------.
+ *     |  BSSDescription data (variable, size given in bufsize)    |
+ *     .-----------------------------------------------------------.
+ *     |  TLV data (variable, size calculated using header->size,  |
+ *     |            bufsize and sizeof the fixed fields above)     |
+ *     .-----------------------------------------------------------.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to cmd_ds_command
+ *
+ *  @return        0 or -1
+ */
+int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct cmd_ds_802_11_scan_rsp *pscan;
+       struct bss_descriptor newbssentry;
+       struct mrvlietypes_data *ptlv;
+       struct mrvlietypes_tsftimestamp *ptsftlv;
+       u8 *pbssinfo;
+       u16 scanrespsize;
+       int bytesleft;
+       int numintable;
+       int bssIdx;
+       int idx;
+       int tlvbufsize;
+       u64 tsfval;
+
+       ENTER();
+
+       pscan = &resp->params.scanresp;
+
+       if (pscan->nr_sets > MRVDRV_MAX_BSSID_LIST) {
+        lbs_pr_debug(1,
+                      "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+                      pscan->nr_sets);
+               LEAVE();
+               return -1;
+       }
+
+       bytesleft = le16_to_cpu(pscan->bssdescriptsize);
+       lbs_pr_debug(1, "SCAN_RESP: bssdescriptsize %d\n", bytesleft);
+
+       scanrespsize = le16_to_cpu(resp->size);
+       lbs_pr_debug(1, "SCAN_RESP: returned %d AP before parsing\n",
+              pscan->nr_sets);
+
+       numintable = adapter->numinscantable;
+       pbssinfo = pscan->bssdesc_and_tlvbuffer;
+
+       /* The size of the TLV buffer is equal to the entire command response
+        *   size (scanrespsize) minus the fixed fields (sizeof()'s), the
+        *   BSS Descriptions (bssdescriptsize as bytesLef) and the command
+        *   response header (S_DS_GEN)
+        */
+       tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize)
+                                    + sizeof(pscan->nr_sets)
+                                    + S_DS_GEN);
+
+       ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft);
+
+       /* Search the TLV buffer space in the scan response for any valid TLVs */
+       wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv);
+
+       /*
+        *  Process each scan response returned (pscan->nr_sets).  Save
+        *    the information in the newbssentry and then insert into the
+        *    driver scan table either as an update to an existing entry
+        *    or as an addition at the end of the table
+        */
+       for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) {
+               /* Zero out the newbssentry we are about to store info in */
+               memset(&newbssentry, 0x00, sizeof(newbssentry));
+
+               /* Process the data fields and IEs returned for this BSS */
+               if ((InterpretBSSDescriptionWithIE(&newbssentry,
+                                                  &pbssinfo,
+                                                  &bytesleft) ==
+                    0)
+                   && CHECK_SSID_IS_VALID(&newbssentry.ssid)) {
+
+            lbs_pr_debug(1,
+                              "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                              newbssentry.macaddress[0],
+                              newbssentry.macaddress[1],
+                              newbssentry.macaddress[2],
+                              newbssentry.macaddress[3],
+                              newbssentry.macaddress[4],
+                              newbssentry.macaddress[5]);
+
+                       /*
+                        * Search the scan table for the same bssid
+                        */
+                       for (bssIdx = 0; bssIdx < numintable; bssIdx++) {
+                               if (memcmp(newbssentry.macaddress,
+                                          adapter->scantable[bssIdx].
+                                          macaddress,
+                                          sizeof(newbssentry.macaddress)) ==
+                                   0) {
+                                       /*
+                                        * If the SSID matches as well, it is a duplicate of
+                                        *   this entry.  Keep the bssIdx set to this
+                                        *   entry so we replace the old contents in the table
+                                        */
+                                       if ((newbssentry.ssid.ssidlength ==
+                                            adapter->scantable[bssIdx].ssid.
+                                            ssidlength)
+                                           &&
+                                           (memcmp
+                                            (newbssentry.ssid.ssid,
+                                             adapter->scantable[bssIdx].ssid.
+                                             ssid,
+                                             newbssentry.ssid.ssidlength) ==
+                                            0)) {
+                        lbs_pr_debug(1,
+                                                      "SCAN_RESP: Duplicate of index: %d\n",
+                                                      bssIdx);
+                                               break;
+                                       }
+                               }
+                       }
+                       /*
+                        * If the bssIdx is equal to the number of entries in the table,
+                        *   the new entry was not a duplicate; append it to the scan
+                        *   table
+                        */
+                       if (bssIdx == numintable) {
+                               /* Range check the bssIdx, keep it limited to the last entry */
+                               if (bssIdx == MRVDRV_MAX_BSSID_LIST) {
+                                       bssIdx--;
+                               } else {
+                                       numintable++;
+                               }
+                       }
+
+                       /*
+                        * If the TSF TLV was appended to the scan results, save the
+                        *   this entries TSF value in the networktsf field.  The
+                        *   networktsf is the firmware's TSF value at the time the
+                        *   beacon or probe response was received.
+                        */
+                       if (ptsftlv) {
+                               memcpy(&tsfval, &ptsftlv->tsftable[idx],
+                                      sizeof(tsfval));
+                               tsfval = le64_to_cpu(tsfval);
+
+                               memcpy(&newbssentry.networktsf,
+                                      &tsfval, sizeof(newbssentry.networktsf));
+                       }
+
+                       /* Copy the locally created newbssentry to the scan table */
+                       memcpy(&adapter->scantable[bssIdx],
+                              &newbssentry,
+                              sizeof(adapter->scantable[bssIdx]));
+
+               } else {
+
+                       /* error parsing/interpreting the scan response, skipped */
+                       lbs_pr_debug(1, "SCAN_RESP: "
+                              "InterpretBSSDescriptionWithIE returned ERROR\n");
+               }
+       }
+
+       lbs_pr_debug(1, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+              pscan->nr_sets, numintable - adapter->numinscantable,
+              numintable);
+
+       /* Update the total number of BSSIDs in the scan table */
+       adapter->numinscantable = numintable;
+
+       LEAVE();
+       return 0;
+}
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
new file mode 100644 (file)
index 0000000..d93aa7f
--- /dev/null
@@ -0,0 +1,216 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+  * Interface for the wlan network scan routines
+  *
+  * Driver interface functions and type declarations for the scan module
+  *   implemented in wlan_scan.c.
+  */
+#ifndef _WLAN_SCAN_H
+#define _WLAN_SCAN_H
+
+#include "hostcmd.h"
+
+/**
+ *  @brief Maximum number of channels that can be sent in a setuserscan ioctl
+ *
+ *  @sa wlan_ioctl_user_scan_cfg
+ */
+#define WLAN_IOCTL_USER_SCAN_CHAN_MAX  50
+
+//! Infrastructure BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_BSS         1
+
+//! Adhoc BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_IBSS        2
+
+//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter
+#define WLAN_SCAN_BSS_TYPE_ANY         3
+
+/**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command processing module to configure the firmware
+ *   scan command prepared by libertas_cmd_80211_scan.
+ *
+ * @sa wlan_scan_networks
+ *
+ */
+struct wlan_scan_cmd_config {
+    /**
+     *  @brief BSS type to be sent in the firmware command
+     *
+     *  Field can be used to restrict the types of networks returned in the
+     *    scan.  valid settings are:
+     *
+     *   - WLAN_SCAN_BSS_TYPE_BSS  (infrastructure)
+     *   - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+     *   - WLAN_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
+     */
+       u8 bsstype;
+
+    /**
+     *  @brief Specific BSSID used to filter scan results in the firmware
+     */
+       u8 specificBSSID[ETH_ALEN];
+
+    /**
+     *  @brief length of TLVs sent in command starting at tlvBuffer
+     */
+       int tlvbufferlen;
+
+    /**
+     *  @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+     *
+     *  @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t
+     *  @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t
+     */
+       u8 tlvbuffer[1];        //!< SSID TLV(s) and ChanList TLVs are stored here
+};
+
+/**
+ *  @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ *  Multiple instances of this structure are included in the IOCTL command
+ *   to configure a instance of a scan on the specific channel.
+ */
+struct wlan_ioctl_user_scan_chan {
+       u8 channumber;          //!< channel Number to scan
+       u8 radiotype;           //!< Radio type: 'B/G' band = 0, 'A' band = 1
+       u8 scantype;            //!< Scan type: Active = 0, Passive = 1
+       u16 scantime;           //!< Scan duration in milliseconds; if 0 default used
+};
+
+/**
+ *  @brief IOCTL input structure to configure an immediate scan cmd to firmware
+ *
+ *  Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl.  Specifies
+ *   a number of parameters to be used in general for the scan as well
+ *   as a channel list (wlan_ioctl_user_scan_chan) for each scan period
+ *   desired.
+ *
+ *  @sa libertas_set_user_scan_ioctl
+ */
+struct wlan_ioctl_user_scan_cfg {
+
+    /**
+     *  @brief Flag set to keep the previous scan table intact
+     *
+     *  If set, the scan results will accumulate, replacing any previous
+     *   matched entries for a BSS with the new scan data
+     */
+       u8 keeppreviousscan;    //!< Do not erase the existing scan results
+
+    /**
+     *  @brief BSS type to be sent in the firmware command
+     *
+     *  Field can be used to restrict the types of networks returned in the
+     *    scan.  valid settings are:
+     *
+     *   - WLAN_SCAN_BSS_TYPE_BSS  (infrastructure)
+     *   - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+     *   - WLAN_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
+     */
+       u8 bsstype;
+
+    /**
+     *  @brief Configure the number of probe requests for active chan scans
+     */
+       u8 numprobes;
+
+    /**
+     *  @brief BSSID filter sent in the firmware command to limit the results
+     */
+       u8 specificBSSID[ETH_ALEN];
+
+    /**
+     *  @brief SSID filter sent in the firmware command to limit the results
+     */
+       char specificSSID[IW_ESSID_MAX_SIZE + 1];
+
+    /**
+     *  @brief Variable number (fixed maximum) of channels to scan up
+     */
+       struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+};
+
+/**
+ *  @brief Structure used to store information for each beacon/probe response
+ */
+struct bss_descriptor {
+       u8 macaddress[ETH_ALEN];
+
+       struct WLAN_802_11_SSID ssid;
+
+       /* WEP encryption requirement */
+       u32 privacy;
+
+       /* receive signal strength in dBm */
+       long rssi;
+
+       u32 channel;
+
+       u16 beaconperiod;
+
+       u32 atimwindow;
+
+       enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
+       u8 libertas_supported_rates[WLAN_SUPPORTED_RATES];
+
+       int extra_ie;
+
+       u8 timestamp[8];        //!< TSF value included in the beacon/probe response
+       union ieeetypes_phyparamset phyparamset;
+       union IEEEtypes_ssparamset ssparamset;
+       struct ieeetypes_capinfo cap;
+       u8 datarates[WLAN_SUPPORTED_RATES];
+
+       __le64 networktsf;              //!< TSF timestamp from the current firmware TSF
+
+       struct ieeetypes_countryinfofullset countryinfo;
+
+       struct WPA_SUPPLICANT wpa_supplicant;
+       struct WPA_SUPPLICANT wpa2_supplicant;
+
+};
+
+extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1,
+                  struct WLAN_802_11_SSID *ssid2);
+extern int libertas_find_SSID_in_list(wlan_adapter * adapter, struct WLAN_802_11_SSID *ssid,
+                         u8 * bssid, int mode);
+int libertas_find_best_SSID_in_list(wlan_adapter * adapter, enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode);
+extern int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode);
+
+int libertas_find_best_network_SSID(wlan_private * priv,
+                       struct WLAN_802_11_SSID *pSSID,
+                       enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
+                       enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode);
+
+extern int libertas_send_specific_SSID_scan(wlan_private * priv,
+                               struct WLAN_802_11_SSID *prequestedssid,
+                               u8 keeppreviousscan);
+extern int libertas_send_specific_BSSID_scan(wlan_private * priv,
+                                u8 * bssid, u8 keeppreviousscan);
+
+extern int libertas_cmd_80211_scan(wlan_private * priv,
+                               struct cmd_ds_command *cmd,
+                               void *pdata_buf);
+
+extern int libertas_ret_80211_scan(wlan_private * priv,
+                               struct cmd_ds_command *resp);
+
+int wlan_scan_networks(wlan_private * priv,
+                const struct wlan_ioctl_user_scan_cfg * puserscanin);
+
+struct ifreq;
+
+struct iw_point;
+struct iw_param;
+struct iw_request_info;
+extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+                        struct iw_point *dwrq, char *extra);
+extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+                        struct iw_param *vwrq, char *extra);
+
+#endif                         /* _WLAN_SCAN_H */
diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h
new file mode 100644 (file)
index 0000000..207b8a6
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef        __WLAN_THREAD_H_
+#define        __WLAN_THREAD_H_
+
+#include       <linux/kthread.h>
+
+struct wlan_thread {
+       struct task_struct *task;
+       wait_queue_head_t waitq;
+       pid_t pid;
+       void *priv;
+};
+
+static inline void wlan_activate_thread(struct wlan_thread * thr)
+{
+       /** Record the thread pid */
+       thr->pid = current->pid;
+
+       /** Initialize the wait queue */
+       init_waitqueue_head(&thr->waitq);
+}
+
+static inline void wlan_deactivate_thread(struct wlan_thread * thr)
+{
+       ENTER();
+
+       thr->pid = 0;
+
+       LEAVE();
+}
+
+static inline void wlan_create_thread(int (*wlanfunc) (void *),
+                                     struct wlan_thread * thr, char *name)
+{
+       thr->task = kthread_run(wlanfunc, thr, "%s", name);
+}
+
+static inline int wlan_terminate_thread(struct wlan_thread * thr)
+{
+       ENTER();
+
+       /* Check if the thread is active or not */
+       if (!thr->pid) {
+               printk(KERN_ERR "Thread does not exist\n");
+               return -1;
+       }
+       kthread_stop(thr->task);
+
+       LEAVE();
+       return 0;
+}
+
+#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
new file mode 100644 (file)
index 0000000..82d0622
--- /dev/null
@@ -0,0 +1,285 @@
+/**
+  * This file contains the handling of TX in wlan driver.
+  */
+#include <linux/netdevice.h>
+
+#include "hostcmd.h"
+#include "radiotap.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "wext.h"
+
+/**
+ *  @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
+ *  units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
+ *
+ *  @param rate    Input rate
+ *  @return      Output Rate (0 if invalid)
+ */
+static u32 convert_radiotap_rate_to_mv(u8 rate)
+{
+       switch (rate) {
+       case 2:         /*   1 Mbps */
+               return 0 | (1 << 4);
+       case 4:         /*   2 Mbps */
+               return 1 | (1 << 4);
+       case 11:                /* 5.5 Mbps */
+               return 2 | (1 << 4);
+       case 22:                /*  11 Mbps */
+               return 3 | (1 << 4);
+       case 12:                /*   6 Mbps */
+               return 4 | (1 << 4);
+       case 18:                /*   9 Mbps */
+               return 5 | (1 << 4);
+       case 24:                /*  12 Mbps */
+               return 6 | (1 << 4);
+       case 36:                /*  18 Mbps */
+               return 7 | (1 << 4);
+       case 48:                /*  24 Mbps */
+               return 8 | (1 << 4);
+       case 72:                /*  36 Mbps */
+               return 9 | (1 << 4);
+       case 96:                /*  48 Mbps */
+               return 10 | (1 << 4);
+       case 108:               /*  54 Mbps */
+               return 11 | (1 << 4);
+       }
+       return 0;
+}
+
+/**
+ *  @brief This function processes a single packet and sends
+ *  to IF layer
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param skb     A pointer to skb which includes TX packet
+ *  @return       0 or -1
+ */
+static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       struct txpd localtxpd;
+       struct txpd *plocaltxpd = &localtxpd;
+       u8 *p802x_hdr;
+       struct tx_radiotap_hdr *pradiotap_hdr;
+       u32 new_rate;
+       u8 *ptr = priv->adapter->tmptxbuf;
+
+       ENTER();
+
+       if (priv->adapter->surpriseremoved)
+               return -1;
+
+       if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+               lbs_dbg_hex("TX packet: ", skb->data,
+                        min_t(unsigned int, skb->len, 100));
+
+       if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
+               lbs_pr_debug(1, "Tx error: Bad skb length %d : %d\n",
+                      skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
+               ret = -1;
+               goto done;
+       }
+
+       memset(plocaltxpd, 0, sizeof(struct txpd));
+
+       plocaltxpd->tx_packet_length = skb->len;
+
+       /* offset of actual data */
+       plocaltxpd->tx_packet_location = sizeof(struct txpd);
+
+       /* TxCtrl set by user or default */
+       plocaltxpd->tx_control = adapter->pkttxctrl;
+
+       p802x_hdr = skb->data;
+       if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+
+               /* locate radiotap header */
+               pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
+
+               /* set txpd fields from the radiotap header */
+               new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
+               if (new_rate != 0) {
+                       /* erase tx_control[4:0] */
+                       plocaltxpd->tx_control &= ~0x1f;
+                       /* write new tx_control[4:0] */
+                       plocaltxpd->tx_control |= new_rate;
+               }
+
+               /* skip the radiotap header */
+               p802x_hdr += sizeof(struct tx_radiotap_hdr);
+               plocaltxpd->tx_packet_length -= sizeof(struct tx_radiotap_hdr);
+
+       }
+       /* copy destination address from 802.3 or 802.11 header */
+       if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+               memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
+       else
+               memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
+
+       lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
+
+       if (IS_MESH_FRAME(skb)) {
+               plocaltxpd->tx_control |= TxPD_MESH_FRAME;
+       }
+
+       memcpy(ptr, plocaltxpd, sizeof(struct txpd));
+
+       ptr += sizeof(struct txpd);
+
+       lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, plocaltxpd->tx_packet_length);
+       memcpy(ptr, p802x_hdr, plocaltxpd->tx_packet_length);
+       ret = libertas_sbi_host_to_card(priv, MVMS_DAT,
+                              priv->adapter->tmptxbuf,
+                              plocaltxpd->tx_packet_length +
+                              sizeof(struct txpd));
+
+       if (ret) {
+               lbs_pr_debug(1, "Tx error: libertas_sbi_host_to_card failed: 0x%X\n", ret);
+               goto done;
+       }
+
+       lbs_pr_debug(1, "SendSinglePacket succeeds\n");
+
+      done:
+       if (!ret) {
+               priv->stats.tx_packets++;
+               priv->stats.tx_bytes += skb->len;
+       } else {
+               priv->stats.tx_dropped++;
+               priv->stats.tx_errors++;
+       }
+
+       if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+               /* Keep the skb to echo it back once Tx feedback is
+                  received from FW */
+               skb_orphan(skb);
+               /* stop processing outgoing pkts */
+               netif_stop_queue(priv->wlan_dev.netdev);
+               /* freeze any packets already in our queues */
+               priv->adapter->TxLockFlag = 1;
+       } else {
+               dev_kfree_skb_any(skb);
+               priv->adapter->currenttxskb = NULL;
+       }
+
+       LEAVE();
+       return ret;
+}
+
+
+void libertas_tx_runqueue(wlan_private *priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int i;
+
+       spin_lock(&adapter->txqueue_lock);
+       for (i = 0; i < adapter->tx_queue_idx; i++) {
+               struct sk_buff *skb = adapter->tx_queue_ps[i];
+               spin_unlock(&adapter->txqueue_lock);
+               SendSinglePacket(priv, skb);
+               spin_lock(&adapter->txqueue_lock);
+       }
+       adapter->tx_queue_idx = 0;
+       spin_unlock(&adapter->txqueue_lock);
+}
+
+static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb)
+{
+       wlan_adapter *adapter = priv->adapter;
+
+       spin_lock(&adapter->txqueue_lock);
+
+       WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE);
+       adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb;
+       if (adapter->tx_queue_idx == NR_TX_QUEUE)
+               netif_stop_queue(priv->wlan_dev.netdev);
+       else
+               netif_start_queue(priv->wlan_dev.netdev);
+
+       spin_unlock(&adapter->txqueue_lock);
+}
+
+/**
+ *  @brief This function checks the conditions and sends packet to IF
+ *  layer if everything is ok.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return       n/a
+ */
+int libertas_process_tx(wlan_private * priv, struct sk_buff *skb)
+{
+       int ret = -1;
+
+       ENTER();
+
+       lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+
+       if (priv->wlan_dev.dnld_sent) {
+               lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
+                      priv->wlan_dev.dnld_sent);
+               goto done;
+       }
+
+       if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
+           (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) {
+               wlan_tx_queue(priv, skb);
+               return ret;
+       }
+
+       priv->adapter->currenttxskb = skb;
+
+       ret = SendSinglePacket(priv, skb);
+done:
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief This function sends to the host the last transmitted packet,
+ *  filling the radiotap headers with transmission information.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param status   A 32 bit value containing transmission status.
+ *
+ *  @returns void
+ */
+void libertas_send_tx_feedback(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
+       struct tx_radiotap_hdr *radiotap_hdr;
+       u32 status = adapter->eventcause;
+       int txfail;
+       int try_count;
+
+       if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP ||
+           adapter->currenttxskb == NULL)
+               return;
+
+       radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
+
+       if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+               lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr,
+                       min_t(unsigned int, adapter->currenttxskb->len, 100));
+
+       txfail = (status >> 24);
+
+#if 0
+       /* The version of roofnet that we've tested does not use this yet
+        * But it may be used in the future.
+        */
+       if (txfail)
+               radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL;
+#endif
+       try_count = (status >> 16) & 0xff;
+       radiotap_hdr->data_retries = (try_count) ?
+           (1 + adapter->txretrycount - try_count) : 0;
+       libertas_upload_rx_packet(priv, adapter->currenttxskb);
+       adapter->currenttxskb = NULL;
+       priv->adapter->TxLockFlag = 0;
+       if (priv->adapter->connect_status == libertas_connected)
+               netif_wake_queue(priv->wlan_dev.netdev);
+}
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
new file mode 100644 (file)
index 0000000..09d62f8
--- /dev/null
@@ -0,0 +1,289 @@
+/**
+  * This header file contains definition for global types
+  */
+#ifndef _WLAN_TYPES_
+#define _WLAN_TYPES_
+
+#include <linux/if_ether.h>
+
+/** IEEE type definitions  */
+enum ieeetypes_elementid {
+       SSID = 0,
+       SUPPORTED_RATES,
+       FH_PARAM_SET,
+       DS_PARAM_SET,
+       CF_PARAM_SET,
+       TIM,
+       IBSS_PARAM_SET,
+       COUNTRY_INFO = 7,
+
+       CHALLENGE_TEXT = 16,
+
+       EXTENDED_SUPPORTED_RATES = 50,
+
+       VENDOR_SPECIFIC_221 = 221,
+
+       WPA_IE = 221,
+       WPA2_IE = 48,
+
+       EXTRA_IE = 133,
+} __attribute__ ((packed));
+
+#define CAPINFO_MASK   (~(0xda00))
+
+struct ieeetypes_capinfo {
+       u8 ess:1;
+       u8 ibss:1;
+       u8 cfpollable:1;
+       u8 cfpollrqst:1;
+       u8 privacy:1;
+       u8 shortpreamble:1;
+       u8 pbcc:1;
+       u8 chanagility:1;
+       u8 spectrummgmt:1;
+       u8 rsrvd3:1;
+       u8 shortslottime:1;
+       u8 apsd:1;
+       u8 rsvrd2:1;
+       u8 dsssofdm:1;
+       u8 rsrvd1:2;
+} __attribute__ ((packed));
+
+struct ieeetypes_cfparamset {
+       u8 elementid;
+       u8 len;
+       u8 cfpcnt;
+       u8 cfpperiod;
+       u16 cfpmaxduration;
+       u16 cfpdurationremaining;
+} __attribute__ ((packed));
+
+
+struct ieeetypes_ibssparamset {
+       u8 elementid;
+       u8 len;
+       u16 atimwindow;
+} __attribute__ ((packed));
+
+union IEEEtypes_ssparamset {
+       struct ieeetypes_cfparamset cfparamset;
+       struct ieeetypes_ibssparamset ibssparamset;
+} __attribute__ ((packed));
+
+struct ieeetypes_fhparamset {
+       u8 elementid;
+       u8 len;
+       u16 dwelltime;
+       u8 hopset;
+       u8 hoppattern;
+       u8 hopindex;
+} __attribute__ ((packed));
+
+struct ieeetypes_dsparamset {
+       u8 elementid;
+       u8 len;
+       u8 currentchan;
+} __attribute__ ((packed));
+
+union ieeetypes_phyparamset {
+       struct ieeetypes_fhparamset fhparamset;
+       struct ieeetypes_dsparamset dsparamset;
+} __attribute__ ((packed));
+
+struct ieeetypes_assocrsp {
+       struct ieeetypes_capinfo capability;
+       u16 statuscode;
+       u16 aid;
+       u8 iebuffer[1];
+} __attribute__ ((packed));
+
+/** TLV  type ID definition */
+#define PROPRIETARY_TLV_BASE_ID                0x0100
+
+/* Terminating TLV type */
+#define MRVL_TERMINATE_TLV_ID          0xffff
+
+#define TLV_TYPE_SSID                          0x0000
+#define TLV_TYPE_RATES                         0x0001
+#define TLV_TYPE_PHY_FH                                0x0002
+#define TLV_TYPE_PHY_DS                                0x0003
+#define TLV_TYPE_CF                                0x0004
+#define TLV_TYPE_IBSS                          0x0006
+
+#define TLV_TYPE_DOMAIN                                0x0007
+
+#define TLV_TYPE_POWER_CAPABILITY      0x0021
+
+#define TLV_TYPE_KEY_MATERIAL       (PROPRIETARY_TLV_BASE_ID + 0)
+#define TLV_TYPE_CHANLIST           (PROPRIETARY_TLV_BASE_ID + 1)
+#define TLV_TYPE_NUMPROBES          (PROPRIETARY_TLV_BASE_ID + 2)
+#define TLV_TYPE_RSSI_LOW           (PROPRIETARY_TLV_BASE_ID + 4)
+#define TLV_TYPE_SNR_LOW            (PROPRIETARY_TLV_BASE_ID + 5)
+#define TLV_TYPE_FAILCOUNT          (PROPRIETARY_TLV_BASE_ID + 6)
+#define TLV_TYPE_BCNMISS            (PROPRIETARY_TLV_BASE_ID + 7)
+#define TLV_TYPE_LED_GPIO           (PROPRIETARY_TLV_BASE_ID + 8)
+#define TLV_TYPE_LEDBEHAVIOR        (PROPRIETARY_TLV_BASE_ID + 9)
+#define TLV_TYPE_PASSTHROUGH        (PROPRIETARY_TLV_BASE_ID + 10)
+#define TLV_TYPE_REASSOCAP          (PROPRIETARY_TLV_BASE_ID + 11)
+#define TLV_TYPE_POWER_TBL_2_4GHZ   (PROPRIETARY_TLV_BASE_ID + 12)
+#define TLV_TYPE_POWER_TBL_5GHZ     (PROPRIETARY_TLV_BASE_ID + 13)
+#define TLV_TYPE_BCASTPROBE        (PROPRIETARY_TLV_BASE_ID + 14)
+#define TLV_TYPE_NUMSSID_PROBE     (PROPRIETARY_TLV_BASE_ID + 15)
+#define TLV_TYPE_WMMQSTATUS        (PROPRIETARY_TLV_BASE_ID + 16)
+#define TLV_TYPE_CRYPTO_DATA       (PROPRIETARY_TLV_BASE_ID + 17)
+#define TLV_TYPE_WILDCARDSSID      (PROPRIETARY_TLV_BASE_ID + 18)
+#define TLV_TYPE_TSFTIMESTAMP      (PROPRIETARY_TLV_BASE_ID + 19)
+#define TLV_TYPE_RSSI_HIGH          (PROPRIETARY_TLV_BASE_ID + 22)
+#define TLV_TYPE_SNR_HIGH           (PROPRIETARY_TLV_BASE_ID + 23)
+
+/** TLV related data structures*/
+struct mrvlietypesheader {
+       u16 type;
+       u16 len;
+} __attribute__ ((packed));
+
+struct mrvlietypes_data {
+       struct mrvlietypesheader header;
+       u8 Data[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_ratesparamset {
+       struct mrvlietypesheader header;
+       u8 rates[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_ssidparamset {
+       struct mrvlietypesheader header;
+       u8 ssid[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_wildcardssidparamset {
+       struct mrvlietypesheader header;
+       u8 MaxSsidlength;
+       u8 ssid[1];
+} __attribute__ ((packed));
+
+struct chanscanmode {
+       u8 passivescan:1;
+       u8 disablechanfilt:1;
+       u8 reserved_2_7:6;
+} __attribute__ ((packed));
+
+struct chanscanparamset {
+       u8 radiotype;
+       u8 channumber;
+       struct chanscanmode chanscanmode;
+       u16 minscantime;
+       u16 maxscantime;
+} __attribute__ ((packed));
+
+struct mrvlietypes_chanlistparamset {
+       struct mrvlietypesheader header;
+       struct chanscanparamset chanscanparam[1];
+} __attribute__ ((packed));
+
+struct cfparamset {
+       u8 cfpcnt;
+       u8 cfpperiod;
+       u16 cfpmaxduration;
+       u16 cfpdurationremaining;
+} __attribute__ ((packed));
+
+struct ibssparamset {
+       u16 atimwindow;
+} __attribute__ ((packed));
+
+struct mrvlietypes_ssparamset {
+       struct mrvlietypesheader header;
+       union {
+               struct cfparamset cfparamset[1];
+               struct ibssparamset ibssparamset[1];
+       } cf_ibss;
+} __attribute__ ((packed));
+
+struct fhparamset {
+       u16 dwelltime;
+       u8 hopset;
+       u8 hoppattern;
+       u8 hopindex;
+} __attribute__ ((packed));
+
+struct dsparamset {
+       u8 currentchan;
+} __attribute__ ((packed));
+
+struct mrvlietypes_phyparamset {
+       struct mrvlietypesheader header;
+       union {
+               struct fhparamset fhparamset[1];
+               struct dsparamset dsparamset[1];
+       } fh_ds;
+} __attribute__ ((packed));
+
+struct mrvlietypes_rsnparamset {
+       struct mrvlietypesheader header;
+       u8 rsnie[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_tsftimestamp {
+       struct mrvlietypesheader header;
+       __le64 tsftable[1];
+} __attribute__ ((packed));
+
+/**  Local Power capability */
+struct mrvlietypes_powercapability {
+       struct mrvlietypesheader header;
+       s8 minpower;
+       s8 maxpower;
+} __attribute__ ((packed));
+
+struct mrvlietypes_rssithreshold {
+       struct mrvlietypesheader header;
+       u8 rssivalue;
+       u8 rssifreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_snrthreshold {
+       struct mrvlietypesheader header;
+       u8 snrvalue;
+       u8 snrfreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_failurecount {
+       struct mrvlietypesheader header;
+       u8 failvalue;
+       u8 Failfreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_beaconsmissed {
+       struct mrvlietypesheader header;
+       u8 beaconmissed;
+       u8 reserved;
+} __attribute__ ((packed));
+
+struct mrvlietypes_numprobes {
+       struct mrvlietypesheader header;
+       u16 numprobes;
+} __attribute__ ((packed));
+
+struct mrvlietypes_bcastprobe {
+       struct mrvlietypesheader header;
+       u16 bcastprobe;
+} __attribute__ ((packed));
+
+struct mrvlietypes_numssidprobe {
+       struct mrvlietypesheader header;
+       u16 numssidprobe;
+} __attribute__ ((packed));
+
+struct led_pin {
+       u8 led;
+       u8 pin;
+} __attribute__ ((packed));
+
+struct mrvlietypes_ledgpio {
+       struct mrvlietypesheader header;
+       struct led_pin ledpin[1];
+} __attribute__ ((packed));
+
+#endif                         /* _WLAN_TYPES_ */
diff --git a/drivers/net/wireless/libertas/version.h b/drivers/net/wireless/libertas/version.h
new file mode 100644 (file)
index 0000000..e86f65a
--- /dev/null
@@ -0,0 +1,8 @@
+#define DRIVER_RELEASE_VERSION "320.p0"
+const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
+#ifdef  DEBUG
+    "-dbg"
+#endif
+    "";
+
+
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
new file mode 100644 (file)
index 0000000..4a52336
--- /dev/null
@@ -0,0 +1,2769 @@
+/**
+  * This file contains ioctl functions
+  */
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/bitops.h>
+
+#include <net/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "version.h"
+#include "wext.h"
+#include "assoc.h"
+
+
+/**
+ *  @brief Convert mw value to dbm value
+ *
+ *  @param mw     the value of mw
+ *  @return       the value of dbm
+ */
+static int mw_to_dbm(int mw)
+{
+       if (mw < 2)
+               return 0;
+       else if (mw < 3)
+               return 3;
+       else if (mw < 4)
+               return 5;
+       else if (mw < 6)
+               return 7;
+       else if (mw < 7)
+               return 8;
+       else if (mw < 8)
+               return 9;
+       else if (mw < 10)
+               return 10;
+       else if (mw < 13)
+               return 11;
+       else if (mw < 16)
+               return 12;
+       else if (mw < 20)
+               return 13;
+       else if (mw < 25)
+               return 14;
+       else if (mw < 32)
+               return 15;
+       else if (mw < 40)
+               return 16;
+       else if (mw < 50)
+               return 17;
+       else if (mw < 63)
+               return 18;
+       else if (mw < 79)
+               return 19;
+       else if (mw < 100)
+               return 20;
+       else
+               return 21;
+}
+
+/**
+ *  @brief Find the channel frequency power info with specific channel
+ *
+ *  @param adapter     A pointer to wlan_adapter structure
+ *  @param band                it can be BAND_A, BAND_G or BAND_B
+ *  @param channel      the channel for looking
+ *  @return            A pointer to struct chan_freq_power structure or NULL if not find.
+ */
+struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
+                                                u8 band, u16 channel)
+{
+       struct chan_freq_power *cfp = NULL;
+       struct region_channel *rc;
+       int count = sizeof(adapter->region_channel) /
+           sizeof(adapter->region_channel[0]);
+       int i, j;
+
+       for (j = 0; !cfp && (j < count); j++) {
+               rc = &adapter->region_channel[j];
+
+               if (adapter->enable11d)
+                       rc = &adapter->universal_channel[j];
+               if (!rc->valid || !rc->CFP)
+                       continue;
+               if (rc->band != band)
+                       continue;
+               for (i = 0; i < rc->nrcfp; i++) {
+                       if (rc->CFP[i].channel == channel) {
+                               cfp = &rc->CFP[i];
+                               break;
+                       }
+               }
+       }
+
+       if (!cfp && channel)
+               lbs_pr_debug(1, "libertas_find_cfp_by_band_and_channel(): cannot find "
+                      "cfp by band %d & channel %d\n", band, channel);
+
+       return cfp;
+}
+
+/**
+ *  @brief Find the channel frequency power info with specific frequency
+ *
+ *  @param adapter     A pointer to wlan_adapter structure
+ *  @param band                it can be BAND_A, BAND_G or BAND_B
+ *  @param freq                the frequency for looking
+ *  @return            A pointer to struct chan_freq_power structure or NULL if not find.
+ */
+static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
+                                                    u8 band, u32 freq)
+{
+       struct chan_freq_power *cfp = NULL;
+       struct region_channel *rc;
+       int count = sizeof(adapter->region_channel) /
+           sizeof(adapter->region_channel[0]);
+       int i, j;
+
+       for (j = 0; !cfp && (j < count); j++) {
+               rc = &adapter->region_channel[j];
+
+               if (adapter->enable11d)
+                       rc = &adapter->universal_channel[j];
+               if (!rc->valid || !rc->CFP)
+                       continue;
+               if (rc->band != band)
+                       continue;
+               for (i = 0; i < rc->nrcfp; i++) {
+                       if (rc->CFP[i].freq == freq) {
+                               cfp = &rc->CFP[i];
+                               break;
+                       }
+               }
+       }
+
+       if (!cfp && freq)
+               lbs_pr_debug(1, "find_cfp_by_band_and_freql(): cannot find cfp by "
+                      "band %d & freq %d\n", band, freq);
+
+       return cfp;
+}
+
+static int updatecurrentchannel(wlan_private * priv)
+{
+       int ret;
+
+       /*
+        ** the channel in f/w could be out of sync, get the current channel
+        */
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+                                   cmd_opt_802_11_rf_channel_get,
+                                   cmd_option_waitforrsp, 0, NULL);
+
+       lbs_pr_debug(1, "Current channel = %d\n",
+              priv->adapter->curbssparams.channel);
+
+       return ret;
+}
+
+static int setcurrentchannel(wlan_private * priv, int channel)
+{
+       lbs_pr_debug(1, "Set channel = %d\n", channel);
+
+       /*
+        **  Current channel is not set to adhocchannel requested, set channel
+        */
+       return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+                                     cmd_opt_802_11_rf_channel_set,
+                                     cmd_option_waitforrsp, 0, &channel));
+}
+
+static int changeadhocchannel(wlan_private * priv, int channel)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+
+       adapter->adhocchannel = channel;
+
+       updatecurrentchannel(priv);
+
+       if (adapter->curbssparams.channel == adapter->adhocchannel) {
+               /* adhocchannel is set to the current channel already */
+               LEAVE();
+               return 0;
+       }
+
+       lbs_pr_debug(1, "Updating channel from %d to %d\n",
+              adapter->curbssparams.channel, adapter->adhocchannel);
+
+       setcurrentchannel(priv, adapter->adhocchannel);
+
+       updatecurrentchannel(priv);
+
+       if (adapter->curbssparams.channel != adapter->adhocchannel) {
+               lbs_pr_debug(1, "failed to updated channel to %d, channel = %d\n",
+                      adapter->adhocchannel, adapter->curbssparams.channel);
+               LEAVE();
+               return -1;
+       }
+
+       if (adapter->connect_status == libertas_connected) {
+               int i;
+               struct WLAN_802_11_SSID curadhocssid;
+
+               lbs_pr_debug(1, "channel Changed while in an IBSS\n");
+
+               /* Copy the current ssid */
+               memcpy(&curadhocssid, &adapter->curbssparams.ssid,
+                      sizeof(struct WLAN_802_11_SSID));
+
+               /* Exit Adhoc mode */
+               lbs_pr_debug(1, "In changeadhocchannel(): Sending Adhoc Stop\n");
+               ret = libertas_stop_adhoc_network(priv);
+
+               if (ret) {
+                       LEAVE();
+                       return ret;
+               }
+               /* Scan for the network, do not save previous results.  Stale
+                *   scan data will cause us to join a non-existant adhoc network
+                */
+               libertas_send_specific_SSID_scan(priv, &curadhocssid, 0);
+
+               // find out the BSSID that matches the current SSID
+               i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
+                                  wlan802_11ibss);
+
+               if (i >= 0) {
+                       lbs_pr_debug(1, "SSID found at %d in List,"
+                              "so join\n", i);
+                       libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+               } else {
+                       // else send START command
+                       lbs_pr_debug(1, "SSID not found in list, "
+                              "so creating adhoc with ssid = %s\n",
+                              curadhocssid.ssid);
+                       libertas_start_adhoc_network(priv, &curadhocssid);
+               }               // end of else (START command)
+       }
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief Set Radio On/OFF
+ *
+ *  @param priv                 A pointer to wlan_private structure
+ *  @option                    Radio Option
+ *  @return                    0 --success, otherwise fail
+ */
+int wlan_radio_ioctl(wlan_private * priv, u8 option)
+{
+       int ret = 0;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       if (adapter->radioon != option) {
+               lbs_pr_debug(1, "Switching %s the Radio\n", option ? "On" : "Off");
+               adapter->radioon = option;
+
+               ret = libertas_prepare_and_send_command(priv,
+                                           cmd_802_11_radio_control,
+                                           cmd_act_set,
+                                           cmd_option_waitforrsp, 0, NULL);
+       }
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Copy rates
+ *
+ *  @param dest                 A pointer to Dest Buf
+ *  @param src                 A pointer to Src Buf
+ *  @param len                  The len of Src Buf
+ *  @return                    Number of rates copyed
+ */
+static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
+{
+       int i;
+
+       for (i = 0; i < len && src[i]; i++, pos++) {
+               if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
+                       break;
+               dest[pos] = src[i];
+       }
+
+       return pos;
+}
+
+/**
+ *  @brief Get active data rates
+ *
+ *  @param adapter              A pointer to wlan_adapter structure
+ *  @param rate                        The buf to return the active rates
+ *  @return                    The number of rates
+ */
+static int get_active_data_rates(wlan_adapter * adapter,
+                                u8* rates)
+{
+       int k = 0;
+
+       ENTER();
+
+       if (adapter->connect_status != libertas_connected) {
+               if (adapter->inframode == wlan802_11infrastructure) {
+                       //Infra. mode
+                       lbs_pr_debug(1, "Infra\n");
+                       k = copyrates(rates, k, libertas_supported_rates,
+                                     sizeof(libertas_supported_rates));
+               } else {
+                       //ad-hoc mode
+                       lbs_pr_debug(1, "Adhoc G\n");
+                       k = copyrates(rates, k, libertas_adhoc_rates_g,
+                                     sizeof(libertas_adhoc_rates_g));
+               }
+       } else {
+               k = copyrates(rates, 0, adapter->curbssparams.datarates,
+                             adapter->curbssparams.numofrates);
+       }
+
+       LEAVE();
+
+       return k;
+}
+
+static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
+                        char *cwrq, char *extra)
+{
+       const char *cp;
+       char comm[6] = { "COMM-" };
+       char mrvl[6] = { "MRVL-" };
+       int cnt;
+
+       ENTER();
+
+       strcpy(cwrq, mrvl);
+
+       cp = strstr(libertas_driver_version, comm);
+       if (cp == libertas_driver_version)      //skip leading "COMM-"
+               cp = libertas_driver_version + strlen(comm);
+       else
+               cp = libertas_driver_version;
+
+       cnt = strlen(mrvl);
+       cwrq += cnt;
+       while (cnt < 16 && (*cp != '-')) {
+               *cwrq++ = toupper(*cp++);
+               cnt++;
+       }
+       *cwrq = '\0';
+
+       LEAVE();
+
+       return 0;
+}
+
+static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
+                        struct iw_freq *fwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct chan_freq_power *cfp;
+
+       ENTER();
+
+       cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
+                                          adapter->curbssparams.channel);
+
+       if (!cfp) {
+               if (adapter->curbssparams.channel)
+                       lbs_pr_debug(1, "Invalid channel=%d\n",
+                              adapter->curbssparams.channel);
+               return -EINVAL;
+       }
+
+       fwrq->m = (long)cfp->freq * 100000;
+       fwrq->e = 1;
+
+       lbs_pr_debug(1, "freq=%u\n", fwrq->m);
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
+                       struct sockaddr *awrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       if (adapter->connect_status == libertas_connected) {
+               memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+       } else {
+               memset(awrq->sa_data, 0, ETH_ALEN);
+       }
+       awrq->sa_family = ARPHRD_ETHER;
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
+                        struct iw_point *dwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       /*
+        * Check the size of the string
+        */
+
+       if (dwrq->length > 16) {
+               return -E2BIG;
+       }
+
+       mutex_lock(&adapter->lock);
+       memset(adapter->nodename, 0, sizeof(adapter->nodename));
+       memcpy(adapter->nodename, extra, dwrq->length);
+       mutex_unlock(&adapter->lock);
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
+                        struct iw_point *dwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       /*
+        * Get the Nick Name saved
+        */
+
+       mutex_lock(&adapter->lock);
+       strncpy(extra, adapter->nodename, 16);
+       mutex_unlock(&adapter->lock);
+
+       extra[16] = '\0';
+
+       /*
+        * If none, we may want to get the one that was set
+        */
+
+       /*
+        * Push it out !
+        */
+       dwrq->length = strlen(extra) + 1;
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
+                       struct iw_param *vwrq, char *extra)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       int rthr = vwrq->value;
+
+       ENTER();
+
+       if (vwrq->disabled) {
+               adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
+       } else {
+               if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
+                       return -EINVAL;
+               adapter->rtsthsd = rthr;
+       }
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+                                   cmd_act_set, cmd_option_waitforrsp,
+                                   OID_802_11_RTS_THRESHOLD, &rthr);
+
+       LEAVE();
+       return ret;
+}
+
+static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
+                       struct iw_param *vwrq, char *extra)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       adapter->rtsthsd = 0;
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+                                   cmd_act_get, cmd_option_waitforrsp,
+                                   OID_802_11_RTS_THRESHOLD, NULL);
+       if (ret) {
+               LEAVE();
+               return ret;
+       }
+
+       vwrq->value = adapter->rtsthsd;
+       vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
+                         || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
+       vwrq->fixed = 1;
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
+                        struct iw_param *vwrq, char *extra)
+{
+       int ret = 0;
+       int fthr = vwrq->value;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       if (vwrq->disabled) {
+               adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
+       } else {
+               if (fthr < MRVDRV_FRAG_MIN_VALUE
+                   || fthr > MRVDRV_FRAG_MAX_VALUE)
+                       return -EINVAL;
+               adapter->fragthsd = fthr;
+       }
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+                                   cmd_act_set, cmd_option_waitforrsp,
+                                   OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
+       LEAVE();
+       return ret;
+}
+
+static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
+                        struct iw_param *vwrq, char *extra)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       adapter->fragthsd = 0;
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_snmp_mib,
+                                   cmd_act_get, cmd_option_waitforrsp,
+                                   OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
+       if (ret) {
+               LEAVE();
+               return ret;
+       }
+
+       vwrq->value = adapter->fragthsd;
+       vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
+                         || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
+       vwrq->fixed = 1;
+
+       LEAVE();
+       return ret;
+}
+
+static int wlan_get_mode(struct net_device *dev,
+                        struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       switch (adapter->inframode) {
+       case wlan802_11ibss:
+               *uwrq = IW_MODE_ADHOC;
+               break;
+
+       case wlan802_11infrastructure:
+               *uwrq = IW_MODE_INFRA;
+               break;
+
+       default:
+       case wlan802_11autounknown:
+               *uwrq = IW_MODE_AUTO;
+               break;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_get_txpow(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_rf_tx_power,
+                                   cmd_act_tx_power_opt_get,
+                                   cmd_option_waitforrsp, 0, NULL);
+
+       if (ret) {
+               LEAVE();
+               return ret;
+       }
+
+       lbs_pr_debug(1, "TXPOWER GET %d dbm.\n", adapter->txpowerlevel);
+       vwrq->value = adapter->txpowerlevel;
+       vwrq->fixed = 1;
+       if (adapter->radioon) {
+               vwrq->disabled = 0;
+               vwrq->flags = IW_TXPOW_DBM;
+       } else {
+               vwrq->disabled = 1;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       if (vwrq->flags == IW_RETRY_LIMIT) {
+               /* The MAC has a 4-bit Total_Tx_Count register
+                  Total_Tx_Count = 1 + Tx_Retry_Count */
+#define TX_RETRY_MIN 0
+#define TX_RETRY_MAX 14
+               if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
+                       return -EINVAL;
+
+               /* Adding 1 to convert retry count to try count */
+               adapter->txretrycount = vwrq->value + 1;
+
+               ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+                                           cmd_act_set,
+                                           cmd_option_waitforrsp,
+                                           OID_802_11_TX_RETRYCOUNT, NULL);
+
+               if (ret) {
+                       LEAVE();
+                       return ret;
+               }
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       ENTER();
+       adapter->txretrycount = 0;
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_snmp_mib,
+                                   cmd_act_get, cmd_option_waitforrsp,
+                                   OID_802_11_TX_RETRYCOUNT, NULL);
+       if (ret) {
+               LEAVE();
+               return ret;
+       }
+       vwrq->disabled = 0;
+       if (!vwrq->flags) {
+               vwrq->flags = IW_RETRY_LIMIT;
+               /* Subtract 1 to convert try count to retry count */
+               vwrq->value = adapter->txretrycount - 1;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static inline void sort_channels(struct iw_freq *freq, int num)
+{
+       int i, j;
+       struct iw_freq temp;
+
+       for (i = 0; i < num; i++)
+               for (j = i + 1; j < num; j++)
+                       if (freq[i].i > freq[j].i) {
+                               temp.i = freq[i].i;
+                               temp.m = freq[i].m;
+
+                               freq[i].i = freq[j].i;
+                               freq[i].m = freq[j].m;
+
+                               freq[j].i = temp.i;
+                               freq[j].m = temp.m;
+                       }
+}
+
+/* data rate listing
+       MULTI_BANDS:
+               abg             a       b       b/g
+   Infra       G(12)           A(8)    B(4)    G(12)
+   Adhoc       A+B(12)         A(8)    B(4)    B(4)
+
+       non-MULTI_BANDS:
+                                       b       b/g
+   Infra                               B(4)    G(12)
+   Adhoc                               B(4)    B(4)
+ */
+/**
+ *  @brief Get Range Info
+ *
+ *  @param dev                  A pointer to net_device structure
+ *  @param info                        A pointer to iw_request_info structure
+ *  @param vwrq                A pointer to iw_param structure
+ *  @param extra               A pointer to extra data buf
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_point *dwrq, char *extra)
+{
+       int i, j;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct iw_range *range = (struct iw_range *)extra;
+       struct chan_freq_power *cfp;
+       u8 rates[WLAN_SUPPORTED_RATES];
+
+       u8 flag = 0;
+
+       ENTER();
+
+       dwrq->length = sizeof(struct iw_range);
+       memset(range, 0, sizeof(struct iw_range));
+
+       range->min_nwid = 0;
+       range->max_nwid = 0;
+
+       memset(rates, 0, sizeof(rates));
+       range->num_bitrates = get_active_data_rates(adapter, rates);
+
+       for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
+            i++) {
+               range->bitrate[i] = (rates[i] & 0x7f) * 500000;
+       }
+       range->num_bitrates = i;
+       lbs_pr_debug(1, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+              range->num_bitrates);
+
+       range->num_frequency = 0;
+       if (priv->adapter->enable11d &&
+           adapter->connect_status == libertas_connected) {
+               u8 chan_no;
+               u8 band;
+
+               struct parsed_region_chan_11d *parsed_region_chan =
+                   &adapter->parsed_region_chan;
+
+               if (parsed_region_chan == NULL) {
+                       lbs_pr_debug(1, "11D:parsed_region_chan is NULL\n");
+                       LEAVE();
+                       return 0;
+               }
+               band = parsed_region_chan->band;
+               lbs_pr_debug(1, "band=%d NoOfChan=%d\n", band,
+                      parsed_region_chan->nr_chan);
+
+               for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+                    && (i < parsed_region_chan->nr_chan); i++) {
+                       chan_no = parsed_region_chan->chanpwr[i].chan;
+                       lbs_pr_debug(1, "chan_no=%d\n", chan_no);
+                       range->freq[range->num_frequency].i = (long)chan_no;
+                       range->freq[range->num_frequency].m =
+                           (long)libertas_chan_2_freq(chan_no, band) * 100000;
+                       range->freq[range->num_frequency].e = 1;
+                       range->num_frequency++;
+               }
+               flag = 1;
+       }
+       if (!flag) {
+               for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+                    && (j < sizeof(adapter->region_channel)
+                        / sizeof(adapter->region_channel[0])); j++) {
+                       cfp = adapter->region_channel[j].CFP;
+                       for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+                            && adapter->region_channel[j].valid
+                            && cfp
+                            && (i < adapter->region_channel[j].nrcfp); i++) {
+                               range->freq[range->num_frequency].i =
+                                   (long)cfp->channel;
+                               range->freq[range->num_frequency].m =
+                                   (long)cfp->freq * 100000;
+                               range->freq[range->num_frequency].e = 1;
+                               cfp++;
+                               range->num_frequency++;
+                       }
+               }
+       }
+
+       lbs_pr_debug(1, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+              IW_MAX_FREQUENCIES, range->num_frequency);
+
+       range->num_channels = range->num_frequency;
+
+       sort_channels(&range->freq[0], range->num_frequency);
+
+       /*
+        * Set an indication of the max TCP throughput in bit/s that we can
+        * expect using this interface
+        */
+       if (i > 2)
+               range->throughput = 5000 * 1000;
+       else
+               range->throughput = 1500 * 1000;
+
+       range->min_rts = MRVDRV_RTS_MIN_VALUE;
+       range->max_rts = MRVDRV_RTS_MAX_VALUE;
+       range->min_frag = MRVDRV_FRAG_MIN_VALUE;
+       range->max_frag = MRVDRV_FRAG_MAX_VALUE;
+
+       range->encoding_size[0] = 5;
+       range->encoding_size[1] = 13;
+       range->num_encoding_sizes = 2;
+       range->max_encoding_tokens = 4;
+
+       range->min_pmp = 1000000;
+       range->max_pmp = 120000000;
+       range->min_pmt = 1000;
+       range->max_pmt = 1000000;
+       range->pmp_flags = IW_POWER_PERIOD;
+       range->pmt_flags = IW_POWER_TIMEOUT;
+       range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+       /*
+        * Minimum version we recommend
+        */
+       range->we_version_source = 15;
+
+       /*
+        * Version we are compiled with
+        */
+       range->we_version_compiled = WIRELESS_EXT;
+
+       range->retry_capa = IW_RETRY_LIMIT;
+       range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+       range->min_retry = TX_RETRY_MIN;
+       range->max_retry = TX_RETRY_MAX;
+
+       /*
+        * Set the qual, level and noise range values
+        */
+       range->max_qual.qual = 100;
+       range->max_qual.level = 0;
+       range->max_qual.noise = 0;
+       range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+
+       range->avg_qual.qual = 70;
+       /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
+       range->avg_qual.level = 0;
+       range->avg_qual.noise = 0;
+       range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+
+       range->sensitivity = 0;
+
+       /*
+        * Setup the supported power level ranges
+        */
+       memset(range->txpower, 0, sizeof(range->txpower));
+       range->txpower[0] = 5;
+       range->txpower[1] = 7;
+       range->txpower[2] = 9;
+       range->txpower[3] = 11;
+       range->txpower[4] = 13;
+       range->txpower[5] = 15;
+       range->txpower[6] = 17;
+       range->txpower[7] = 19;
+
+       range->num_txpower = 8;
+       range->txpower_capa = IW_TXPOW_DBM;
+       range->txpower_capa |= IW_TXPOW_RANGE;
+
+       range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+                               IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+                               IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+       range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
+       if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
+               range->enc_capa =   IW_ENC_CAPA_WPA
+                                 | IW_ENC_CAPA_WPA2
+                                 | IW_ENC_CAPA_CIPHER_TKIP
+                                 | IW_ENC_CAPA_CIPHER_CCMP;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       /* PS is currently supported only in Infrastructure mode
+        * Remove this check if it is to be supported in IBSS mode also
+        */
+
+       if (vwrq->disabled) {
+               adapter->psmode = wlan802_11powermodecam;
+               if (adapter->psstate != PS_STATE_FULL_POWER) {
+                       libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+               }
+
+               return 0;
+       }
+
+       if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+               lbs_pr_debug(1,
+                      "Setting power timeout command is not supported\n");
+               return -EINVAL;
+       } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+               lbs_pr_debug(1, "Setting power period command is not supported\n");
+               return -EINVAL;
+       }
+
+       if (adapter->psmode != wlan802_11powermodecam) {
+               return 0;
+       }
+
+       adapter->psmode = wlan802_11powermodemax_psp;
+
+       if (adapter->connect_status == libertas_connected) {
+               libertas_ps_sleep(priv, cmd_option_waitforrsp);
+       }
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       int mode;
+
+       ENTER();
+
+       mode = adapter->psmode;
+
+       if ((vwrq->disabled = (mode == wlan802_11powermodecam))
+           || adapter->connect_status == libertas_disconnected) {
+               LEAVE();
+               return 0;
+       }
+
+       vwrq->value = 0;
+
+       LEAVE();
+       return 0;
+}
+
+/*
+ * iwpriv settable callbacks
+ */
+
+static const iw_handler wlan_private_handler[] = {
+       NULL,                   /* SIOCIWFIRSTPRIV */
+};
+
+static const struct iw_priv_args wlan_private_args[] = {
+       /*
+        * { cmd, set_args, get_args, name }
+        */
+       {
+        WLANSCAN_TYPE,
+        IW_PRIV_TYPE_CHAR | 8,
+        IW_PRIV_TYPE_CHAR | 8,
+        "scantype"},
+
+       {
+        WLAN_SETINT_GETINT,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        ""},
+       {
+        WLANNF,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "getNF"},
+       {
+        WLANRSSI,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "getRSSI"},
+       {
+        WLANENABLE11D,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "enable11d"},
+       {
+        WLANADHOCGRATE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "adhocgrate"},
+
+       {
+        WLAN_SUBCMD_SET_PRESCAN,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "prescan"},
+       {
+        WLAN_SETONEINT_GETONEINT,
+        IW_PRIV_TYPE_INT | 1,
+        IW_PRIV_TYPE_INT | 1,
+        ""},
+       {
+        WLAN_BEACON_INTERVAL,
+        IW_PRIV_TYPE_INT | 1,
+        IW_PRIV_TYPE_INT | 1,
+        "bcninterval"},
+       {
+        WLAN_LISTENINTRVL,
+        IW_PRIV_TYPE_INT | 1,
+        IW_PRIV_TYPE_INT | 1,
+        "lolisteninter"},
+       {
+        WLAN_TXCONTROL,
+        IW_PRIV_TYPE_INT | 1,
+        IW_PRIV_TYPE_INT | 1,
+        "txcontrol"},
+       {
+        WLAN_NULLPKTINTERVAL,
+        IW_PRIV_TYPE_INT | 1,
+        IW_PRIV_TYPE_INT | 1,
+        "psnullinterval"},
+       /* Using iwpriv sub-command feature */
+       {
+        WLAN_SETONEINT_GETNONE,        /* IOCTL: 24 */
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        ""},
+
+       {
+        WLAN_SUBCMD_SETRXANTENNA,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "setrxant"},
+       {
+        WLAN_SUBCMD_SETTXANTENNA,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "settxant"},
+       {
+        WLANSETAUTHALG,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "authalgs",
+        },
+       {
+        WLANSET8021XAUTHALG,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "8021xauthalgs",
+        },
+       {
+        WLANSETENCRYPTIONMODE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "encryptionmode",
+        },
+       {
+        WLANSETREGION,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "setregioncode"},
+       {
+        WLAN_SET_LISTEN_INTERVAL,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "setlisteninter"},
+       {
+        WLAN_SET_MULTIPLE_DTIM,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "setmultipledtim"},
+       {
+        WLAN_SET_ATIM_WINDOW,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "atimwindow"},
+       {
+        WLANSETBCNAVG,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "setbcnavg"},
+       {
+        WLANSETDATAAVG,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "setdataavg"},
+       {
+        WLAN_SET_LINKMODE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "linkmode"},
+       {
+        WLAN_SET_RADIOMODE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "radiomode"},
+       {
+        WLAN_SET_DEBUGMODE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "debugmode"},
+       {
+        WLAN_SUBCMD_MESH_SET_TTL,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        IW_PRIV_TYPE_NONE,
+        "mesh_set_ttl"},
+       {
+        WLAN_SETNONE_GETONEINT,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        ""},
+       {
+        WLANGETREGION,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "getregioncode"},
+       {
+        WLAN_GET_LISTEN_INTERVAL,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "getlisteninter"},
+       {
+        WLAN_GET_MULTIPLE_DTIM,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "getmultipledtim"},
+       {
+        WLAN_GET_TX_RATE,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "gettxrate"},
+       {
+        WLANGETBCNAVG,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "getbcnavg"},
+       {
+        WLAN_GET_LINKMODE,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "get_linkmode"},
+       {
+        WLAN_GET_RADIOMODE,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "get_radiomode"},
+       {
+        WLAN_GET_DEBUGMODE,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "get_debugmode"},
+       {
+        WLAN_SUBCMD_FWT_CLEANUP,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "fwt_cleanup"},
+       {
+        WLAN_SUBCMD_FWT_TIME,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "fwt_time"},
+       {
+        WLAN_SUBCMD_MESH_GET_TTL,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "mesh_get_ttl"},
+       {
+        WLAN_SETNONE_GETTWELVE_CHAR,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_CHAR | 12,
+        ""},
+       {
+        WLAN_SUBCMD_GETRXANTENNA,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_CHAR | 12,
+        "getrxant"},
+       {
+        WLAN_SUBCMD_GETTXANTENNA,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_CHAR | 12,
+        "gettxant"},
+       {
+        WLAN_GET_TSF,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_CHAR | 12,
+        "gettsf"},
+       {
+        WLAN_SETNONE_GETNONE,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_NONE,
+        ""},
+       {
+        WLANDEAUTH,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_NONE,
+        "deauth"},
+       {
+        WLANADHOCSTOP,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_NONE,
+        "adhocstop"},
+       {
+        WLANRADIOON,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_NONE,
+        "radioon"},
+       {
+        WLANRADIOOFF,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_NONE,
+        "radiooff"},
+       {
+        WLANWLANIDLEON,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_NONE,
+        "wlanidle-on"},
+       {
+        WLANWLANIDLEOFF,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_NONE,
+        "wlanidle-off"},
+       {
+        WLAN_SUBCMD_FWT_RESET,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_NONE,
+        "fwt_reset"},
+       {
+        WLAN_SUBCMD_BT_RESET,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_NONE,
+        "bt_reset"},
+       {
+        WLAN_SET128CHAR_GET128CHAR,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        ""},
+       /* BT Management */
+       {
+        WLAN_SUBCMD_BT_ADD,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "bt_add"},
+       {
+        WLAN_SUBCMD_BT_DEL,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "bt_del"},
+       {
+        WLAN_SUBCMD_BT_LIST,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "bt_list"},
+       /* FWT Management */
+       {
+        WLAN_SUBCMD_FWT_ADD,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "fwt_add"},
+       {
+        WLAN_SUBCMD_FWT_DEL,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "fwt_del"},
+       {
+        WLAN_SUBCMD_FWT_LOOKUP,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "fwt_lookup"},
+       {
+        WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "fwt_list_neigh"},
+       {
+        WLAN_SUBCMD_FWT_LIST,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "fwt_list"},
+       {
+        WLAN_SUBCMD_FWT_LIST_ROUTE,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "fwt_list_route"},
+       {
+        WLANSCAN_MODE,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "scanmode"},
+       {
+        WLAN_GET_ADHOC_STATUS,
+        IW_PRIV_TYPE_CHAR | 128,
+        IW_PRIV_TYPE_CHAR | 128,
+        "getadhocstatus"},
+       {
+        WLAN_SETNONE_GETWORDCHAR,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_CHAR | 128,
+        ""},
+       {
+        WLANSETWPAIE,
+        IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24,
+        IW_PRIV_TYPE_NONE,
+        "setwpaie"},
+       {
+        WLANGETLOG,
+        IW_PRIV_TYPE_NONE,
+        IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
+        "getlog"},
+       {
+        WLAN_SET_GET_SIXTEEN_INT,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        ""},
+       {
+        WLAN_TPCCFG,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "tpccfg"},
+       {
+        WLAN_POWERCFG,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "powercfg"},
+       {
+        WLAN_AUTO_FREQ_SET,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "setafc"},
+       {
+        WLAN_AUTO_FREQ_GET,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "getafc"},
+       {
+        WLAN_SCANPROBES,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "scanprobes"},
+       {
+        WLAN_LED_GPIO_CTRL,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "ledgpio"},
+       {
+        WLAN_ADAPT_RATESET,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "rateadapt"},
+       {
+        WLAN_INACTIVITY_TIMEOUT,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "inactivityto"},
+       {
+        WLANSNR,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "getSNR"},
+       {
+        WLAN_GET_RATE,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "getrate"},
+       {
+        WLAN_GET_RXINFO,
+        IW_PRIV_TYPE_INT | 16,
+        IW_PRIV_TYPE_INT | 16,
+        "getrxinfo"},
+};
+
+static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
+{
+       enum {
+               POOR = 30,
+               FAIR = 60,
+               GOOD = 80,
+               VERY_GOOD = 90,
+               EXCELLENT = 95,
+               PERFECT = 100
+       };
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       u32 rssi_qual;
+       u32 tx_qual;
+       u32 quality = 0;
+       int stats_valid = 0;
+       u8 rssi;
+       u32 tx_retries;
+
+       ENTER();
+
+       priv->wstats.status = adapter->inframode;
+
+       /* If we're not associated, all quality values are meaningless */
+       if (adapter->connect_status != libertas_connected)
+               goto out;
+
+       /* Quality by RSSI */
+       priv->wstats.qual.level =
+           CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+            adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+       if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+               priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+       } else {
+               priv->wstats.qual.noise =
+                   CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+       }
+
+       lbs_pr_debug(1, "Signal Level = %#x\n", priv->wstats.qual.level);
+       lbs_pr_debug(1, "Noise = %#x\n", priv->wstats.qual.noise);
+
+       rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
+       if (rssi < 15)
+               rssi_qual = rssi * POOR / 10;
+       else if (rssi < 20)
+               rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
+       else if (rssi < 30)
+               rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
+       else if (rssi < 40)
+               rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
+                   10 + GOOD;
+       else
+               rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
+                   10 + VERY_GOOD;
+       quality = rssi_qual;
+
+       /* Quality by TX errors */
+       priv->wstats.discard.retries = priv->stats.tx_errors;
+
+       tx_retries = adapter->logmsg.retry;
+
+       if (tx_retries > 75)
+               tx_qual = (90 - tx_retries) * POOR / 15;
+       else if (tx_retries > 70)
+               tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
+       else if (tx_retries > 65)
+               tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
+       else if (tx_retries > 50)
+               tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
+                   15 + GOOD;
+       else
+               tx_qual = (50 - tx_retries) *
+                   (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
+       quality = min(quality, tx_qual);
+
+       priv->wstats.discard.code = adapter->logmsg.wepundecryptable;
+       priv->wstats.discard.fragment = adapter->logmsg.fcserror;
+       priv->wstats.discard.retries = tx_retries;
+       priv->wstats.discard.misc = adapter->logmsg.ackfailure;
+
+       /* Calculate quality */
+       priv->wstats.qual.qual = max(quality, (u32)100);
+       priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+       stats_valid = 1;
+
+       /* update stats asynchronously for future calls */
+       libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
+                                       0, 0, NULL);
+       libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
+                                       0, 0, NULL);
+out:
+       if (!stats_valid) {
+               priv->wstats.miss.beacon = 0;
+               priv->wstats.discard.retries = 0;
+               priv->wstats.qual.qual = 0;
+               priv->wstats.qual.level = 0;
+               priv->wstats.qual.noise = 0;
+               priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
+               priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
+                   IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+       }
+
+       LEAVE ();
+       return &priv->wstats;
+
+
+}
+
+static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
+                 struct iw_freq *fwrq, char *extra)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       int rc = -EINPROGRESS;  /* Call commit handler */
+       struct chan_freq_power *cfp;
+
+       ENTER();
+
+       /*
+        * If setting by frequency, convert to a channel
+        */
+       if (fwrq->e == 1) {
+
+               long f = fwrq->m / 100000;
+               int c = 0;
+
+               cfp = find_cfp_by_band_and_freq(adapter, 0, f);
+               if (!cfp) {
+                       lbs_pr_debug(1, "Invalid freq=%ld\n", f);
+                       return -EINVAL;
+               }
+
+               c = (int)cfp->channel;
+
+               if (c < 0)
+                       return -EINVAL;
+
+               fwrq->e = 0;
+               fwrq->m = c;
+       }
+
+       /*
+        * Setting by channel number
+        */
+       if (fwrq->m > 1000 || fwrq->e > 0) {
+               rc = -EOPNOTSUPP;
+       } else {
+               int channel = fwrq->m;
+
+               cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
+               if (!cfp) {
+                       rc = -EINVAL;
+               } else {
+                       if (adapter->inframode == wlan802_11ibss) {
+                               rc = changeadhocchannel(priv, channel);
+                               /*  If station is WEP enabled, send the
+                                *  command to set WEP in firmware
+                                */
+                               if (adapter->secinfo.WEPstatus ==
+                                   wlan802_11WEPenabled) {
+                                       lbs_pr_debug(1, "set_freq: WEP enabled\n");
+                                       ret = libertas_prepare_and_send_command(priv,
+                                                                   cmd_802_11_set_wep,
+                                                                   cmd_act_add,
+                                                                   cmd_option_waitforrsp,
+                                                                   0,
+                                                                   NULL);
+
+                                       if (ret) {
+                                               LEAVE();
+                                               return ret;
+                                       }
+
+                                       adapter->currentpacketfilter |=
+                                           cmd_act_mac_wep_enable;
+
+                                       libertas_set_mac_packet_filter(priv);
+                               }
+                       } else {
+                               rc = -EOPNOTSUPP;
+                       }
+               }
+       }
+
+       LEAVE();
+       return rc;
+}
+
+/**
+ *  @brief use index to get the data rate
+ *
+ *  @param index                The index of data rate
+ *  @return                    data rate or 0
+ */
+u32 libertas_index_to_data_rate(u8 index)
+{
+       if (index >= sizeof(libertas_wlan_data_rates))
+               index = 0;
+
+       return libertas_wlan_data_rates[index];
+}
+
+/**
+ *  @brief use rate to get the index
+ *
+ *  @param rate                 data rate
+ *  @return                    index or 0
+ */
+u8 libertas_data_rate_to_index(u32 rate)
+{
+       u8 *ptr;
+
+       if (rate)
+               if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
+                                 sizeof(libertas_wlan_data_rates))))
+                       return (ptr - libertas_wlan_data_rates);
+
+       return 0;
+}
+
+static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
+                 struct iw_param *vwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       u32 data_rate;
+       u16 action;
+       int ret = 0;
+       u8 rates[WLAN_SUPPORTED_RATES];
+       u8 *rate;
+
+       ENTER();
+
+       lbs_pr_debug(1, "Vwrq->value = %d\n", vwrq->value);
+
+       if (vwrq->value == -1) {
+               action = cmd_act_set_tx_auto;   // Auto
+               adapter->is_datarate_auto = 1;
+               adapter->datarate = 0;
+       } else {
+               if (vwrq->value % 100000) {
+                       return -EINVAL;
+               }
+
+               data_rate = vwrq->value / 500000;
+
+               memset(rates, 0, sizeof(rates));
+               get_active_data_rates(adapter, rates);
+               rate = rates;
+               while (*rate) {
+                       lbs_pr_debug(1, "Rate=0x%X  Wanted=0x%X\n", *rate,
+                              data_rate);
+                       if ((*rate & 0x7f) == (data_rate & 0x7f))
+                               break;
+                       rate++;
+               }
+               if (!*rate) {
+                       lbs_pr_alert( "The fixed data rate 0x%X is out "
+                              "of range.\n", data_rate);
+                       return -EINVAL;
+               }
+
+               adapter->datarate = data_rate;
+               action = cmd_act_set_tx_fix_rate;
+               adapter->is_datarate_auto = 0;
+       }
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+                                   action, cmd_option_waitforrsp, 0, NULL);
+
+       LEAVE();
+       return ret;
+}
+
+static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
+                 struct iw_param *vwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       if (adapter->is_datarate_auto) {
+               vwrq->fixed = 0;
+       } else {
+               vwrq->fixed = 1;
+       }
+
+       vwrq->value = adapter->datarate * 500000;
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_set_mode(struct net_device *dev,
+                 struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct assoc_request * assoc_req;
+       enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
+
+       ENTER();
+
+       switch (*uwrq) {
+       case IW_MODE_ADHOC:
+               lbs_pr_debug(1, "Wanted mode is ad-hoc: current datarate=%#x\n",
+                      adapter->datarate);
+               new_mode = wlan802_11ibss;
+               adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
+               break;
+
+       case IW_MODE_INFRA:
+               lbs_pr_debug(1, "Wanted mode is Infrastructure\n");
+               new_mode = wlan802_11infrastructure;
+               break;
+
+       case IW_MODE_AUTO:
+               lbs_pr_debug(1, "Wanted mode is Auto\n");
+               new_mode = wlan802_11autounknown;
+               break;
+
+       default:
+               lbs_pr_debug(1, "Wanted mode is Unknown: 0x%x\n", *uwrq);
+               return -EINVAL;
+       }
+
+       mutex_lock(&adapter->lock);
+       assoc_req = wlan_get_association_request(adapter);
+       if (!assoc_req) {
+               ret = -ENOMEM;
+       } else {
+               assoc_req->mode = new_mode;
+       }
+
+       if (ret == 0) {
+               set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+               wlan_postpone_association_work(priv);
+       } else {
+               wlan_cancel_association_work(priv);
+       }
+       mutex_unlock(&adapter->lock);
+
+       LEAVE();
+       return ret;
+}
+
+
+/**
+ *  @brief Get Encryption key
+ *
+ *  @param dev                  A pointer to net_device structure
+ *  @param info                        A pointer to iw_request_info structure
+ *  @param vwrq                A pointer to iw_param structure
+ *  @param extra               A pointer to extra data buf
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_get_encode(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_point *dwrq, u8 * extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+       ENTER();
+
+       lbs_pr_debug(1, "flags=0x%x index=%d length=%d wep_tx_keyidx=%d\n",
+              dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
+
+       dwrq->flags = 0;
+
+       /* Authentication method */
+       switch (adapter->secinfo.authmode) {
+       case wlan802_11authmodeopen:
+               dwrq->flags = IW_ENCODE_OPEN;
+               break;
+
+       case wlan802_11authmodeshared:
+       case wlan802_11authmodenetworkEAP:
+               dwrq->flags = IW_ENCODE_RESTRICTED;
+               break;
+       default:
+               dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+               break;
+       }
+
+       if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
+           || adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+               dwrq->flags &= ~IW_ENCODE_DISABLED;
+       } else {
+               dwrq->flags |= IW_ENCODE_DISABLED;
+       }
+
+       memset(extra, 0, 16);
+
+       mutex_lock(&adapter->lock);
+
+       /* Default to returning current transmit key */
+       if (index < 0)
+               index = adapter->wep_tx_keyidx;
+
+       if ((adapter->wep_keys[index].len) &&
+           (adapter->secinfo.WEPstatus == wlan802_11WEPenabled)) {
+               memcpy(extra, adapter->wep_keys[index].key,
+                      adapter->wep_keys[index].len);
+               dwrq->length = adapter->wep_keys[index].len;
+
+               dwrq->flags |= (index + 1);
+               /* Return WEP enabled */
+               dwrq->flags &= ~IW_ENCODE_DISABLED;
+       } else if ((adapter->secinfo.WPAenabled)
+                  || (adapter->secinfo.WPA2enabled)) {
+               /* return WPA enabled */
+               dwrq->flags &= ~IW_ENCODE_DISABLED;
+       } else {
+               dwrq->flags |= IW_ENCODE_DISABLED;
+       }
+
+       mutex_unlock(&adapter->lock);
+
+       dwrq->flags |= IW_ENCODE_NOKEY;
+
+       lbs_pr_debug(1, "key:%02x:%02x:%02x:%02x:%02x:%02x keylen=%d\n",
+              extra[0], extra[1], extra[2],
+              extra[3], extra[4], extra[5], dwrq->length);
+
+       lbs_pr_debug(1, "Return flags=0x%x\n", dwrq->flags);
+
+       LEAVE();
+       return 0;
+}
+
+/**
+ *  @brief Set Encryption key (internal)
+ *
+ *  @param priv                        A pointer to private card structure
+ *  @param key_material                A pointer to key material
+ *  @param key_length          length of key material
+ *  @param index               key index to set
+ *  @param set_tx_key          Force set TX key (1 = yes, 0 = no)
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_set_wep_key(struct assoc_request *assoc_req,
+                           const char *key_material,
+                           u16 key_length,
+                           u16 index,
+                           int set_tx_key)
+{
+       struct WLAN_802_11_KEY *pkey;
+
+       ENTER();
+
+       /* Paranoid validation of key index */
+       if (index > 3) {
+               LEAVE();
+               return -EINVAL;
+       }
+
+       /* validate max key length */
+       if (key_length > KEY_LEN_WEP_104) {
+               LEAVE();
+               return -EINVAL;
+       }
+
+       pkey = &assoc_req->wep_keys[index];
+
+       if (key_length > 0) {
+               memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+               pkey->type = KEY_TYPE_ID_WEP;
+
+               /* Standardize the key length */
+               pkey->len = (key_length > KEY_LEN_WEP_40) ?
+                               KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
+               memcpy(pkey->key, key_material, key_length);
+       }
+
+       if (set_tx_key) {
+               /* Ensure the chosen key is valid */
+               if (!pkey->len) {
+                       lbs_pr_debug(1, "key not set, so cannot enable it\n");
+                       LEAVE();
+                       return -EINVAL;
+               }
+               assoc_req->wep_tx_keyidx = index;
+       }
+
+       assoc_req->secinfo.WEPstatus = wlan802_11WEPenabled;
+
+       LEAVE();
+       return 0;
+}
+
+static int validate_key_index(u16 def_index, u16 raw_index,
+                             u16 *out_index, u16 *is_default)
+{
+       if (!out_index || !is_default)
+               return -EINVAL;
+
+       /* Verify index if present, otherwise use default TX key index */
+       if (raw_index > 0) {
+               if (raw_index > 4)
+                       return -EINVAL;
+               *out_index = raw_index - 1;
+       } else {
+               *out_index = def_index;
+               *is_default = 1;
+       }
+       return 0;
+}
+
+static void disable_wep(struct assoc_request *assoc_req)
+{
+       int i;
+
+       /* Set Open System auth mode */
+       assoc_req->secinfo.authmode = wlan802_11authmodeopen;
+
+       /* Clear WEP keys and mark WEP as disabled */
+       assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+       for (i = 0; i < 4; i++)
+               assoc_req->wep_keys[i].len = 0;
+
+       set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+       set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+}
+
+/**
+ *  @brief Set Encryption key
+ *
+ *  @param dev                  A pointer to net_device structure
+ *  @param info                        A pointer to iw_request_info structure
+ *  @param vwrq                A pointer to iw_param structure
+ *  @param extra               A pointer to extra data buf
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_set_encode(struct net_device *dev,
+                   struct iw_request_info *info,
+                   struct iw_point *dwrq, char *extra)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct assoc_request * assoc_req;
+       u16 is_default = 0, index = 0, set_tx_key = 0;
+
+       ENTER();
+
+       mutex_lock(&adapter->lock);
+       assoc_req = wlan_get_association_request(adapter);
+       if (!assoc_req) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (dwrq->flags & IW_ENCODE_DISABLED) {
+               disable_wep (assoc_req);
+               goto out;
+       }
+
+       ret = validate_key_index(assoc_req->wep_tx_keyidx,
+                                (dwrq->flags & IW_ENCODE_INDEX),
+                                &index, &is_default);
+       if (ret) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* If WEP isn't enabled, or if there is no key data but a valid
+        * index, set the TX key.
+        */
+       if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
+           || (dwrq->length == 0 && !is_default))
+               set_tx_key = 1;
+
+       ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
+       if (ret)
+               goto out;
+
+       if (dwrq->length)
+               set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+       if (set_tx_key)
+               set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+
+       if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+               assoc_req->secinfo.authmode = wlan802_11authmodeshared;
+       } else if (dwrq->flags & IW_ENCODE_OPEN) {
+               assoc_req->secinfo.authmode = wlan802_11authmodeopen;
+       }
+
+out:
+       if (ret == 0) {
+               set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+               wlan_postpone_association_work(priv);
+       } else {
+               wlan_cancel_association_work(priv);
+       }
+       mutex_unlock(&adapter->lock);
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Get Extended Encryption key (WPA/802.1x and WEP)
+ *
+ *  @param dev                  A pointer to net_device structure
+ *  @param info                        A pointer to iw_request_info structure
+ *  @param vwrq                A pointer to iw_param structure
+ *  @param extra               A pointer to extra data buf
+ *  @return                    0 on success, otherwise failure
+ */
+static int wlan_get_encodeext(struct net_device *dev,
+                             struct iw_request_info *info,
+                             struct iw_point *dwrq,
+                             char *extra)
+{
+       int ret = -EINVAL;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       int index, max_key_len;
+
+       ENTER();
+
+       max_key_len = dwrq->length - sizeof(*ext);
+       if (max_key_len < 0)
+               goto out;
+
+       index = dwrq->flags & IW_ENCODE_INDEX;
+       if (index) {
+               if (index < 1 || index > 4)
+                       goto out;
+               index--;
+       } else {
+               index = adapter->wep_tx_keyidx;
+       }
+
+       if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
+           ext->alg != IW_ENCODE_ALG_WEP) {
+               if (index != 0 || adapter->inframode != wlan802_11infrastructure)
+                       goto out;
+       }
+
+       dwrq->flags = index + 1;
+       memset(ext, 0, sizeof(*ext));
+
+       if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled)
+           && !adapter->secinfo.WPAenabled && !adapter->secinfo.WPA2enabled) {
+               ext->alg = IW_ENCODE_ALG_NONE;
+               ext->key_len = 0;
+               dwrq->flags |= IW_ENCODE_DISABLED;
+       } else {
+               u8 *key = NULL;
+
+               if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
+                   && !adapter->secinfo.WPAenabled
+                   && !adapter->secinfo.WPA2enabled) {
+                       ext->alg = IW_ENCODE_ALG_WEP;
+                       ext->key_len = adapter->wep_keys[index].len;
+                       key = &adapter->wep_keys[index].key[0];
+               } else if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) &&
+                          (adapter->secinfo.WPAenabled ||
+                           adapter->secinfo.WPA2enabled)) {
+                       /* WPA */
+                       ext->alg = IW_ENCODE_ALG_TKIP;
+                       ext->key_len = 0;
+               } else {
+                       goto out;
+               }
+
+               if (ext->key_len > max_key_len) {
+                       ret = -E2BIG;
+                       goto out;
+               }
+
+               if (ext->key_len)
+                       memcpy(ext->key, key, ext->key_len);
+               else
+                       dwrq->flags |= IW_ENCODE_NOKEY;
+               dwrq->flags |= IW_ENCODE_ENABLED;
+       }
+       ret = 0;
+
+out:
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Set Encryption key Extended (WPA/802.1x and WEP)
+ *
+ *  @param dev                  A pointer to net_device structure
+ *  @param info                        A pointer to iw_request_info structure
+ *  @param vwrq                A pointer to iw_param structure
+ *  @param extra               A pointer to extra data buf
+ *  @return                    0 --success, otherwise fail
+ */
+static int wlan_set_encodeext(struct net_device *dev,
+                             struct iw_request_info *info,
+                             struct iw_point *dwrq,
+                             char *extra)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       int alg = ext->alg;
+       struct assoc_request * assoc_req;
+
+       ENTER();
+
+       mutex_lock(&adapter->lock);
+       assoc_req = wlan_get_association_request(adapter);
+       if (!assoc_req) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
+               disable_wep (assoc_req);
+       } else if (alg == IW_ENCODE_ALG_WEP) {
+               u16 is_default = 0, index, set_tx_key = 0;
+
+               ret = validate_key_index(assoc_req->wep_tx_keyidx,
+                                        (dwrq->flags & IW_ENCODE_INDEX),
+                                        &index, &is_default);
+               if (ret)
+                       goto out;
+
+               /* If WEP isn't enabled, or if there is no key data but a valid
+                * index, or if the set-TX-key flag was passed, set the TX key.
+                */
+               if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
+                   || (dwrq->length == 0 && !is_default)
+                   || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
+                       set_tx_key = 1;
+
+               /* Copy key to driver */
+               ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
+                                       set_tx_key);
+               if (ret)
+                       goto out;
+
+               if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+                       assoc_req->secinfo.authmode =
+                           wlan802_11authmodeshared;
+               } else if (dwrq->flags & IW_ENCODE_OPEN) {
+                       assoc_req->secinfo.authmode =
+                           wlan802_11authmodeopen;
+               }
+
+               /* Mark the various WEP bits as modified */
+               set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+               if (dwrq->length)
+                       set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+               if (set_tx_key)
+                       set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+
+       } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
+               struct WLAN_802_11_KEY * pkey;
+
+               /* validate key length */
+               if (((alg == IW_ENCODE_ALG_TKIP)
+                       && (ext->key_len != KEY_LEN_WPA_TKIP))
+                   || ((alg == IW_ENCODE_ALG_CCMP)
+                       && (ext->key_len != KEY_LEN_WPA_AES))) {
+                               lbs_pr_debug(1, "Invalid size %d for key of alg"
+                                      "type %d.\n",
+                                      ext->key_len,
+                                      alg);
+                               ret = -EINVAL;
+                               goto out;
+               }
+
+               if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+                       pkey = &assoc_req->wpa_mcast_key;
+               else
+                       pkey = &assoc_req->wpa_unicast_key;
+
+               memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
+               memcpy(pkey->key, ext->key, ext->key_len);
+               pkey->len = ext->key_len;
+               pkey->flags = KEY_INFO_WPA_ENABLED;
+
+               if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+                       pkey->flags |= KEY_INFO_WPA_MCAST;
+                       set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
+               } else {
+                       pkey->flags |= KEY_INFO_WPA_UNICAST;
+                       set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+               }
+
+               if (alg == IW_ENCODE_ALG_TKIP)
+                       pkey->type = KEY_TYPE_ID_TKIP;
+               else if (alg == IW_ENCODE_ALG_CCMP)
+                       pkey->type = KEY_TYPE_ID_AES;
+
+               /* If WPA isn't enabled yet, do that now */
+               if (   assoc_req->secinfo.WPAenabled == 0
+                   && assoc_req->secinfo.WPA2enabled == 0) {
+                       assoc_req->secinfo.WPAenabled = 1;
+                       assoc_req->secinfo.WPA2enabled = 1;
+                       set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+               }
+
+               disable_wep (assoc_req);
+       }
+
+out:
+       if (ret == 0) {
+               wlan_postpone_association_work(priv);
+       } else {
+               wlan_cancel_association_work(priv);
+       }
+       mutex_unlock(&adapter->lock);
+
+       LEAVE();
+       return ret;
+}
+
+
+static int wlan_set_genie(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_point *dwrq,
+                         char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       struct assoc_request * assoc_req;
+
+       ENTER();
+
+       mutex_lock(&adapter->lock);
+       assoc_req = wlan_get_association_request(adapter);
+       if (!assoc_req) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (dwrq->length > MAX_WPA_IE_LEN ||
+           (dwrq->length && extra == NULL)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (dwrq->length) {
+               memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
+               assoc_req->wpa_ie_len = dwrq->length;
+       } else {
+               memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
+               assoc_req->wpa_ie_len = 0;
+       }
+
+out:
+       if (ret == 0) {
+               set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
+               wlan_postpone_association_work(priv);
+       } else {
+               wlan_cancel_association_work(priv);
+       }
+       mutex_unlock(&adapter->lock);
+
+       LEAVE();
+       return ret;
+}
+
+static int wlan_get_genie(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_point *dwrq,
+                         char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       if (adapter->wpa_ie_len == 0) {
+               dwrq->length = 0;
+               LEAVE();
+               return 0;
+       }
+
+       if (dwrq->length < adapter->wpa_ie_len) {
+               LEAVE();
+               return -E2BIG;
+       }
+
+       dwrq->length = adapter->wpa_ie_len;
+       memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
+
+       LEAVE();
+       return 0;
+}
+
+
+static int wlan_set_auth(struct net_device *dev,
+                        struct iw_request_info *info,
+                        struct iw_param *dwrq,
+                        char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct assoc_request * assoc_req;
+       int ret = 0;
+       int updated = 0;
+
+       ENTER();
+
+       mutex_lock(&adapter->lock);
+       assoc_req = wlan_get_association_request(adapter);
+       if (!assoc_req) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       switch (dwrq->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_TKIP_COUNTERMEASURES:
+       case IW_AUTH_CIPHER_PAIRWISE:
+       case IW_AUTH_CIPHER_GROUP:
+       case IW_AUTH_KEY_MGMT:
+               /*
+                * libertas does not use these parameters
+                */
+               break;
+
+       case IW_AUTH_WPA_VERSION:
+               if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
+                       assoc_req->secinfo.WPAenabled = 0;
+                       assoc_req->secinfo.WPA2enabled = 0;
+               }
+               if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
+                       assoc_req->secinfo.WPAenabled = 1;
+                       assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+                       assoc_req->secinfo.authmode =
+                           wlan802_11authmodeopen;
+               }
+               if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
+                       assoc_req->secinfo.WPA2enabled = 1;
+                       assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+                       assoc_req->secinfo.authmode =
+                           wlan802_11authmodeopen;
+               }
+               updated = 1;
+               break;
+
+       case IW_AUTH_DROP_UNENCRYPTED:
+               if (dwrq->value) {
+                       adapter->currentpacketfilter |=
+                           cmd_act_mac_strict_protection_enable;
+               } else {
+                       adapter->currentpacketfilter &=
+                           ~cmd_act_mac_strict_protection_enable;
+               }
+               updated = 1;
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG:
+               if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
+                       assoc_req->secinfo.authmode =
+                           wlan802_11authmodeshared;
+               } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+                       assoc_req->secinfo.authmode =
+                           wlan802_11authmodeopen;
+               } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
+                       assoc_req->secinfo.authmode =
+                           wlan802_11authmodenetworkEAP;
+               } else {
+                       ret = -EINVAL;
+               }
+               updated = 1;
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               if (dwrq->value) {
+                       if (!assoc_req->secinfo.WPAenabled &&
+                           !assoc_req->secinfo.WPA2enabled) {
+                               assoc_req->secinfo.WPAenabled = 1;
+                               assoc_req->secinfo.WPA2enabled = 1;
+                               assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+                               assoc_req->secinfo.authmode =
+                                   wlan802_11authmodeopen;
+                       }
+               } else {
+                       assoc_req->secinfo.WPAenabled = 0;
+                       assoc_req->secinfo.WPA2enabled = 0;
+               }
+               updated = 1;
+               break;
+
+       default:
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+out:
+       if (ret == 0) {
+               if (updated)
+                       set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+               wlan_postpone_association_work(priv);
+       } else if (ret != -EOPNOTSUPP) {
+               wlan_cancel_association_work(priv);
+       }
+       mutex_unlock(&adapter->lock);
+
+       LEAVE();
+       return ret;
+}
+
+static int wlan_get_auth(struct net_device *dev,
+                        struct iw_request_info *info,
+                        struct iw_param *dwrq,
+                        char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+
+       switch (dwrq->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+               dwrq->value = 0;
+               if (adapter->secinfo.WPAenabled)
+                       dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
+               if (adapter->secinfo.WPA2enabled)
+                       dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
+               if (!dwrq->value)
+                       dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
+               break;
+
+       case IW_AUTH_DROP_UNENCRYPTED:
+               dwrq->value = 0;
+               if (adapter->currentpacketfilter &
+                   cmd_act_mac_strict_protection_enable)
+                       dwrq->value = 1;
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG:
+               switch (adapter->secinfo.authmode) {
+               case wlan802_11authmodeshared:
+                       dwrq->value = IW_AUTH_ALG_SHARED_KEY;
+                       break;
+               case wlan802_11authmodeopen:
+                       dwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+                       break;
+               case wlan802_11authmodenetworkEAP:
+                       dwrq->value = IW_AUTH_ALG_LEAP;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
+                       dwrq->value = 1;
+               break;
+
+       default:
+               LEAVE();
+               return -EOPNOTSUPP;
+       }
+
+       LEAVE();
+       return 0;
+}
+
+
+static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
+                  struct iw_param *vwrq, char *extra)
+{
+       int ret = 0;
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       u16 dbm;
+
+       ENTER();
+
+       if (vwrq->disabled) {
+               wlan_radio_ioctl(priv, RADIO_OFF);
+               return 0;
+       }
+
+       adapter->preamble = cmd_type_auto_preamble;
+
+       wlan_radio_ioctl(priv, RADIO_ON);
+
+       if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
+               dbm = (u16) mw_to_dbm(vwrq->value);
+       } else
+               dbm = (u16) vwrq->value;
+
+       /* auto tx power control */
+
+       if (vwrq->fixed == 0)
+               dbm = 0xffff;
+
+       lbs_pr_debug(1, "<1>TXPOWER SET %d dbm.\n", dbm);
+
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_rf_tx_power,
+                                   cmd_act_tx_power_opt_set_low,
+                                   cmd_option_waitforrsp, 0, (void *)&dbm);
+
+       LEAVE();
+       return ret;
+}
+
+static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
+                  struct iw_point *dwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+
+       ENTER();
+       /*
+        * Note : if dwrq->flags != 0, we should get the relevant SSID from
+        * the SSID list...
+        */
+
+       /*
+        * Get the current SSID
+        */
+       if (adapter->connect_status == libertas_connected) {
+               memcpy(extra, adapter->curbssparams.ssid.ssid,
+                      adapter->curbssparams.ssid.ssidlength);
+               extra[adapter->curbssparams.ssid.ssidlength] = '\0';
+       } else {
+               memset(extra, 0, 32);
+               extra[adapter->curbssparams.ssid.ssidlength] = '\0';
+       }
+       /*
+        * If none, we may want to get the one that was set
+        */
+
+       /* To make the driver backward compatible with WPA supplicant v0.2.4 */
+       if (dwrq->length == 32) /* check with WPA supplicant buffer size */
+               dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength,
+                                  IW_ESSID_MAX_SIZE);
+       else
+               dwrq->length = adapter->curbssparams.ssid.ssidlength + 1;
+
+       dwrq->flags = 1;        /* active */
+
+       LEAVE();
+       return 0;
+}
+
+static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
+                  struct iw_point *dwrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+       struct WLAN_802_11_SSID ssid;
+       struct assoc_request * assoc_req;
+       int ssid_len = dwrq->length;
+
+       ENTER();
+
+       /*
+        * WE-20 and earlier NULL pad the end of the SSID and increment
+        * SSID length so it can be used like a string.  WE-21 and later don't,
+        * but some userspace tools aren't able to cope with the change.
+        */
+       if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
+               ssid_len--;
+
+       /* Check the size of the string */
+       if (ssid_len > IW_ESSID_MAX_SIZE) {
+               ret = -E2BIG;
+               goto out;
+       }
+
+       memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
+
+       if (!dwrq->flags || !ssid_len) {
+               /* "any" SSID requested; leave SSID blank */
+       } else {
+               /* Specific SSID requested */
+               memcpy(&ssid.ssid, extra, ssid_len);
+               ssid.ssidlength = ssid_len;
+       }
+
+       lbs_pr_debug(1, "Requested new SSID = %s\n",
+              (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
+
+out:
+       mutex_lock(&adapter->lock);
+       if (ret == 0) {
+               /* Get or create the current association request */
+               assoc_req = wlan_get_association_request(adapter);
+               if (!assoc_req) {
+                       ret = -ENOMEM;
+               } else {
+                       /* Copy the SSID to the association request */
+                       memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
+                       set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
+                       wlan_postpone_association_work(priv);
+               }
+       }
+
+       /* Cancel the association request if there was an error */
+       if (ret != 0) {
+               wlan_cancel_association_work(priv);
+       }
+
+       mutex_unlock(&adapter->lock);
+
+       LEAVE();
+       return ret;
+}
+
+/**
+ *  @brief Connect to the AP or Ad-hoc Network with specific bssid
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param awrq         A pointer to iw_param structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             0 --success, otherwise fail
+ */
+static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
+                struct sockaddr *awrq, char *extra)
+{
+       wlan_private *priv = dev->priv;
+       wlan_adapter *adapter = priv->adapter;
+       struct assoc_request * assoc_req;
+       int ret = 0;
+
+       ENTER();
+
+       if (awrq->sa_family != ARPHRD_ETHER)
+               return -EINVAL;
+
+       lbs_pr_debug(1, "ASSOC: WAP: sa_data: " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
+
+       mutex_lock(&adapter->lock);
+
+       /* Get or create the current association request */
+       assoc_req = wlan_get_association_request(adapter);
+       if (!assoc_req) {
+               wlan_cancel_association_work(priv);
+               ret = -ENOMEM;
+       } else {
+               /* Copy the BSSID to the association request */
+               memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
+               set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
+               wlan_postpone_association_work(priv);
+       }
+
+       mutex_unlock(&adapter->lock);
+
+       return ret;
+}
+
+void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
+{
+       union {
+               u32 l;
+               u8 c[4];
+       } ver;
+       char fwver[32];
+
+       mutex_lock(&adapter->lock);
+       ver.l = adapter->fwreleasenumber;
+       mutex_unlock(&adapter->lock);
+
+       if (ver.c[3] == 0)
+               sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
+       else
+               sprintf(fwver, "%u.%u.%u.p%u",
+                       ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+       snprintf(fwversion, maxlen, fwver);
+}
+
+
+/*
+ * iwconfig settable callbacks
+ */
+static const iw_handler wlan_handler[] = {
+       (iw_handler) NULL,      /* SIOCSIWCOMMIT */
+       (iw_handler) wlan_get_name,     /* SIOCGIWNAME */
+       (iw_handler) NULL,      /* SIOCSIWNWID */
+       (iw_handler) NULL,      /* SIOCGIWNWID */
+       (iw_handler) wlan_set_freq,     /* SIOCSIWFREQ */
+       (iw_handler) wlan_get_freq,     /* SIOCGIWFREQ */
+       (iw_handler) wlan_set_mode,     /* SIOCSIWMODE */
+       (iw_handler) wlan_get_mode,     /* SIOCGIWMODE */
+       (iw_handler) NULL,      /* SIOCSIWSENS */
+       (iw_handler) NULL,      /* SIOCGIWSENS */
+       (iw_handler) NULL,      /* SIOCSIWRANGE */
+       (iw_handler) wlan_get_range,    /* SIOCGIWRANGE */
+       (iw_handler) NULL,      /* SIOCSIWPRIV */
+       (iw_handler) NULL,      /* SIOCGIWPRIV */
+       (iw_handler) NULL,      /* SIOCSIWSTATS */
+       (iw_handler) NULL,      /* SIOCGIWSTATS */
+       iw_handler_set_spy,     /* SIOCSIWSPY */
+       iw_handler_get_spy,     /* SIOCGIWSPY */
+       iw_handler_set_thrspy,  /* SIOCSIWTHRSPY */
+       iw_handler_get_thrspy,  /* SIOCGIWTHRSPY */
+       (iw_handler) wlan_set_wap,      /* SIOCSIWAP */
+       (iw_handler) wlan_get_wap,      /* SIOCGIWAP */
+       (iw_handler) NULL,      /* SIOCSIWMLME */
+       (iw_handler) NULL,      /* SIOCGIWAPLIST - deprecated */
+       (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
+       (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
+       (iw_handler) wlan_set_essid,    /* SIOCSIWESSID */
+       (iw_handler) wlan_get_essid,    /* SIOCGIWESSID */
+       (iw_handler) wlan_set_nick,     /* SIOCSIWNICKN */
+       (iw_handler) wlan_get_nick,     /* SIOCGIWNICKN */
+       (iw_handler) NULL,      /* -- hole -- */
+       (iw_handler) NULL,      /* -- hole -- */
+       (iw_handler) wlan_set_rate,     /* SIOCSIWRATE */
+       (iw_handler) wlan_get_rate,     /* SIOCGIWRATE */
+       (iw_handler) wlan_set_rts,      /* SIOCSIWRTS */
+       (iw_handler) wlan_get_rts,      /* SIOCGIWRTS */
+       (iw_handler) wlan_set_frag,     /* SIOCSIWFRAG */
+       (iw_handler) wlan_get_frag,     /* SIOCGIWFRAG */
+       (iw_handler) wlan_set_txpow,    /* SIOCSIWTXPOW */
+       (iw_handler) wlan_get_txpow,    /* SIOCGIWTXPOW */
+       (iw_handler) wlan_set_retry,    /* SIOCSIWRETRY */
+       (iw_handler) wlan_get_retry,    /* SIOCGIWRETRY */
+       (iw_handler) wlan_set_encode,   /* SIOCSIWENCODE */
+       (iw_handler) wlan_get_encode,   /* SIOCGIWENCODE */
+       (iw_handler) wlan_set_power,    /* SIOCSIWPOWER */
+       (iw_handler) wlan_get_power,    /* SIOCGIWPOWER */
+       (iw_handler) NULL,      /* -- hole -- */
+       (iw_handler) NULL,      /* -- hole -- */
+       (iw_handler) wlan_set_genie,    /* SIOCSIWGENIE */
+       (iw_handler) wlan_get_genie,    /* SIOCGIWGENIE */
+       (iw_handler) wlan_set_auth,     /* SIOCSIWAUTH */
+       (iw_handler) wlan_get_auth,     /* SIOCGIWAUTH */
+       (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
+       (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
+       (iw_handler) NULL,              /* SIOCSIWPMKSA */
+};
+
+struct iw_handler_def libertas_handler_def = {
+       .num_standard   = sizeof(wlan_handler) / sizeof(iw_handler),
+       .num_private    = sizeof(wlan_private_handler) / sizeof(iw_handler),
+       .num_private_args = sizeof(wlan_private_args) /
+               sizeof(struct iw_priv_args),
+       .standard       = (iw_handler *) wlan_handler,
+       .private        = (iw_handler *) wlan_private_handler,
+       .private_args   = (struct iw_priv_args *)wlan_private_args,
+       .get_wireless_stats = wlan_get_wireless_stats,
+};
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
new file mode 100644 (file)
index 0000000..39f367c
--- /dev/null
@@ -0,0 +1,147 @@
+/**
+  * This file contains definition for IOCTL call.
+  */
+#ifndef        _WLAN_WEXT_H_
+#define        _WLAN_WEXT_H_
+
+#define SUBCMD_OFFSET                  4
+#define SUBCMD_DATA(x)                 *((int *)(x->u.name + SUBCMD_OFFSET))
+
+/** PRIVATE CMD ID */
+#define        WLANIOCTL                       SIOCIWFIRSTPRIV
+
+#define WLANSETWPAIE                   (WLANIOCTL + 0)
+
+#define WLAN_SETINT_GETINT             (WLANIOCTL + 7)
+#define WLANNF                                 1
+#define WLANRSSI                               2
+#define WLANENABLE11D                          5
+#define WLANADHOCGRATE                         6
+#define WLAN_SUBCMD_SET_PRESCAN                        11
+
+#define WLAN_SETNONE_GETNONE           (WLANIOCTL + 8)
+#define WLANDEAUTH                             1
+#define WLANRADIOON                            2
+#define WLANRADIOOFF                           3
+#define WLANREMOVEADHOCAES                     4
+#define WLANADHOCSTOP                          5
+#define WLANCIPHERTEST                         6
+#define WLANCRYPTOTEST                         7
+
+#define WLANWLANIDLEON                         10
+#define WLANWLANIDLEOFF                                11
+#define WLAN_SUBCMD_BT_RESET                   13
+#define WLAN_SUBCMD_FWT_RESET                  14
+
+#define WLANGETLOG                     (WLANIOCTL + 9)
+#define GETLOG_BUFSIZE  300
+
+#define WLANSCAN_TYPE                  (WLANIOCTL + 11)
+
+#define WLAN_SETNONE_GETONEINT         (WLANIOCTL + 15)
+#define WLANGETREGION                          1
+#define WLAN_GET_LISTEN_INTERVAL               2
+#define WLAN_GET_MULTIPLE_DTIM                 3
+#define WLAN_GET_TX_RATE                       4
+#define        WLANGETBCNAVG                           5
+
+#define WLAN_GET_LINKMODE                      6
+#define WLAN_GET_RADIOMODE                     7
+#define WLAN_GET_DEBUGMODE                     8
+#define WLAN_SUBCMD_FWT_CLEANUP                        15
+#define WLAN_SUBCMD_FWT_TIME                   16
+#define WLAN_SUBCMD_MESH_GET_TTL               17
+
+#define WLANREGCFRDWR                  (WLANIOCTL + 18)
+
+#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19)
+#define WLAN_SUBCMD_GETRXANTENNA    1
+#define WLAN_SUBCMD_GETTXANTENNA    2
+#define WLAN_GET_TSF                3
+
+#define WLAN_SETNONE_GETWORDCHAR       (WLANIOCTL + 21)
+#define WLANGETADHOCAES                                1
+
+#define WLAN_SETONEINT_GETONEINT       (WLANIOCTL + 23)
+#define WLAN_BEACON_INTERVAL                   1
+#define        WLAN_LISTENINTRVL                       4
+
+#define WLAN_TXCONTROL                         6
+#define WLAN_NULLPKTINTERVAL                   7
+
+#define WLAN_SETONEINT_GETNONE         (WLANIOCTL + 24)
+#define WLAN_SUBCMD_SETRXANTENNA               1
+#define WLAN_SUBCMD_SETTXANTENNA               2
+#define WLANSETAUTHALG                         5
+#define WLANSET8021XAUTHALG                    6
+#define WLANSETENCRYPTIONMODE                  7
+#define WLANSETREGION                          8
+#define WLAN_SET_LISTEN_INTERVAL               9
+
+#define WLAN_SET_MULTIPLE_DTIM                 10
+#define WLAN_SET_ATIM_WINDOW                   11
+#define WLANSETBCNAVG                          13
+#define WLANSETDATAAVG                         14
+#define WLAN_SET_LINKMODE                      15
+#define WLAN_SET_RADIOMODE                     16
+#define WLAN_SET_DEBUGMODE                     17
+#define WLAN_SUBCMD_MESH_SET_TTL               18
+
+#define WLAN_SET128CHAR_GET128CHAR     (WLANIOCTL + 25)
+#define WLANSCAN_MODE                          6
+
+#define WLAN_GET_ADHOC_STATUS                  9
+
+#define WLAN_SUBCMD_BT_ADD                     18
+#define WLAN_SUBCMD_BT_DEL                     19
+#define WLAN_SUBCMD_BT_LIST                    20
+#define WLAN_SUBCMD_FWT_ADD                            21
+#define WLAN_SUBCMD_FWT_DEL            22
+#define WLAN_SUBCMD_FWT_LOOKUP         23
+#define WLAN_SUBCMD_FWT_LIST_NEIGHBOR                  24
+#define WLAN_SUBCMD_FWT_LIST                   25
+#define WLAN_SUBCMD_FWT_LIST_ROUTE                     26
+
+#define WLAN_SET_GET_SIXTEEN_INT       (WLANIOCTL + 29)
+#define WLAN_TPCCFG                             1
+#define WLAN_POWERCFG                           2
+
+#define WLAN_AUTO_FREQ_SET                     3
+#define WLAN_AUTO_FREQ_GET                     4
+#define WLAN_LED_GPIO_CTRL                     5
+#define WLAN_SCANPROBES                        6
+#define        WLAN_ADAPT_RATESET                      8
+#define        WLAN_INACTIVITY_TIMEOUT                 9
+#define WLANSNR                                        10
+#define WLAN_GET_RATE                          11
+#define        WLAN_GET_RXINFO                         12
+
+#define WLANCMD52RDWR                  (WLANIOCTL + 30)
+#define WLANCMD53RDWR                  (WLANIOCTL + 31)
+#define CMD53BUFLEN                            32
+
+#define        REG_MAC                                 0x19
+#define        REG_BBP                                 0x1a
+#define        REG_RF                                  0x1b
+#define        REG_EEPROM                              0x59
+#define WLAN_LINKMODE_802_3                    0
+#define WLAN_LINKMODE_802_11                   2
+#define WLAN_RADIOMODE_NONE                            0
+#define WLAN_RADIOMODE_RADIOTAP                        2
+
+/** wlan_ioctl_regrdwr */
+struct wlan_ioctl_regrdwr {
+       /** Which register to access */
+       u16 whichreg;
+       /** Read or Write */
+       u16 action;
+       u32 offset;
+       u16 NOB;
+       u32 value;
+};
+
+extern struct iw_handler_def libertas_handler_def;
+int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+int wlan_radio_ioctl(wlan_private * priv, u8 option);
+
+#endif                         /* _WLAN_WEXT_H_ */
diff --git a/drivers/net/wireless/todo.txt b/drivers/net/wireless/todo.txt
deleted file mode 100644 (file)
index 3223401..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-       Wireless Todo
-       -------------
-
-1) Bring other kernel Wireless LAN drivers here
-       Completed
-
-2) Bring new Wireless LAN driver not yet in the kernel there
-       See my web page for details
-       In particular : HostAP
-
-3) Misc
-       o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete
-       o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete
-
-       Jean II
index 87ee3ee020fe11727c355bbae433fb07c5ee9ebe..95b4a2a26707b2f85cf6755d07092975450aa2a8 100644 (file)
@@ -67,11 +67,12 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
        i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
        i += scnprintf(buffer+i, size-i, " ");
        i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
-       i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type,
+       i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type,
                chip->patch_cck_gain ? 'g' : '-',
                chip->patch_cr157 ? '7' : '-',
                chip->patch_6m_band_edge ? '6' : '-',
-               chip->new_phy_layout ? 'N' : '-');
+               chip->new_phy_layout ? 'N' : '-',
+               chip->al2230s_bit ? 'S' : '-');
        return i;
 }
 
@@ -114,7 +115,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
        /* Allocate a single memory block for values and addresses. */
        count16 = 2*count;
        a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
-                                  GFP_NOFS);
+                                  GFP_KERNEL);
        if (!a16) {
                dev_dbg_f(zd_chip_dev(chip),
                          "error ENOMEM in allocation of a16\n");
@@ -163,7 +164,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
 
        /* Allocate a single memory block for values and addresses. */
        count16 = 2*count;
-       ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS);
+       ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_KERNEL);
        if (!ioreqs16) {
                r = -ENOMEM;
                dev_dbg_f(zd_chip_dev(chip),
@@ -614,16 +615,24 @@ static int patch_cr157(struct zd_chip *chip)
  * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge
  * bit (for AL2230, AL2230S)
  */
-static int patch_6m_band_edge(struct zd_chip *chip, int channel)
+static int patch_6m_band_edge(struct zd_chip *chip, u8 channel)
+{
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       if (!chip->patch_6m_band_edge)
+               return 0;
+
+       return zd_rf_patch_6m_band_edge(&chip->rf, channel);
+}
+
+/* Generic implementation of 6M band edge patching, used by most RFs via
+ * zd_rf_generic_patch_6m() */
+int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel)
 {
        struct zd_ioreq16 ioreqs[] = {
                { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
                { CR47,  0x1e },
        };
 
-       if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge)
-               return 0;
-
        /* FIXME: Channel 11 is not the edge for all regulatory domains. */
        if (channel == 1 || channel == 11)
                ioreqs[0].value = 0x12;
@@ -683,17 +692,17 @@ static int zd1211_hw_reset_phy(struct zd_chip *chip)
                { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
                { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
                { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f },
-               { CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 },
-               { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
-               { CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 },
-               { CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 },
-               { CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c },
-               { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c },
-               { CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 },
-               { CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa },
-               { CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea },
-               { CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a },
-               { CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba },
+               { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 },
+               { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C },
+               { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 },
+               { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 },
+               { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c },
+               { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 },
+               { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe },
+               { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
+               { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
+               { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
+               { CR170, 0xba }, { CR171, 0xba },
                /* Note: CR204 must lead the CR203 */
                { CR204, 0x7d },
                { },
index e57ed75d9425130f61901f64a401c3a2ec436ad1..ce0a5f6da0d2e3326442e1d6c913ecb681795130 100644 (file)
@@ -833,6 +833,7 @@ int zd_chip_enable_rx(struct zd_chip *chip);
 void zd_chip_disable_rx(struct zd_chip *chip);
 int zd_chip_enable_hwint(struct zd_chip *chip);
 int zd_chip_disable_hwint(struct zd_chip *chip);
+int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel);
 
 int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
        u8 rts_rate, int preamble);
index 4c5f78eac349a4f77d5d897a9936618c0dc562a3..6753d240c16825f9c0b0c4801f2874e8b57c462f 100644 (file)
@@ -156,17 +156,8 @@ void zd_mac_clear(struct zd_mac *mac)
 static int reset_mode(struct zd_mac *mac)
 {
        struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-       struct zd_ioreq32 ioreqs[] = {
-               { CR_RX_FILTER, STA_RX_FILTER },
-               { CR_SNIFFER_ON, 0U },
-       };
-
-       if (ieee->iw_mode == IW_MODE_MONITOR) {
-               ioreqs[0].value = 0xffffffff;
-               ioreqs[1].value = 0x1;
-       }
-
-       return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
+       u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
+       return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
 }
 
 int zd_mac_open(struct net_device *netdev)
@@ -974,14 +965,14 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
        switch (ieee->iw_mode) {
        case IW_MODE_ADHOC:
                if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
-                   memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0)
+                   compare_ether_addr(hdr->addr3, ieee->bssid) != 0)
                        return 0;
                break;
        case IW_MODE_AUTO:
        case IW_MODE_INFRA:
                if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
                    IEEE80211_FCTL_FROMDS ||
-                   memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0)
+                   compare_ether_addr(hdr->addr2, ieee->bssid) != 0)
                        return 0;
                break;
        default:
@@ -989,9 +980,9 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
                return 0;
        }
 
-       return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
+       return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 ||
               (is_multicast_ether_addr(hdr->addr1) &&
-               memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) ||
+               compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) ||
               (netdev->flags & IFF_PROMISC);
 }
 
@@ -1047,7 +1038,7 @@ static void update_qual_rssi(struct zd_mac *mac,
        hdr = (struct ieee80211_hdr_3addr *)buffer;
        if (length < offsetof(struct ieee80211_hdr_3addr, addr3))
                return;
-       if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0)
+       if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0)
                return;
 
        spin_lock_irqsave(&mac->lock, flags);
index f50cff3db9164e26658b34302295f9cecbf70abe..549c23bcd6ccce78b752060892f0326d6b54b57d 100644 (file)
@@ -23,7 +23,7 @@
 #include "zd_ieee80211.h"
 #include "zd_chip.h"
 
-static const char *rfs[] = {
+static const char * const rfs[] = {
        [0]             = "unknown RF0",
        [1]             = "unknown RF1",
        [UW2451_RF]     = "UW2451_RF",
@@ -34,7 +34,7 @@ static const char *rfs[] = {
        [AL2210_RF]     = "AL2210_RF",
        [MAXIM_NEW_RF]  = "MAXIM_NEW_RF",
        [UW2453_RF]     = "UW2453_RF",
-       [AL2230S_RF]    = "AL2230S_RF",
+       [UNKNOWN_A_RF]  = "UNKNOWN_A_RF",
        [RALINK_RF]     = "RALINK_RF",
        [INTERSIL_RF]   = "INTERSIL_RF",
        [RF2959_RF]     = "RF2959_RF",
@@ -154,3 +154,17 @@ int zd_switch_radio_off(struct zd_rf *rf)
                r = t;
        return r;
 }
+
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel)
+{
+       if (!rf->patch_6m_band_edge)
+               return 0;
+
+       return rf->patch_6m_band_edge(rf, channel);
+}
+
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel)
+{
+       return zd_chip_generic_patch_6m_band(zd_rf_to_chip(rf), channel);
+}
+
index a57732eb69e1ca136f2974685f5e56d3e6903734..aa9cc105ce60daf199c062952cddbfb83eeb6f48 100644 (file)
@@ -26,7 +26,7 @@
 #define AL2210_RF                      0x7
 #define MAXIM_NEW_RF                   0x8
 #define UW2453_RF                      0x9
-#define AL2230S_RF                     0xa
+#define UNKNOWN_A_RF                   0xa
 #define RALINK_RF                      0xb
 #define INTERSIL_RF                    0xc
 #define RF2959_RF                      0xd
@@ -47,17 +47,13 @@ struct zd_rf {
        u8 type;
 
        u8 channel;
-       /*
-        * Whether this RF should patch the 6M band edge
-        * (assuming E2P_POD agrees)
-        */
-       u8 patch_6m_band_edge:1;
 
        /* RF-specific functions */
        int (*init_hw)(struct zd_rf *rf);
        int (*set_channel)(struct zd_rf *rf, u8 channel);
        int (*switch_radio_on)(struct zd_rf *rf);
        int (*switch_radio_off)(struct zd_rf *rf);
+       int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel);
 };
 
 const char *zd_rf_name(u8 type);
@@ -72,6 +68,9 @@ int zd_rf_set_channel(struct zd_rf *rf, u8 channel);
 int zd_switch_radio_on(struct zd_rf *rf);
 int zd_switch_radio_off(struct zd_rf *rf);
 
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel);
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel);
+
 /* Functions for individual RF chips */
 
 int zd_rf_init_rf2959(struct zd_rf *rf);
index 5235a7827ac5effcd14ab26438bcc712987a3fa7..511392acfedf3f179359c840fb01b87e114f3124 100644 (file)
@@ -59,6 +59,18 @@ static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
        { CR240, 0x57 }, { CR9,   0xe0 },
 };
 
+static const struct zd_ioreq16 ioreqs_init_al2230s[] = {
+       { CR47,   0x1e }, /* MARK_002 */
+       { CR106,  0x22 },
+       { CR107,  0x2a }, /* MARK_002 */
+       { CR109,  0x13 }, /* MARK_002 */
+       { CR118,  0xf8 }, /* MARK_002 */
+       { CR119,  0x12 }, { CR122,  0xe0 },
+       { CR128,  0x10 }, /* MARK_001 from 0xe->0x10 */
+       { CR129,  0x0e }, /* MARK_001 from 0xd->0x0e */
+       { CR130,  0x10 }, /* MARK_001 from 0xb->0x0d */
+};
+
 static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
 {
        int r;
@@ -90,7 +102,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
        int r;
        struct zd_chip *chip = zd_rf_to_chip(rf);
 
-       static const struct zd_ioreq16 ioreqs[] = {
+       static const struct zd_ioreq16 ioreqs_init[] = {
                { CR15,   0x20 }, { CR23,   0x40 }, { CR24,  0x20 },
                { CR26,   0x11 }, { CR28,   0x3e }, { CR29,  0x00 },
                { CR44,   0x33 }, { CR106,  0x2a }, { CR107, 0x1a },
@@ -117,10 +129,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
                { CR119,  0x10 }, { CR120,  0x4f }, { CR121, 0x77 },
                { CR122,  0xe0 }, { CR137,  0x88 }, { CR252, 0xff },
                { CR253,  0xff },
+       };
 
-               /* These following happen separately in the vendor driver */
-               { },
-
+       static const struct zd_ioreq16 ioreqs_pll[] = {
                /* shdnb(PLL_ON)=0 */
                { CR251,  0x2f },
                /* shdnb(PLL_ON)=1 */
@@ -128,7 +139,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
                { CR138,  0x28 }, { CR203,  0x06 },
        };
 
-       static const u32 rv[] = {
+       static const u32 rv1[] = {
                /* Channel 1 */
                0x03f790,
                0x033331,
@@ -137,6 +148,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
                0x0b3331,
                0x03b812,
                0x00fff3,
+       };
+
+       static const u32 rv2[] = {
                0x000da4,
                0x0f4dc5, /* fix freq shift, 0x04edc5 */
                0x0805b6,
@@ -148,8 +162,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
                0x0bdffc,
                0x00000d,
                0x00500f,
+       };
 
-               /* These writes happen separately in the vendor driver */
+       static const u32 rv3[] = {
                0x00d00f,
                0x004c0f,
                0x00540f,
@@ -157,11 +172,38 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
                0x00500f,
        };
 
-       r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+       r = zd_iowrite16a_locked(chip, ioreqs_init, ARRAY_SIZE(ioreqs_init));
        if (r)
                return r;
 
-       r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+       if (chip->al2230s_bit) {
+               r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
+                       ARRAY_SIZE(ioreqs_init_al2230s));
+               if (r)
+                       return r;
+       }
+
+       r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+       if (r)
+               return r;
+
+       /* improve band edge for AL2230S */
+       if (chip->al2230s_bit)
+               r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS);
+       else
+               r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS);
+       if (r)
+               return r;
+
+       r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+       if (r)
+               return r;
+
+       r = zd_iowrite16a_locked(chip, ioreqs_pll, ARRAY_SIZE(ioreqs_pll));
+       if (r)
+               return r;
+
+       r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
        if (r)
                return r;
 
@@ -227,7 +269,9 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
                0x481dc0,
                0xcfff00,
                0x25a000,
+       };
 
+       static const u32 rv2[] = {
                /* To improve AL2230 yield, improve phase noise, 4713 */
                0x25a000,
                0xa3b2f0,
@@ -250,7 +294,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
                { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
        };
 
-       static const u32 rv2[] = {
+       static const u32 rv3[] = {
                /* To improve AL2230 yield, 4713 */
                0xf01b00,
                0xf01e00,
@@ -269,16 +313,35 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
        r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
        if (r)
                return r;
+
+       if (chip->al2230s_bit) {
+               r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
+                       ARRAY_SIZE(ioreqs_init_al2230s));
+               if (r)
+                       return r;
+       }
+
        r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3);
        if (r)
                return r;
        r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1));
        if (r)
                return r;
-       r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+
+       if (chip->al2230s_bit)
+               r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS);
+       else
+               r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS);
        if (r)
                return r;
+
        r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2));
+       if (r)
+               return r;
+       r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+       if (r)
+               return r;
+       r = zd_rfwritev_cr_locked(chip, rv3, ARRAY_SIZE(rv3));
        if (r)
                return r;
        r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
@@ -358,12 +421,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
 {
        struct zd_chip *chip = zd_rf_to_chip(rf);
 
-       if (chip->al2230s_bit) {
-               dev_err(zd_chip_dev(chip), "AL2230S devices are not yet "
-                       "supported by this driver.\n");
-               return -ENODEV;
-       }
-
        rf->switch_radio_off = al2230_switch_radio_off;
        if (chip->is_zd1211b) {
                rf->init_hw = zd1211b_al2230_init_hw;
@@ -374,6 +431,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
                rf->set_channel = zd1211_al2230_set_channel;
                rf->switch_radio_on = zd1211_al2230_switch_radio_on;
        }
-       rf->patch_6m_band_edge = 1;
+       rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
        return 0;
 }
index a289f95187ec5cd8ab9fc8597e11cd5b9121ddf4..5e5e9ddc6a7467501fe6bc891df6b3980dbb2a8b 100644 (file)
@@ -51,9 +51,52 @@ static const u32 std_rv[] = {
        0xd8c010,
 };
 
-static int al7230b_init_hw(struct zd_rf *rf)
+static const u32 rv_init1[] = {
+       0x3c9000,
+       0xbfffff,
+       0x700000,
+       0xf15d58,
+};
+
+static const u32 rv_init2[] = {
+       0xf15d59,
+       0xf15d5c,
+       0xf15d58,
+};
+
+static const struct zd_ioreq16 ioreqs_sw[] = {
+       { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+       { CR38,  0x38 }, { CR136, 0xdf },
+};
+
+static int zd1211b_al7230b_finalize(struct zd_chip *chip)
 {
-       int i, r;
+       int r;
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR80,  0x30 }, { CR81,  0x30 }, { CR79,  0x58 },
+               { CR12,  0xf0 }, { CR77,  0x1b }, { CR78,  0x58 },
+               { CR203, 0x04 },
+               { },
+               { CR240, 0x80 },
+       };
+
+       r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+       if (r)
+               return r;
+
+       if (chip->new_phy_layout) {
+               /* antenna selection? */
+               r = zd_iowrite16_locked(chip, 0xe5, CR9);
+               if (r)
+                       return r;
+       }
+
+       return zd_iowrite16_locked(chip, 0x04, CR203);
+}
+
+static int zd1211_al7230b_init_hw(struct zd_rf *rf)
+{
+       int r;
        struct zd_chip *chip = zd_rf_to_chip(rf);
 
        /* All of these writes are identical to AL2230 unless otherwise
@@ -117,39 +160,136 @@ static int al7230b_init_hw(struct zd_rf *rf)
        };
 
        static const struct zd_ioreq16 ioreqs_2[] = {
-               /* PLL_ON */
-               { CR251, 0x3f },
+               { CR251, 0x3f }, /* PLL_ON */
                { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
-               { CR38, 0x38 }, { CR136, 0xdf },
+               { CR38,  0x38 }, { CR136, 0xdf },
        };
 
        r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
        if (r)
                return r;
 
-       r = zd_rfwrite_cr_locked(chip, 0x09ec04);
+       r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0]));
        if (r)
                return r;
-       r = zd_rfwrite_cr_locked(chip, 0x8cccc8);
+
+       r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
        if (r)
                return r;
 
-       for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
-               r = zd_rfwrite_cr_locked(chip, std_rv[i]);
-               if (r)
-                       return r;
-       }
+       r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1));
+       if (r)
+               return r;
 
-       r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+       r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
        if (r)
                return r;
-       r = zd_rfwrite_cr_locked(chip, 0xbfffff);
+
+       r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2));
        if (r)
                return r;
-       r = zd_rfwrite_cr_locked(chip, 0x700000);
+
+       r = zd_iowrite16_locked(chip, 0x06, CR203);
        if (r)
                return r;
-       r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+       r = zd_iowrite16_locked(chip, 0x80, CR240);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+static int zd1211b_al7230b_init_hw(struct zd_rf *rf)
+{
+       int r;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       static const struct zd_ioreq16 ioreqs_1[] = {
+               { CR240, 0x57 }, { CR9,   0x9 },
+               { },
+               { CR10,  0x8b }, { CR15,  0x20 },
+               { CR17,  0x2B }, /* for newest (3rd cut) AL2230 */
+               { CR20,  0x10 }, /* 4N25->Stone Request */
+               { CR23,  0x40 }, { CR24,  0x20 }, { CR26,  0x93 },
+               { CR28,  0x3e }, { CR29,  0x00 },
+               { CR33,  0x28 }, /* 5613 */
+               { CR34,  0x30 },
+               { CR35,  0x3e }, /* for newest (3rd cut) AL2230 */
+               { CR41,  0x24 }, { CR44,  0x32 },
+               { CR46,  0x99 }, /* for newest (3rd cut) AL2230 */
+               { CR47,  0x1e },
+
+               /* ZD1215 5610 */
+               { CR48,  0x00 }, { CR49,  0x00 }, { CR51,  0x01 },
+               { CR52,  0x80 }, { CR53,  0x7e }, { CR65,  0x00 },
+               { CR66,  0x00 }, { CR67,  0x00 }, { CR68,  0x00 },
+               { CR69,  0x28 },
+
+               { CR79,  0x58 }, { CR80,  0x30 }, { CR81,  0x30 },
+               { CR87,  0x0A }, { CR89,  0x04 },
+               { CR90,  0x58 }, /* 5112 */
+               { CR91,  0x00 }, /* 5613 */
+               { CR92,  0x0a },
+               { CR98,  0x8d }, /* 4804, for 1212 new algorithm */
+               { CR99,  0x00 }, { CR100, 0x02 }, { CR101, 0x13 },
+               { CR102, 0x27 },
+               { CR106, 0x20 }, /* change to 0x24 for AL7230B */
+               { CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+               { CR112, 0x1f },
+       };
+
+       static const struct zd_ioreq16 ioreqs_new_phy[] = {
+               { CR107, 0x28 },
+               { CR110, 0x1f }, /* 5127, 0x13->0x1f */
+               { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */
+               { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 },
+               { CR121, 0x6c }, /* 5613 */
+       };
+
+       static const struct zd_ioreq16 ioreqs_old_phy[] = {
+               { CR107, 0x24 },
+               { CR110, 0x13 }, /* 5127, 0x13->0x1f */
+               { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */
+               { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 },
+               { CR121, 0x6a }, /* 5613 */
+       };
+
+       static const struct zd_ioreq16 ioreqs_2[] = {
+               { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 },
+               { CR117, 0xfa }, { CR120, 0x4f },
+               { CR122, 0xfc }, /* E0->FCh at 4901 */
+               { CR123, 0x57 }, /* 5613 */
+               { CR125, 0xad }, /* 4804, for 1212 new algorithm */
+               { CR126, 0x6c }, /* 5613 */
+               { CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+               { CR130, 0x10 },
+               { CR131, 0x00 }, /* 5112 */
+               { CR137, 0x50 }, /* 5613 */
+               { CR138, 0xa8 }, /* 5112 */
+               { CR144, 0xac }, /* 5613 */
+               { CR148, 0x40 }, /* 5112 */
+               { CR149, 0x40 }, /* 4O07, 50->40 */
+               { CR150, 0x1a }, /* 5112, 0C->1A */
+               { CR252, 0x34 }, { CR253, 0x34 },
+               { CR251, 0x2f }, /* PLL_OFF */
+       };
+
+       static const struct zd_ioreq16 ioreqs_3[] = {
+               { CR251, 0x7f }, /* PLL_ON */
+               { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+               { CR38,  0x38 }, { CR136, 0xdf },
+       };
+
+       r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+       if (r)
+               return r;
+
+       if (chip->new_phy_layout)
+               r = zd_iowrite16a_locked(chip, ioreqs_new_phy,
+                       ARRAY_SIZE(ioreqs_new_phy));
+       else
+               r = zd_iowrite16a_locked(chip, ioreqs_old_phy,
+                       ARRAY_SIZE(ioreqs_old_phy));
        if (r)
                return r;
 
@@ -157,38 +297,36 @@ static int al7230b_init_hw(struct zd_rf *rf)
        if (r)
                return r;
 
-       r = zd_rfwrite_cr_locked(chip, 0xf15d59);
+       r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0]));
        if (r)
                return r;
-       r = zd_rfwrite_cr_locked(chip, 0xf15d5c);
+
+       r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
        if (r)
                return r;
-       r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+
+       r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1));
        if (r)
                return r;
 
-       r = zd_iowrite16_locked(chip, 0x06, CR203);
+       r = zd_iowrite16a_locked(chip, ioreqs_3, ARRAY_SIZE(ioreqs_3));
        if (r)
                return r;
-       r = zd_iowrite16_locked(chip, 0x80, CR240);
+
+       r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2));
        if (r)
                return r;
 
-       return 0;
+       return zd1211b_al7230b_finalize(chip);
 }
 
-static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
+static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel)
 {
-       int i, r;
+       int r;
        const u32 *rv = chan_rv[channel-1];
        struct zd_chip *chip = zd_rf_to_chip(rf);
 
-       struct zd_ioreq16 ioreqs_1[] = {
-               { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
-               { CR38,  0x38 }, { CR136, 0xdf },
-       };
-
-       struct zd_ioreq16 ioreqs_2[] = {
+       static const struct zd_ioreq16 ioreqs[] = {
                /* PLL_ON */
                { CR251, 0x3f },
                { CR203, 0x06 }, { CR240, 0x08 },
@@ -203,11 +341,9 @@ static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
        if (r)
                return r;
 
-       for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
-               r = zd_rfwrite_cr_locked(chip, std_rv[i]);
-               if (r)
-                       return r;
-       }
+       r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
+       if (r)
+               return r;
 
        r = zd_rfwrite_cr_locked(chip, 0x3c9000);
        if (r)
@@ -216,24 +352,69 @@ static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
        if (r)
                return r;
 
-       r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+       r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw));
        if (r)
                return r;
 
-       for (i = 0; i < 2; i++) {
-               r = zd_rfwrite_cr_locked(chip, rv[i]);
-               if (r)
-                       return r;
-       }
+       r = zd_rfwritev_cr_locked(chip, rv, 2);
+       if (r)
+               return r;
 
        r = zd_rfwrite_cr_locked(chip, 0x3c9000);
        if (r)
                return r;
 
-       return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
-static int al7230b_switch_radio_on(struct zd_rf *rf)
+static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel)
+{
+       int r;
+       const u32 *rv = chan_rv[channel-1];
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       r = zd_iowrite16_locked(chip, 0x57, CR240);
+       if (r)
+               return r;
+       r = zd_iowrite16_locked(chip, 0xe4, CR9);
+       if (r)
+               return r;
+
+       /* PLL_OFF */
+       r = zd_iowrite16_locked(chip, 0x2f, CR251);
+       if (r)
+               return r;
+       r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
+       if (r)
+               return r;
+
+       r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+       if (r)
+               return r;
+       r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+       if (r)
+               return r;
+
+       r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw));
+       if (r)
+               return r;
+
+       r = zd_rfwritev_cr_locked(chip, rv, 2);
+       if (r)
+               return r;
+
+       r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+       if (r)
+               return r;
+
+       r = zd_iowrite16_locked(chip, 0x7f, CR251);
+       if (r)
+               return r;
+
+       return zd1211b_al7230b_finalize(chip);
+}
+
+static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf)
 {
        struct zd_chip *chip = zd_rf_to_chip(rf);
        static const struct zd_ioreq16 ioreqs[] = {
@@ -244,6 +425,17 @@ static int al7230b_switch_radio_on(struct zd_rf *rf)
        return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
+static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf)
+{
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR11,  0x00 },
+               { CR251, 0x7f },
+       };
+
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
 static int al7230b_switch_radio_off(struct zd_rf *rf)
 {
        struct zd_chip *chip = zd_rf_to_chip(rf);
@@ -255,20 +447,45 @@ static int al7230b_switch_radio_off(struct zd_rf *rf)
        return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
+/* ZD1211B+AL7230B 6m band edge patching differs slightly from other
+ * configurations */
+static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel)
+{
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+       struct zd_ioreq16 ioreqs[] = {
+               { CR128, 0x14 }, { CR129, 0x12 },
+       };
+
+       /* FIXME: Channel 11 is not the edge for all regulatory domains. */
+       if (channel == 1) {
+               ioreqs[0].value = 0x0e;
+               ioreqs[1].value = 0x10;
+       } else if (channel == 11) {
+               ioreqs[0].value = 0x10;
+               ioreqs[1].value = 0x10;
+       }
+
+       dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel);
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
 int zd_rf_init_al7230b(struct zd_rf *rf)
 {
        struct zd_chip *chip = zd_rf_to_chip(rf);
 
        if (chip->is_zd1211b) {
-               dev_err(zd_chip_dev(chip), "AL7230B is currently not "
-                       "supported for ZD1211B devices\n");
-               return -ENODEV;
+               rf->init_hw = zd1211b_al7230b_init_hw;
+               rf->switch_radio_on = zd1211b_al7230b_switch_radio_on;
+               rf->set_channel = zd1211b_al7230b_set_channel;
+               rf->patch_6m_band_edge = zd1211b_al7230b_patch_6m;
+       } else {
+               rf->init_hw = zd1211_al7230b_init_hw;
+               rf->switch_radio_on = zd1211_al7230b_switch_radio_on;
+               rf->set_channel = zd1211_al7230b_set_channel;
+               rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
        }
 
-       rf->init_hw = al7230b_init_hw;
-       rf->set_channel = al7230b_set_channel;
-       rf->switch_radio_on = al7230b_switch_radio_on;
        rf->switch_radio_off = al7230b_switch_radio_off;
-       rf->patch_6m_band_edge = 1;
+
        return 0;
 }
index 58247271cc240abc4bf31d4cd8dc26404dfa107e..2d736bdf707c6329358f3568e08a5c62df68e230 100644 (file)
@@ -21,7 +21,7 @@
 #include "zd_usb.h"
 #include "zd_chip.h"
 
-static u32 rf2959_table[][2] = {
+static const u32 rf2959_table[][2] = {
        RF_CHANNEL( 1) = { 0x181979, 0x1e6666 },
        RF_CHANNEL( 2) = { 0x181989, 0x1e6666 },
        RF_CHANNEL( 3) = { 0x181999, 0x1e6666 },
@@ -228,7 +228,7 @@ static int rf2959_init_hw(struct zd_rf *rf)
 static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
 {
        int i, r;
-       u32 *rv = rf2959_table[channel-1];
+       const u32 *rv = rf2959_table[channel-1];
        struct zd_chip *chip = zd_rf_to_chip(rf);
 
        for (i = 0; i < 2; i++) {
index edaaad2f648b627493abc6954d0d76558e24eec3..e04cffc8adf305240d6f7f5923af55550f91262d 100644 (file)
@@ -52,6 +52,7 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
        /* ZD1211B */
        { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -62,7 +63,10 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
        /* "Driverless" devices that need ejecting */
        { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
        {}
@@ -413,7 +417,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
 
        dev_dbg_f(zd_usb_dev(usb), "\n");
 
-       urb = usb_alloc_urb(0, GFP_NOFS);
+       urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!urb) {
                r = -ENOMEM;
                goto out;
@@ -431,7 +435,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
 
        /* TODO: make it a DMA buffer */
        r = -ENOMEM;
-       transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS);
+       transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_KERNEL);
        if (!transfer_buffer) {
                dev_dbg_f(zd_usb_dev(usb),
                        "couldn't allocate transfer_buffer\n");
@@ -445,7 +449,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
                         intr->interval);
 
        dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
-       r = usb_submit_urb(urb, GFP_NOFS);
+       r = usb_submit_urb(urb, GFP_KERNEL);
        if (r) {
                dev_dbg_f(zd_usb_dev(usb),
                         "Couldn't submit urb. Error number %d\n", r);
@@ -594,10 +598,10 @@ static struct urb *alloc_urb(struct zd_usb *usb)
        struct urb *urb;
        void *buffer;
 
-       urb = usb_alloc_urb(0, GFP_NOFS);
+       urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!urb)
                return NULL;
-       buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS,
+       buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
                                  &urb->transfer_dma);
        if (!buffer) {
                usb_free_urb(urb);
@@ -630,7 +634,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
        dev_dbg_f(zd_usb_dev(usb), "\n");
 
        r = -ENOMEM;
-       urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS);
+       urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
        if (!urbs)
                goto error;
        for (i = 0; i < URBS_COUNT; i++) {
@@ -651,7 +655,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
        spin_unlock_irq(&rx->lock);
 
        for (i = 0; i < URBS_COUNT; i++) {
-               r = usb_submit_urb(urbs[i], GFP_NOFS);
+               r = usb_submit_urb(urbs[i], GFP_KERNEL);
                if (r)
                        goto error_submit;
        }
@@ -1157,7 +1161,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
        }
 
        req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
-       req = kmalloc(req_len, GFP_NOFS);
+       req = kmalloc(req_len, GFP_KERNEL);
        if (!req)
                return -ENOMEM;
        req->id = cpu_to_le16(USB_REQ_READ_REGS);
@@ -1220,7 +1224,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
 
        req_len = sizeof(struct usb_req_write_regs) +
                  count * sizeof(struct reg_data);
-       req = kmalloc(req_len, GFP_NOFS);
+       req = kmalloc(req_len, GFP_KERNEL);
        if (!req)
                return -ENOMEM;
 
@@ -1300,7 +1304,7 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
        bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
 
        req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
-       req = kmalloc(req_len, GFP_NOFS);
+       req = kmalloc(req_len, GFP_KERNEL);
        if (!req)
                return -ENOMEM;
 
index a064f36a0805d605e3e3edbf5ed87be5c7ee3819..b5ac810404c0f19dc98318dfe8dde6212d04c2bb 100644 (file)
@@ -317,6 +317,10 @@ static int __init acpi_pci_init(void)
 {
        int ret;
 
+       if (acpi_gbl_FADT.boot_flags & BAF_MSI_NOT_SUPPORTED) {
+               printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n");
+               pci_no_msi();
+       }
        ret = register_acpi_bus_type(&acpi_pci_bus);
        if (ret)
                return 0;
index 65d6f23ead4151ae6953477f6eeed653df0cdd06..3411483240cd7166db36d84c8760b18c67b0cf59 100644 (file)
@@ -1303,119 +1303,6 @@ static void __init quirk_alder_ioapic(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_EESSC,      quirk_alder_ioapic );
 #endif
 
-enum ide_combined_type { COMBINED = 0, IDE = 1, LIBATA = 2 };
-/* Defaults to combined */
-static enum ide_combined_type combined_mode;
-
-static int __init combined_setup(char *str)
-{
-       if (!strncmp(str, "ide", 3))
-               combined_mode = IDE;
-       else if (!strncmp(str, "libata", 6))
-               combined_mode = LIBATA;
-       else /* "combined" or anything else defaults to old behavior */
-               combined_mode = COMBINED;
-
-       return 1;
-}
-__setup("combined_mode=", combined_setup);
-
-#ifdef CONFIG_SATA_INTEL_COMBINED
-static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
-{
-       u8 prog, comb, tmp;
-       int ich = 0;
-
-       /*
-        * Narrow down to Intel SATA PCI devices.
-        */
-       switch (pdev->device) {
-       /* PCI ids taken from drivers/scsi/ata_piix.c */
-       case 0x24d1:
-       case 0x24df:
-       case 0x25a3:
-       case 0x25b0:
-               ich = 5;
-               break;
-       case 0x2651:
-       case 0x2652:
-       case 0x2653:
-       case 0x2680:    /* ESB2 */
-               ich = 6;
-               break;
-       case 0x27c0:
-       case 0x27c4:
-               ich = 7;
-               break;
-       case 0x2828:    /* ICH8M */
-               ich = 8;
-               break;
-       default:
-               /* we do not handle this PCI device */
-               return;
-       }
-
-       /*
-        * Read combined mode register.
-        */
-       pci_read_config_byte(pdev, 0x90, &tmp); /* combined mode reg */
-
-       if (ich == 5) {
-               tmp &= 0x6;  /* interesting bits 2:1, PATA primary/secondary */
-               if (tmp == 0x4)         /* bits 10x */
-                       comb = (1 << 0);        /* SATA port 0, PATA port 1 */
-               else if (tmp == 0x6)    /* bits 11x */
-                       comb = (1 << 2);        /* PATA port 0, SATA port 1 */
-               else
-                       return;                 /* not in combined mode */
-       } else {
-               WARN_ON((ich != 6) && (ich != 7) && (ich != 8));
-               tmp &= 0x3;  /* interesting bits 1:0 */
-               if (tmp & (1 << 0))
-                       comb = (1 << 2);        /* PATA port 0, SATA port 1 */
-               else if (tmp & (1 << 1))
-                       comb = (1 << 0);        /* SATA port 0, PATA port 1 */
-               else
-                       return;                 /* not in combined mode */
-       }
-
-       /*
-        * Read programming interface register.
-        * (Tells us if it's legacy or native mode)
-        */
-       pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
-
-       /* if SATA port is in native mode, we're ok. */
-       if (prog & comb)
-               return;
-
-       /* Don't reserve any so the IDE driver can get them (but only if
-        * combined_mode=ide).
-        */
-       if (combined_mode == IDE)
-               return;
-
-       /* Grab them both for libata if combined_mode=libata. */
-       if (combined_mode == LIBATA) {
-               request_region(0x1f0, 8, "libata");     /* port 0 */
-               request_region(0x170, 8, "libata");     /* port 1 */
-               return;
-       }
-
-       /* SATA port is in legacy mode.  Reserve port so that
-        * IDE driver does not attempt to use it.  If request_region
-        * fails, it will be obvious at boot time, so we don't bother
-        * checking return values.
-        */
-       if (comb == (1 << 0))
-               request_region(0x1f0, 8, "libata");     /* port 0 */
-       else
-               request_region(0x170, 8, "libata");     /* port 1 */
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_ANY_ID,      quirk_intel_ide_combined );
-#endif /* CONFIG_SATA_INTEL_COMBINED */
-
-
 int pcie_mch_quirk;
 EXPORT_SYMBOL(pcie_mch_quirk);
 
index 6c12744eeb9d24a5c4249c24386d7f8f14d40b08..7d7cab1d91b460a7311db72c8869e77d8eaf9de1 100644 (file)
@@ -82,14 +82,6 @@ struct ports_bmp {
        u64 unused[3];
 } __attribute__ ((aligned (32)));
 
-/* redefine dev_dbg to do a syntax check */
-
-#if !defined(DEBUG)
-#undef dev_dbg
-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
-       const struct device *_dev, const char *fmt, ...) {return 0;}
-#endif
-
 #define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
 static void __attribute__ ((unused)) _dump_ports_bmp(
        const struct ports_bmp* bmp, const char* func, int line)
index 4368ca0e8270b7a4b9b8d75596dcbb79d906c0c6..a39a478bb39a2351c13df1fa2bbe2fad7eb182e4 100644 (file)
@@ -897,9 +897,9 @@ static int get_system_info(void)
 {
        struct device_node *rootdn;
        const char *id, *model, *name;
-       unsigned int *num;
+       const unsigned int *num;
 
-       rootdn = find_path_device("/");
+       rootdn = of_find_node_by_path("/");
        if (!rootdn)
                return -ENOENT;
 
@@ -912,10 +912,11 @@ static int get_system_info(void)
        if (name)
                strncpy(partition_name, name, sizeof(partition_name));
 
-       num = (unsigned int *) get_property(rootdn, "ibm,partition-no", NULL);
+       num = get_property(rootdn, "ibm,partition-no", NULL);
        if (num)
                partition_number = *num;
 
+       of_node_put(rootdn);
        return 0;
 }
 
index 227c0f2f4d74e6d580043c0adc77d22de7a1e7ca..0a533f398f52482fa05537f375ebce744d1256b3 100644 (file)
@@ -157,7 +157,7 @@ static void gather_partition_info(void)
        const unsigned int *p_number_ptr;
 
        /* Retrieve information about this partition */
-       rootdn = find_path_device("/");
+       rootdn = of_find_node_by_path("/");
        if (!rootdn) {
                return;
        }
@@ -169,6 +169,7 @@ static void gather_partition_info(void)
        p_number_ptr = get_property(rootdn, "ibm,partition-no", NULL);
        if (p_number_ptr)
                partition_number = *p_number_ptr;
+       of_node_put(rootdn);
 }
 
 static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
index 95045e33710d488b758374d17956f0f4074b837a..e9bd29975db4361913161ee5b1d24b88ff5c0ef9 100644 (file)
@@ -3770,7 +3770,8 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
  * Return value:
  *     0 on success / non-zero on failure
  **/
-static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes)
+static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes,
+                               unsigned long deadline)
 {
        struct ipr_sata_port *sata_port = ap->private_data;
        struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
index 9f7482d0b59489e7efccc347a8b7ce33208b4cdb..05d79af5ab90bfe76b58f1a77aab3eb215a83ec8 100644 (file)
@@ -31,7 +31,7 @@
 
 
 #define SG_MEMPOOL_NR          ARRAY_SIZE(scsi_sg_pools)
-#define SG_MEMPOOL_SIZE                32
+#define SG_MEMPOOL_SIZE                2
 
 struct scsi_host_sg_pool {
        size_t          size;
index 752ef07516b9d7d6cfa6ec2842334b0a790ab20a..be8d75721a85cfd8245b508ed3e3377afe14a140 100644 (file)
@@ -1467,7 +1467,8 @@ no_dma:
        if (ZS_IS_IRDA(uap))
                uap->port_type = PMAC_SCC_IRDA;
        if (ZS_IS_INTMODEM(uap)) {
-               struct device_node* i2c_modem = find_devices("i2c-modem");
+               struct device_node* i2c_modem =
+                       of_find_node_by_name(NULL, "i2c-modem");
                if (i2c_modem) {
                        const char* mid =
                                get_property(i2c_modem, "modem-id", NULL);
@@ -1482,6 +1483,7 @@ no_dma:
                        }
                        printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n",
                                mid ? (*mid) : 0);
+                       of_node_put(i2c_modem);
                } else {
                        printk(KERN_INFO "pmac_zilog: serial modem detected\n");
                }
index 8372ace4a0d936181b0dee19e17e100ad127e7d7..b1cb72c3780fe562a7a382bc339c62308f978a03 100644 (file)
@@ -396,7 +396,7 @@ config FB_ATARI
 
 config FB_OF
        bool "Open Firmware frame buffer device support"
-       depends on (FB = y) && (PPC64 || PPC_OF)
+       depends on (FB = y) && (PPC64 || PPC_OF) && (!PPC_PSERIES || PCI)
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
index 9a2b0d69b0ae7ebdb8bc0dac91a686e986c27f11..c411293cefc8a9bb3a88ca46f5abf0b185cf4b3b 100644 (file)
@@ -1262,7 +1262,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
        /* This is the code for the Aluminium PowerBooks M10 / iBooks M11 */
        if (rinfo->family == CHIP_FAMILY_RV350) {
                u32 sdram_mode_reg = rinfo->save_regs[35];
-               static u32 default_mrtable[] =
+               static const u32 default_mrtable[] =
                        { 0x21320032,
                          0x21321000, 0xa1321000, 0x21321000, 0xffffffff,
                          0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
index fd60dba294dabf28882b3d2084fd1bc23ecf8828..8b762739b1e02720ff36bc2010165760a4c252ed 100644 (file)
@@ -179,12 +179,14 @@ MODULE_LICENSE("GPL");
 int init_module(void)
 {
        struct device_node *dp;
+       int ret = -ENXIO;
 
-       dp = find_devices("control");
+       dp = of_find_node_by_name(NULL, "control");
        if (dp != 0 && !control_of_init(dp))
-               return 0;
+               ret = 0;
+       of_node_put(dp);
 
-       return -ENXIO;
+       return ret;
 }
 
 void cleanup_module(void)
@@ -589,16 +591,18 @@ static int __init control_init(void)
 {
        struct device_node *dp;
        char *option = NULL;
+       int ret = -ENXIO;
 
        if (fb_get_options("controlfb", &option))
                return -ENODEV;
        control_setup(option);
 
-       dp = find_devices("control");
+       dp = of_find_node_by_name(NULL, "control");
        if (dp != 0 && !control_of_init(dp))
-               return 0;
+               ret = 0;
+       of_node_put(dp);
 
-       return -ENXIO;
+       return ret;
 }
 
 module_init(control_init);
index 7618bcb1836848737921c48302359a29a583e23b..693940da40904f537eadf099662fbe9194867eea 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -28,7 +28,7 @@
 #include <linux/blktrace_api.h>
 #include <scsi/sg.h>           /* for struct sg_iovec */
 
-#define BIO_POOL_SIZE 256
+#define BIO_POOL_SIZE 2
 
 static struct kmem_cache *bio_slab __read_mostly;
 
@@ -38,7 +38,7 @@ static struct kmem_cache *bio_slab __read_mostly;
  * a small number of entries is fine, not going to be performance critical.
  * basically we just need to survive
  */
-#define BIO_SPLIT_ENTRIES 8    
+#define BIO_SPLIT_ENTRIES 2
 mempool_t *bio_split_pool __read_mostly;
 
 struct biovec_slab {
@@ -1120,7 +1120,7 @@ struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, int first_sectors)
  * create memory pools for biovec's in a bio_set.
  * use the global biovec slabs created for general use.
  */
-static int biovec_create_pools(struct bio_set *bs, int pool_entries, int scale)
+static int biovec_create_pools(struct bio_set *bs, int pool_entries)
 {
        int i;
 
@@ -1128,9 +1128,6 @@ static int biovec_create_pools(struct bio_set *bs, int pool_entries, int scale)
                struct biovec_slab *bp = bvec_slabs + i;
                mempool_t **bvp = bs->bvec_pools + i;
 
-               if (pool_entries > 1 && i >= scale)
-                       pool_entries >>= 1;
-
                *bvp = mempool_create_slab_pool(pool_entries, bp->slab);
                if (!*bvp)
                        return -ENOMEM;
@@ -1161,7 +1158,7 @@ void bioset_free(struct bio_set *bs)
        kfree(bs);
 }
 
-struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size, int scale)
+struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size)
 {
        struct bio_set *bs = kzalloc(sizeof(*bs), GFP_KERNEL);
 
@@ -1172,7 +1169,7 @@ struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size, int scale)
        if (!bs->bio_pool)
                goto bad;
 
-       if (!biovec_create_pools(bs, bvec_pool_size, scale))
+       if (!biovec_create_pools(bs, bvec_pool_size))
                return bs;
 
 bad:
@@ -1196,38 +1193,12 @@ static void __init biovec_init_slabs(void)
 
 static int __init init_bio(void)
 {
-       int megabytes, bvec_pool_entries;
-       int scale = BIOVEC_NR_POOLS;
-
        bio_slab = kmem_cache_create("bio", sizeof(struct bio), 0,
                                SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
 
        biovec_init_slabs();
 
-       megabytes = nr_free_pages() >> (20 - PAGE_SHIFT);
-
-       /*
-        * find out where to start scaling
-        */
-       if (megabytes <= 16)
-               scale = 0;
-       else if (megabytes <= 32)
-               scale = 1;
-       else if (megabytes <= 64)
-               scale = 2;
-       else if (megabytes <= 96)
-               scale = 3;
-       else if (megabytes <= 128)
-               scale = 4;
-
-       /*
-        * Limit number of entries reserved -- mempools are only used when
-        * the system is completely unable to allocate memory, so we only
-        * need enough to make progress.
-        */
-       bvec_pool_entries = 1 + scale;
-
-       fs_bio_set = bioset_create(BIO_POOL_SIZE, bvec_pool_entries, scale);
+       fs_bio_set = bioset_create(BIO_POOL_SIZE, 2);
        if (!fs_bio_set)
                panic("bio: can't allocate bios\n");
 
index abdf068bc27f4cb9b7699d4a6b478725aa25c180..eca471bc85125626d32c011a820fd828f3124837 100644 (file)
@@ -38,7 +38,7 @@ static int property_read_proc(char *page, char **start, off_t off,
                n = count;
        else
                *eof = 1;
-       memcpy(page, pp->value + off, n);
+       memcpy(page, (char *)pp->value + off, n);
        *start = page;
        return n;
 }
index 09469e7db6a542e6ae7ebbc8d1125b9d5e1c59e7..955adfb8d64c2358d0c7f449a51adc93ecd964bd 100644 (file)
@@ -276,6 +276,7 @@ enum acpi_prefered_pm_profiles {
 
 #define BAF_LEGACY_DEVICES              0x0001
 #define BAF_8042_KEYBOARD_CONTROLLER    0x0002
+#define BAF_MSI_NOT_SUPPORTED           0x0008
 
 #define FADT2_REVISION_ID               3
 #define FADT2_MINUS_REVISION_ID         2
index c89bd58ee2839be66fc98059172523d246d412b4..c19e7367fce67e9db83c1e59fc5c753898d3fffa 100644 (file)
 #define PPC_STLCX      stringify_in_c(stdcx.)
 #define PPC_CNTLZL     stringify_in_c(cntlzd)
 
+/* Move to CR, single-entry optimized version. Only available
+ * on POWER4 and later.
+ */
+#ifdef CONFIG_POWER4_ONLY
+#define PPC_MTOCRF     stringify_in_c(mtocrf)
+#else
+#define PPC_MTOCRF     stringify_in_c(mtcrf)
+#endif
+
 #else /* 32-bit */
 
 /* operations for longs and pointers */
@@ -89,6 +98,7 @@
 #define PPC_LLARX      stringify_in_c(lwarx)
 #define PPC_STLCX      stringify_in_c(stwcx.)
 #define PPC_CNTLZL     stringify_in_c(cntlzw)
+#define PPC_MTOCRF     stringify_in_c(mtcrf)
 
 #endif
 
index 08e93e7892191d40793ea5e6f63ec43a035c65a8..ba667a383b8c8024df596df085cacf444b027db7 100644 (file)
@@ -64,6 +64,12 @@ extern void flush_dcache_phys_range(unsigned long start, unsigned long stop);
        memcpy(dst, src, len)
 
 
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+/* internal debugging function */
+void kernel_map_pages(struct page *page, int numpages, int enable);
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_POWERPC_CACHEFLUSH_H */
index 35b95773746c7c80c049ed9743a86ce3f6c06676..8066eede3a0c9d8bb7b0e63d7c64955ea8b5efa8 100644 (file)
@@ -97,11 +97,6 @@ extern void cbe_disable_pm_interrupts(u32 cpu);
 extern u32  cbe_get_and_clear_pm_interrupts(u32 cpu);
 extern void cbe_sync_irq(int node);
 
-/* Utility functions, macros */
-extern u32 cbe_get_hw_thread_id(int cpu);
-
-#define cbe_cpu_to_node(cpu) ((cpu) >> 1)
-
 #define CBE_COUNT_SUPERVISOR_MODE       0
 #define CBE_COUNT_HYPERVISOR_MODE       1
 #define CBE_COUNT_PROBLEM_MODE          2
index e870b5393175d310ff45858c2530f09d6423812d..434524931ef377e30046e0647f595abfb76a4378 100644 (file)
@@ -48,6 +48,7 @@ enum powerpc_oprofile_type {
        PPC_OPROFILE_G4 = 3,
        PPC_OPROFILE_BOOKE = 4,
        PPC_OPROFILE_CELL = 5,
+       PPC_OPROFILE_PA6T = 6,
 };
 
 enum powerpc_pmc_type {
@@ -223,6 +224,10 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
            CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
            CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
            CPU_FTR_PPC_LE)
+#define CPU_FTRS_750CL (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+           CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+           CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+           CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
 #define CPU_FTRS_750FX1        (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
            CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
            CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
@@ -235,9 +240,9 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
            CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
            CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
            CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
-#define CPU_FTRS_750GX (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
-           CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | \
-           CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+#define CPU_FTRS_750GX (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+           CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+           CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
            CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
 #define CPU_FTRS_7400_NOTAU    (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
            CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
index b8708aedf925327c13e727d094ad6398b3156850..e2c7f06931e72dfb514b19ef1ff1028306e88891 100644 (file)
@@ -12,6 +12,7 @@
 struct task_struct;
 
 #ifdef __powerpc64__
+#include <linux/stddef.h>
 #include <asm/paca.h>
 
 static inline struct task_struct *get_current(void)
diff --git a/include/asm-powerpc/edac.h b/include/asm-powerpc/edac.h
new file mode 100644 (file)
index 0000000..6ead88b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * PPC EDAC common defs
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef ASM_EDAC_H
+#define ASM_EDAC_H
+/*
+ * ECC atomic, DMA, SMP and interrupt safe scrub function.
+ * Implements the per arch atomic_scrub() that EDAC use for software
+ * ECC scrubbing.  It reads memory and then writes back the original
+ * value, allowing the hardware to detect and correct memory errors.
+ */
+static __inline__ void atomic_scrub(void *va, u32 size)
+{
+       unsigned int *virt_addr = va;
+       unsigned int temp;
+       unsigned int i;
+
+       for (i = 0; i < size / sizeof(*virt_addr); i++, virt_addr++) {
+               /* Very carefully read and write to memory atomically
+                * so we are interrupt, DMA and SMP safe.
+                */
+               __asm__ __volatile__ ("\n\
+                               1:      lwarx   %0,0,%1\n\
+                                       stwcx.  %0,0,%1\n\
+                                       bne-    1b\n\
+                                       isync"
+                                       : "=&r"(temp)
+                                       : "r"(virt_addr)
+                                       : "cr0", "memory");
+       }
+}
+
+#endif
index dc6bf0ffb796afb25fe707c85c9147169742665f..cc3cb04539ac4972874000b01e95cd6f8e98ae6c 100644 (file)
@@ -30,8 +30,6 @@ struct eeh_event {
        struct list_head     list;
        struct device_node      *dn;   /* struct device node */
        struct pci_dev       *dev;  /* affected device */
-       enum pci_channel_state state; /* PCI bus state for the affected device */
-       int time_unavail;    /* milliseconds until device might be available */
 };
 
 /**
@@ -46,9 +44,7 @@ struct eeh_event {
  * (from a workqueue).
  */
 int eeh_send_failure_event (struct device_node *dn,
-                            struct pci_dev *dev,
-                            enum pci_channel_state state,
-                            int time_unavail);
+                            struct pci_dev *dev);
 
 /* Main recovery function */
 struct pci_dn * handle_eeh_events (struct eeh_event *);
index 66112114b8c588b066c1ade4bd9778cda00bdb3c..87d396e28db2f8c1dc359918e970f33c98a66777 100644 (file)
@@ -2,36 +2,37 @@
  * IBM PowerPC eBus Infrastructure Support.
  *
  * Copyright (c) 2005 IBM Corporation
+ *  Joachim Fenkes <fenkes@de.ibm.com>
  *  Heiko J Schick <schickhj@de.ibm.com>
- *    
+ *
  * All rights reserved.
  *
- * This source code is distributed under a dual license of GPL v2.0 and OpenIB 
- * BSD. 
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
  *
  * OpenIB BSD License
  *
- * Redistribution and use in source and binary forms, with or without 
- * modification, are permitted provided that the following conditions are met: 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
  *
- * Redistributions of source code must retain the above copyright notice, this 
- * list of conditions and the following disclaimer. 
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
  *
- * Redistributions in binary form must reproduce the above copyright notice, 
- * this list of conditions and the following disclaimer in the documentation 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
  * and/or other materials
- * provided with the distribution. 
+ * provided with the distribution.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
 
 extern struct bus_type ibmebus_bus_type;
 
-struct ibmebus_dev {   
-       const char *name;
+struct ibmebus_dev {
        struct of_device ofdev;
 };
 
-struct ibmebus_driver {        
+struct ibmebus_driver {
        char *name;
        struct of_device_id *id_table;
        int (*probe) (struct ibmebus_dev *dev, const struct of_device_id *id);
@@ -63,7 +63,7 @@ int ibmebus_register_driver(struct ibmebus_driver *drv);
 void ibmebus_unregister_driver(struct ibmebus_driver *drv);
 
 int ibmebus_request_irq(struct ibmebus_dev *dev,
-                       u32 ist, 
+                       u32 ist,
                        irq_handler_t handler,
                        unsigned long irq_flags, const char * devname,
                        void *dev_id);
index d905b6622268c99cf811727fa9a2654fd8d445c3..59b9e07b8e99fe85f81ebcc9583534477c112e62 100644 (file)
@@ -85,81 +85,6 @@ typedef struct ccsr_pci {
        char    res19[472];
 } ccsr_pci_t;
 
-/* PCI Express Registers */
-typedef struct ccsr_pex {
-       uint    pex_config_addr;        /* 0x.000 - PCI Express Configuration Address Register */
-       uint    pex_config_data;        /* 0x.004 - PCI Express Configuration Data Register */
-       char    res1[4];
-       uint    pex_otb_cpl_tor;        /* 0x.00c - PCI Express Outbound completion timeout register */
-       uint    pex_conf_tor;           /* 0x.010 - PCI Express configuration timeout register */
-       char    res2[12];
-       uint    pex_pme_mes_dr;         /* 0x.020 - PCI Express PME and message detect register */
-       uint    pex_pme_mes_disr;       /* 0x.024 - PCI Express PME and message disable register */
-       uint    pex_pme_mes_ier;        /* 0x.028 - PCI Express PME and message interrupt enable register */
-       uint    pex_pmcr;               /* 0x.02c - PCI Express power management command register */
-       char    res3[3024];
-       uint    pexotar0;               /* 0x.c00 - PCI Express outbound translation address register 0 */
-       uint    pexotear0;              /* 0x.c04 - PCI Express outbound translation extended address register 0*/
-       char    res4[8];
-       uint    pexowar0;               /* 0x.c10 - PCI Express outbound window attributes register 0*/
-       char    res5[12];
-       uint    pexotar1;               /* 0x.c20 - PCI Express outbound translation address register 1 */
-       uint    pexotear1;              /* 0x.c24 - PCI Express outbound translation extended address register 1*/
-       uint    pexowbar1;              /* 0x.c28 - PCI Express outbound window base address register 1*/
-       char    res6[4];
-       uint    pexowar1;               /* 0x.c30 - PCI Express outbound window attributes register 1*/
-       char    res7[12];
-       uint    pexotar2;               /* 0x.c40 - PCI Express outbound translation address register 2 */
-       uint    pexotear2;              /* 0x.c44 - PCI Express outbound translation extended address register 2*/
-       uint    pexowbar2;              /* 0x.c48 - PCI Express outbound window base address register 2*/
-       char    res8[4];
-       uint    pexowar2;               /* 0x.c50 - PCI Express outbound window attributes register 2*/
-       char    res9[12];
-       uint    pexotar3;               /* 0x.c60 - PCI Express outbound translation address register 3 */
-       uint    pexotear3;              /* 0x.c64 - PCI Express outbound translation extended address register 3*/
-       uint    pexowbar3;              /* 0x.c68 - PCI Express outbound window base address register 3*/
-       char    res10[4];
-       uint    pexowar3;               /* 0x.c70 - PCI Express outbound window attributes register 3*/
-       char    res11[12];
-       uint    pexotar4;               /* 0x.c80 - PCI Express outbound translation address register 4 */
-       uint    pexotear4;              /* 0x.c84 - PCI Express outbound translation extended address register 4*/
-       uint    pexowbar4;              /* 0x.c88 - PCI Express outbound window base address register 4*/
-       char    res12[4];
-       uint    pexowar4;               /* 0x.c90 - PCI Express outbound window attributes register 4*/
-       char    res13[12];
-       char    res14[256];
-       uint    pexitar3;               /* 0x.da0 - PCI Express inbound translation address register 3 */
-       char    res15[4];
-       uint    pexiwbar3;              /* 0x.da8 - PCI Express inbound window base address register 3 */
-       uint    pexiwbear3;             /* 0x.dac - PCI Express inbound window base extended address register 3 */
-       uint    pexiwar3;               /* 0x.db0 - PCI Express inbound window attributes register 3 */
-       char    res16[12];
-       uint    pexitar2;               /* 0x.dc0 - PCI Express inbound translation address register 2 */
-       char    res17[4];
-       uint    pexiwbar2;              /* 0x.dc8 - PCI Express inbound window base address register 2 */
-       uint    pexiwbear2;             /* 0x.dcc - PCI Express inbound window base extended address register 2 */
-       uint    pexiwar2;               /* 0x.dd0 - PCI Express inbound window attributes register 2 */
-       char    res18[12];
-       uint    pexitar1;               /* 0x.de0 - PCI Express inbound translation address register 2 */
-       char    res19[4];
-       uint    pexiwbar1;              /* 0x.de8 - PCI Express inbound window base address register 2 */
-       uint    pexiwbear1;             /* 0x.dec - PCI Express inbound window base extended address register 2 */
-       uint    pexiwar1;               /* 0x.df0 - PCI Express inbound window attributes register 2 */
-       char    res20[12];
-       uint    pex_err_dr;             /* 0x.e00 - PCI Express error detect register */
-       char    res21[4];
-       uint    pex_err_en;             /* 0x.e08 - PCI Express error interrupt enable register */
-       char    res22[4];
-       uint    pex_err_disr;           /* 0x.e10 - PCI Express error disable register */
-       char    res23[12];
-       uint    pex_err_cap_stat;       /* 0x.e20 - PCI Express error capture status register */
-       char    res24[4];
-       uint    pex_err_cap_r0;         /* 0x.e28 - PCI Express error capture register 0 */
-       uint    pex_err_cap_r1;         /* 0x.e2c - PCI Express error capture register 0 */
-       uint    pex_err_cap_r2;         /* 0x.e30 - PCI Express error capture register 0 */
-       uint    pex_err_cap_r3;         /* 0x.e34 - PCI Express error capture register 0 */
-} ccsr_pex_t;
-
 /* Global Utility Registers */
 typedef struct ccsr_guts {
        uint    porpllsr;       /* 0x.0000 - POR PLL Ratio Status Register */
index 301c9bb308b18c858cd3129089ac541ee8084e02..350c9bdb31dccc7007c1f0bfa7bc72d569b55754 100644 (file)
 
 /* Check of existence of legacy devices */
 extern int check_legacy_ioport(unsigned long base_port);
-#define PNPBIOS_BASE   0xf000  /* only relevant for PReP */
+#define I8042_DATA_REG 0x60
+#define FDC_BASE       0x3f0
+/* only relevant for PReP */
+#define _PIDXR         0x279
+#define _PNPWRP                0xa79
+#define PNPBIOS_BASE   0xf000
 
 #include <linux/compiler.h>
 #include <asm/page.h>
index 3a5dd492588fed5560206c2e850825e79ce3ab64..f850ca7020ed4becd50d98a85742f536d7a94805 100644 (file)
@@ -87,6 +87,11 @@ extern void arch_remove_kprobe(struct kprobe *p);
 struct arch_specific_insn {
        /* copy of original instruction */
        kprobe_opcode_t *insn;
+       /*
+        * Set in kprobes code, initially to 0. If the instruction can be
+        * eumulated, this is set to 1, if not, to -1.
+        */
+       int boostable;
 };
 
 struct prev_kprobe {
index 1b04e57235482ae59f276c89a9bbc6e0baa1ef4b..b204926ce91348a296618c8e350ce0f292136246 100644 (file)
@@ -153,9 +153,6 @@ struct machdep_calls {
         */
        long            (*feature_call)(unsigned int feature, ...);
 
-       /* Check availability of legacy devices like i8042 */
-       int             (*check_legacy_ioport)(unsigned int baseport);
-
        /* Get legacy PCI/IDE interrupt mapping */ 
        int             (*pci_get_legacy_ide_irq)(struct pci_dev *dev, int channel);
        
diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h
new file mode 100644 (file)
index 0000000..6739457
--- /dev/null
@@ -0,0 +1,400 @@
+#ifndef _ASM_POWERPC_MMU_HASH64_H_
+#define _ASM_POWERPC_MMU_HASH64_H_
+/*
+ * PowerPC64 memory management structures
+ *
+ * Dave Engebretsen & Mike Corrigan <{engebret|mikejc}@us.ibm.com>
+ *   PPC64 rework.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/asm-compat.h>
+#include <asm/page.h>
+
+/*
+ * Segment table
+ */
+
+#define STE_ESID_V     0x80
+#define STE_ESID_KS    0x20
+#define STE_ESID_KP    0x10
+#define STE_ESID_N     0x08
+
+#define STE_VSID_SHIFT 12
+
+/* Location of cpu0's segment table */
+#define STAB0_PAGE     0x6
+#define STAB0_OFFSET   (STAB0_PAGE << 12)
+#define STAB0_PHYS_ADDR        (STAB0_OFFSET + PHYSICAL_START)
+
+#ifndef __ASSEMBLY__
+extern char initial_stab[];
+#endif /* ! __ASSEMBLY */
+
+/*
+ * SLB
+ */
+
+#define SLB_NUM_BOLTED         3
+#define SLB_CACHE_ENTRIES      8
+
+/* Bits in the SLB ESID word */
+#define SLB_ESID_V             ASM_CONST(0x0000000008000000) /* valid */
+
+/* Bits in the SLB VSID word */
+#define SLB_VSID_SHIFT         12
+#define SLB_VSID_B             ASM_CONST(0xc000000000000000)
+#define SLB_VSID_B_256M                ASM_CONST(0x0000000000000000)
+#define SLB_VSID_B_1T          ASM_CONST(0x4000000000000000)
+#define SLB_VSID_KS            ASM_CONST(0x0000000000000800)
+#define SLB_VSID_KP            ASM_CONST(0x0000000000000400)
+#define SLB_VSID_N             ASM_CONST(0x0000000000000200) /* no-execute */
+#define SLB_VSID_L             ASM_CONST(0x0000000000000100)
+#define SLB_VSID_C             ASM_CONST(0x0000000000000080) /* class */
+#define SLB_VSID_LP            ASM_CONST(0x0000000000000030)
+#define SLB_VSID_LP_00         ASM_CONST(0x0000000000000000)
+#define SLB_VSID_LP_01         ASM_CONST(0x0000000000000010)
+#define SLB_VSID_LP_10         ASM_CONST(0x0000000000000020)
+#define SLB_VSID_LP_11         ASM_CONST(0x0000000000000030)
+#define SLB_VSID_LLP           (SLB_VSID_L|SLB_VSID_LP)
+
+#define SLB_VSID_KERNEL                (SLB_VSID_KP)
+#define SLB_VSID_USER          (SLB_VSID_KP|SLB_VSID_KS|SLB_VSID_C)
+
+#define SLBIE_C                        (0x08000000)
+
+/*
+ * Hash table
+ */
+
+#define HPTES_PER_GROUP 8
+
+#define HPTE_V_AVPN_SHIFT      7
+#define HPTE_V_AVPN            ASM_CONST(0xffffffffffffff80)
+#define HPTE_V_AVPN_VAL(x)     (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
+#define HPTE_V_COMPARE(x,y)    (!(((x) ^ (y)) & HPTE_V_AVPN))
+#define HPTE_V_BOLTED          ASM_CONST(0x0000000000000010)
+#define HPTE_V_LOCK            ASM_CONST(0x0000000000000008)
+#define HPTE_V_LARGE           ASM_CONST(0x0000000000000004)
+#define HPTE_V_SECONDARY       ASM_CONST(0x0000000000000002)
+#define HPTE_V_VALID           ASM_CONST(0x0000000000000001)
+
+#define HPTE_R_PP0             ASM_CONST(0x8000000000000000)
+#define HPTE_R_TS              ASM_CONST(0x4000000000000000)
+#define HPTE_R_RPN_SHIFT       12
+#define HPTE_R_RPN             ASM_CONST(0x3ffffffffffff000)
+#define HPTE_R_FLAGS           ASM_CONST(0x00000000000003ff)
+#define HPTE_R_PP              ASM_CONST(0x0000000000000003)
+#define HPTE_R_N               ASM_CONST(0x0000000000000004)
+#define HPTE_R_C               ASM_CONST(0x0000000000000080)
+#define HPTE_R_R               ASM_CONST(0x0000000000000100)
+
+/* Values for PP (assumes Ks=0, Kp=1) */
+/* pp0 will always be 0 for linux     */
+#define PP_RWXX        0       /* Supervisor read/write, User none */
+#define PP_RWRX 1      /* Supervisor read/write, User read */
+#define PP_RWRW 2      /* Supervisor read/write, User read/write */
+#define PP_RXRX 3      /* Supervisor read,       User read */
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+       unsigned long v;
+       unsigned long r;
+} hpte_t;
+
+extern hpte_t *htab_address;
+extern unsigned long htab_size_bytes;
+extern unsigned long htab_hash_mask;
+
+/*
+ * Page size definition
+ *
+ *    shift : is the "PAGE_SHIFT" value for that page size
+ *    sllp  : is a bit mask with the value of SLB L || LP to be or'ed
+ *            directly to a slbmte "vsid" value
+ *    penc  : is the HPTE encoding mask for the "LP" field:
+ *
+ */
+struct mmu_psize_def
+{
+       unsigned int    shift;  /* number of bits */
+       unsigned int    penc;   /* HPTE encoding */
+       unsigned int    tlbiel; /* tlbiel supported for that page size */
+       unsigned long   avpnm;  /* bits to mask out in AVPN in the HPTE */
+       unsigned long   sllp;   /* SLB L||LP (exact mask to use in slbmte) */
+};
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * The kernel use the constants below to index in the page sizes array.
+ * The use of fixed constants for this purpose is better for performances
+ * of the low level hash refill handlers.
+ *
+ * A non supported page size has a "shift" field set to 0
+ *
+ * Any new page size being implemented can get a new entry in here. Whether
+ * the kernel will use it or not is a different matter though. The actual page
+ * size used by hugetlbfs is not defined here and may be made variable
+ */
+
+#define MMU_PAGE_4K            0       /* 4K */
+#define MMU_PAGE_64K           1       /* 64K */
+#define MMU_PAGE_64K_AP                2       /* 64K Admixed (in a 4K segment) */
+#define MMU_PAGE_1M            3       /* 1M */
+#define MMU_PAGE_16M           4       /* 16M */
+#define MMU_PAGE_16G           5       /* 16G */
+#define MMU_PAGE_COUNT         6
+
+#ifndef __ASSEMBLY__
+
+/*
+ * The current system page sizes
+ */
+extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
+extern int mmu_linear_psize;
+extern int mmu_virtual_psize;
+extern int mmu_vmalloc_psize;
+extern int mmu_io_psize;
+
+/*
+ * If the processor supports 64k normal pages but not 64k cache
+ * inhibited pages, we have to be prepared to switch processes
+ * to use 4k pages when they create cache-inhibited mappings.
+ * If this is the case, mmu_ci_restrictions will be set to 1.
+ */
+extern int mmu_ci_restrictions;
+
+#ifdef CONFIG_HUGETLB_PAGE
+/*
+ * The page size index of the huge pages for use by hugetlbfs
+ */
+extern int mmu_huge_psize;
+
+#endif /* CONFIG_HUGETLB_PAGE */
+
+/*
+ * This function sets the AVPN and L fields of the HPTE  appropriately
+ * for the page size
+ */
+static inline unsigned long hpte_encode_v(unsigned long va, int psize)
+{
+       unsigned long v =
+       v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm);
+       v <<= HPTE_V_AVPN_SHIFT;
+       if (psize != MMU_PAGE_4K)
+               v |= HPTE_V_LARGE;
+       return v;
+}
+
+/*
+ * This function sets the ARPN, and LP fields of the HPTE appropriately
+ * for the page size. We assume the pa is already "clean" that is properly
+ * aligned for the requested page size
+ */
+static inline unsigned long hpte_encode_r(unsigned long pa, int psize)
+{
+       unsigned long r;
+
+       /* A 4K page needs no special encoding */
+       if (psize == MMU_PAGE_4K)
+               return pa & HPTE_R_RPN;
+       else {
+               unsigned int penc = mmu_psize_defs[psize].penc;
+               unsigned int shift = mmu_psize_defs[psize].shift;
+               return (pa & ~((1ul << shift) - 1)) | (penc << 12);
+       }
+       return r;
+}
+
+/*
+ * This hashes a virtual address for a 256Mb segment only for now
+ */
+
+static inline unsigned long hpt_hash(unsigned long va, unsigned int shift)
+{
+       return ((va >> 28) & 0x7fffffffffUL) ^ ((va & 0x0fffffffUL) >> shift);
+}
+
+extern int __hash_page_4K(unsigned long ea, unsigned long access,
+                         unsigned long vsid, pte_t *ptep, unsigned long trap,
+                         unsigned int local);
+extern int __hash_page_64K(unsigned long ea, unsigned long access,
+                          unsigned long vsid, pte_t *ptep, unsigned long trap,
+                          unsigned int local);
+struct mm_struct;
+extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap);
+extern int hash_huge_page(struct mm_struct *mm, unsigned long access,
+                         unsigned long ea, unsigned long vsid, int local,
+                         unsigned long trap);
+
+extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
+                            unsigned long pstart, unsigned long mode,
+                            int psize);
+
+extern void htab_initialize(void);
+extern void htab_initialize_secondary(void);
+extern void hpte_init_native(void);
+extern void hpte_init_lpar(void);
+extern void hpte_init_iSeries(void);
+extern void hpte_init_beat(void);
+
+extern void stabs_alloc(void);
+extern void slb_initialize(void);
+extern void slb_flush_and_rebolt(void);
+extern void stab_initialize(unsigned long stab);
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * VSID allocation
+ *
+ * We first generate a 36-bit "proto-VSID".  For kernel addresses this
+ * is equal to the ESID, for user addresses it is:
+ *     (context << 15) | (esid & 0x7fff)
+ *
+ * The two forms are distinguishable because the top bit is 0 for user
+ * addresses, whereas the top two bits are 1 for kernel addresses.
+ * Proto-VSIDs with the top two bits equal to 0b10 are reserved for
+ * now.
+ *
+ * The proto-VSIDs are then scrambled into real VSIDs with the
+ * multiplicative hash:
+ *
+ *     VSID = (proto-VSID * VSID_MULTIPLIER) % VSID_MODULUS
+ *     where   VSID_MULTIPLIER = 268435399 = 0xFFFFFC7
+ *             VSID_MODULUS = 2^36-1 = 0xFFFFFFFFF
+ *
+ * This scramble is only well defined for proto-VSIDs below
+ * 0xFFFFFFFFF, so both proto-VSID and actual VSID 0xFFFFFFFFF are
+ * reserved.  VSID_MULTIPLIER is prime, so in particular it is
+ * co-prime to VSID_MODULUS, making this a 1:1 scrambling function.
+ * Because the modulus is 2^n-1 we can compute it efficiently without
+ * a divide or extra multiply (see below).
+ *
+ * This scheme has several advantages over older methods:
+ *
+ *     - We have VSIDs allocated for every kernel address
+ * (i.e. everything above 0xC000000000000000), except the very top
+ * segment, which simplifies several things.
+ *
+ *     - We allow for 15 significant bits of ESID and 20 bits of
+ * context for user addresses.  i.e. 8T (43 bits) of address space for
+ * up to 1M contexts (although the page table structure and context
+ * allocation will need changes to take advantage of this).
+ *
+ *     - The scramble function gives robust scattering in the hash
+ * table (at least based on some initial results).  The previous
+ * method was more susceptible to pathological cases giving excessive
+ * hash collisions.
+ */
+/*
+ * WARNING - If you change these you must make sure the asm
+ * implementations in slb_allocate (slb_low.S), do_stab_bolted
+ * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
+ *
+ * You'll also need to change the precomputed VSID values in head.S
+ * which are used by the iSeries firmware.
+ */
+
+#define VSID_MULTIPLIER        ASM_CONST(200730139)    /* 28-bit prime */
+#define VSID_BITS      36
+#define VSID_MODULUS   ((1UL<<VSID_BITS)-1)
+
+#define CONTEXT_BITS   19
+#define USER_ESID_BITS 16
+
+#define USER_VSID_RANGE        (1UL << (USER_ESID_BITS + SID_SHIFT))
+
+/*
+ * This macro generates asm code to compute the VSID scramble
+ * function.  Used in slb_allocate() and do_stab_bolted.  The function
+ * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS
+ *
+ *     rt = register continaing the proto-VSID and into which the
+ *             VSID will be stored
+ *     rx = scratch register (clobbered)
+ *
+ *     - rt and rx must be different registers
+ *     - The answer will end up in the low 36 bits of rt.  The higher
+ *       bits may contain other garbage, so you may need to mask the
+ *       result.
+ */
+#define ASM_VSID_SCRAMBLE(rt, rx)      \
+       lis     rx,VSID_MULTIPLIER@h;                                   \
+       ori     rx,rx,VSID_MULTIPLIER@l;                                \
+       mulld   rt,rt,rx;               /* rt = rt * MULTIPLIER */      \
+                                                                       \
+       srdi    rx,rt,VSID_BITS;                                        \
+       clrldi  rt,rt,(64-VSID_BITS);                                   \
+       add     rt,rt,rx;               /* add high and low bits */     \
+       /* Now, r3 == VSID (mod 2^36-1), and lies between 0 and         \
+        * 2^36-1+2^28-1.  That in particular means that if r3 >=       \
+        * 2^36-1, then r3+1 has the 2^36 bit set.  So, if r3+1 has     \
+        * the bit clear, r3 already has the answer we want, if it      \
+        * doesn't, the answer is the low 36 bits of r3+1.  So in all   \
+        * cases the answer is the low 36 bits of (r3 + ((r3+1) >> 36))*/\
+       addi    rx,rt,1;                                                \
+       srdi    rx,rx,VSID_BITS;        /* extract 2^36 bit */          \
+       add     rt,rt,rx
+
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned long mm_context_id_t;
+
+typedef struct {
+       mm_context_id_t id;
+       u16 user_psize;                 /* page size index */
+       u16 sllp;                       /* SLB entry page size encoding */
+#ifdef CONFIG_HUGETLB_PAGE
+       u16 low_htlb_areas, high_htlb_areas;
+#endif
+       unsigned long vdso_base;
+} mm_context_t;
+
+
+static inline unsigned long vsid_scramble(unsigned long protovsid)
+{
+#if 0
+       /* The code below is equivalent to this function for arguments
+        * < 2^VSID_BITS, which is all this should ever be called
+        * with.  However gcc is not clever enough to compute the
+        * modulus (2^n-1) without a second multiply. */
+       return ((protovsid * VSID_MULTIPLIER) % VSID_MODULUS);
+#else /* 1 */
+       unsigned long x;
+
+       x = protovsid * VSID_MULTIPLIER;
+       x = (x >> VSID_BITS) + (x & VSID_MODULUS);
+       return (x + ((x+1) >> VSID_BITS)) & VSID_MODULUS;
+#endif /* 1 */
+}
+
+/* This is only valid for addresses >= KERNELBASE */
+static inline unsigned long get_kernel_vsid(unsigned long ea)
+{
+       return vsid_scramble(ea >> SID_SHIFT);
+}
+
+/* This is only valid for user addresses (which are below 2^41) */
+static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
+{
+       return vsid_scramble((context << USER_ESID_BITS)
+                            | (ea >> SID_SHIFT));
+}
+
+#define VSID_SCRAMBLE(pvsid)   (((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS)
+#define KERNEL_VSID(ea)                VSID_SCRAMBLE(GET_ESID(ea))
+
+/* Physical address used by some IO functions */
+typedef unsigned long phys_addr_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_MMU_HASH64_H_ */
index 200055a4b82b5d983504e22df1de7550a3b104eb..06b3e6d336cbad8a72732bb34836dc3edda8152b 100644 (file)
 #define _ASM_POWERPC_MMU_H_
 #ifdef __KERNEL__
 
-#ifndef CONFIG_PPC64
-#include <asm-ppc/mmu.h>
+#ifdef CONFIG_PPC64
+/* 64-bit classic hash table MMU */
+#  include <asm/mmu-hash64.h>
 #else
-
-/*
- * PowerPC memory management structures
- *
- * Dave Engebretsen & Mike Corrigan <{engebret|mikejc}@us.ibm.com>
- *   PPC64 rework.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/asm-compat.h>
-#include <asm/page.h>
-
-/*
- * Segment table
- */
-
-#define STE_ESID_V     0x80
-#define STE_ESID_KS    0x20
-#define STE_ESID_KP    0x10
-#define STE_ESID_N     0x08
-
-#define STE_VSID_SHIFT 12
-
-/* Location of cpu0's segment table */
-#define STAB0_PAGE     0x6
-#define STAB0_OFFSET   (STAB0_PAGE << 12)
-#define STAB0_PHYS_ADDR        (STAB0_OFFSET + PHYSICAL_START)
-
-#ifndef __ASSEMBLY__
-extern char initial_stab[];
-#endif /* ! __ASSEMBLY */
-
-/*
- * SLB
- */
-
-#define SLB_NUM_BOLTED         3
-#define SLB_CACHE_ENTRIES      8
-
-/* Bits in the SLB ESID word */
-#define SLB_ESID_V             ASM_CONST(0x0000000008000000) /* valid */
-
-/* Bits in the SLB VSID word */
-#define SLB_VSID_SHIFT         12
-#define SLB_VSID_B             ASM_CONST(0xc000000000000000)
-#define SLB_VSID_B_256M                ASM_CONST(0x0000000000000000)
-#define SLB_VSID_B_1T          ASM_CONST(0x4000000000000000)
-#define SLB_VSID_KS            ASM_CONST(0x0000000000000800)
-#define SLB_VSID_KP            ASM_CONST(0x0000000000000400)
-#define SLB_VSID_N             ASM_CONST(0x0000000000000200) /* no-execute */
-#define SLB_VSID_L             ASM_CONST(0x0000000000000100)
-#define SLB_VSID_C             ASM_CONST(0x0000000000000080) /* class */
-#define SLB_VSID_LP            ASM_CONST(0x0000000000000030)
-#define SLB_VSID_LP_00         ASM_CONST(0x0000000000000000)
-#define SLB_VSID_LP_01         ASM_CONST(0x0000000000000010)
-#define SLB_VSID_LP_10         ASM_CONST(0x0000000000000020)
-#define SLB_VSID_LP_11         ASM_CONST(0x0000000000000030)
-#define SLB_VSID_LLP           (SLB_VSID_L|SLB_VSID_LP)
-
-#define SLB_VSID_KERNEL                (SLB_VSID_KP)
-#define SLB_VSID_USER          (SLB_VSID_KP|SLB_VSID_KS|SLB_VSID_C)
-
-#define SLBIE_C                        (0x08000000)
-
-/*
- * Hash table
- */
-
-#define HPTES_PER_GROUP 8
-
-#define HPTE_V_AVPN_SHIFT      7
-#define HPTE_V_AVPN            ASM_CONST(0xffffffffffffff80)
-#define HPTE_V_AVPN_VAL(x)     (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
-#define HPTE_V_COMPARE(x,y)    (!(((x) ^ (y)) & HPTE_V_AVPN))
-#define HPTE_V_BOLTED          ASM_CONST(0x0000000000000010)
-#define HPTE_V_LOCK            ASM_CONST(0x0000000000000008)
-#define HPTE_V_LARGE           ASM_CONST(0x0000000000000004)
-#define HPTE_V_SECONDARY       ASM_CONST(0x0000000000000002)
-#define HPTE_V_VALID           ASM_CONST(0x0000000000000001)
-
-#define HPTE_R_PP0             ASM_CONST(0x8000000000000000)
-#define HPTE_R_TS              ASM_CONST(0x4000000000000000)
-#define HPTE_R_RPN_SHIFT       12
-#define HPTE_R_RPN             ASM_CONST(0x3ffffffffffff000)
-#define HPTE_R_FLAGS           ASM_CONST(0x00000000000003ff)
-#define HPTE_R_PP              ASM_CONST(0x0000000000000003)
-#define HPTE_R_N               ASM_CONST(0x0000000000000004)
-#define HPTE_R_C               ASM_CONST(0x0000000000000080)
-#define HPTE_R_R               ASM_CONST(0x0000000000000100)
-
-/* Values for PP (assumes Ks=0, Kp=1) */
-/* pp0 will always be 0 for linux     */
-#define PP_RWXX        0       /* Supervisor read/write, User none */
-#define PP_RWRX 1      /* Supervisor read/write, User read */
-#define PP_RWRW 2      /* Supervisor read/write, User read/write */
-#define PP_RXRX 3      /* Supervisor read,       User read */
-
-#ifndef __ASSEMBLY__
-
-typedef struct {
-       unsigned long v;
-       unsigned long r;
-} hpte_t;
-
-extern hpte_t *htab_address;
-extern unsigned long htab_size_bytes;
-extern unsigned long htab_hash_mask;
-
-/*
- * Page size definition
- *
- *    shift : is the "PAGE_SHIFT" value for that page size
- *    sllp  : is a bit mask with the value of SLB L || LP to be or'ed
- *            directly to a slbmte "vsid" value
- *    penc  : is the HPTE encoding mask for the "LP" field:
- *
- */
-struct mmu_psize_def
-{
-       unsigned int    shift;  /* number of bits */
-       unsigned int    penc;   /* HPTE encoding */
-       unsigned int    tlbiel; /* tlbiel supported for that page size */
-       unsigned long   avpnm;  /* bits to mask out in AVPN in the HPTE */
-       unsigned long   sllp;   /* SLB L||LP (exact mask to use in slbmte) */
-};
-
-#endif /* __ASSEMBLY__ */
-
-/*
- * The kernel use the constants below to index in the page sizes array.
- * The use of fixed constants for this purpose is better for performances
- * of the low level hash refill handlers.
- *
- * A non supported page size has a "shift" field set to 0
- *
- * Any new page size being implemented can get a new entry in here. Whether
- * the kernel will use it or not is a different matter though. The actual page
- * size used by hugetlbfs is not defined here and may be made variable
- */
-
-#define MMU_PAGE_4K            0       /* 4K */
-#define MMU_PAGE_64K           1       /* 64K */
-#define MMU_PAGE_64K_AP                2       /* 64K Admixed (in a 4K segment) */
-#define MMU_PAGE_1M            3       /* 1M */
-#define MMU_PAGE_16M           4       /* 16M */
-#define MMU_PAGE_16G           5       /* 16G */
-#define MMU_PAGE_COUNT         6
-
-#ifndef __ASSEMBLY__
-
-/*
- * The current system page sizes
- */
-extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
-extern int mmu_linear_psize;
-extern int mmu_virtual_psize;
-extern int mmu_vmalloc_psize;
-extern int mmu_io_psize;
-
-/*
- * If the processor supports 64k normal pages but not 64k cache
- * inhibited pages, we have to be prepared to switch processes
- * to use 4k pages when they create cache-inhibited mappings.
- * If this is the case, mmu_ci_restrictions will be set to 1.
- */
-extern int mmu_ci_restrictions;
-
-#ifdef CONFIG_HUGETLB_PAGE
-/*
- * The page size index of the huge pages for use by hugetlbfs
- */
-extern int mmu_huge_psize;
-
-#endif /* CONFIG_HUGETLB_PAGE */
-
-/*
- * This function sets the AVPN and L fields of the HPTE  appropriately
- * for the page size
- */
-static inline unsigned long hpte_encode_v(unsigned long va, int psize)
-{
-       unsigned long v =
-       v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm);
-       v <<= HPTE_V_AVPN_SHIFT;
-       if (psize != MMU_PAGE_4K)
-               v |= HPTE_V_LARGE;
-       return v;
-}
-
-/*
- * This function sets the ARPN, and LP fields of the HPTE appropriately
- * for the page size. We assume the pa is already "clean" that is properly
- * aligned for the requested page size
- */
-static inline unsigned long hpte_encode_r(unsigned long pa, int psize)
-{
-       unsigned long r;
-
-       /* A 4K page needs no special encoding */
-       if (psize == MMU_PAGE_4K)
-               return pa & HPTE_R_RPN;
-       else {
-               unsigned int penc = mmu_psize_defs[psize].penc;
-               unsigned int shift = mmu_psize_defs[psize].shift;
-               return (pa & ~((1ul << shift) - 1)) | (penc << 12);
-       }
-       return r;
-}
-
-/*
- * This hashes a virtual address for a 256Mb segment only for now
- */
-
-static inline unsigned long hpt_hash(unsigned long va, unsigned int shift)
-{
-       return ((va >> 28) & 0x7fffffffffUL) ^ ((va & 0x0fffffffUL) >> shift);
-}
-
-extern int __hash_page_4K(unsigned long ea, unsigned long access,
-                         unsigned long vsid, pte_t *ptep, unsigned long trap,
-                         unsigned int local);
-extern int __hash_page_64K(unsigned long ea, unsigned long access,
-                          unsigned long vsid, pte_t *ptep, unsigned long trap,
-                          unsigned int local);
-struct mm_struct;
-extern int hash_huge_page(struct mm_struct *mm, unsigned long access,
-                         unsigned long ea, unsigned long vsid, int local,
-                         unsigned long trap);
-
-extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
-                            unsigned long pstart, unsigned long mode,
-                            int psize);
-
-extern void htab_initialize(void);
-extern void htab_initialize_secondary(void);
-extern void hpte_init_native(void);
-extern void hpte_init_lpar(void);
-extern void hpte_init_iSeries(void);
-extern void hpte_init_beat(void);
-
-extern void stabs_alloc(void);
-extern void slb_initialize(void);
-extern void slb_flush_and_rebolt(void);
-extern void stab_initialize(unsigned long stab);
-
-#endif /* __ASSEMBLY__ */
-
-/*
- * VSID allocation
- *
- * We first generate a 36-bit "proto-VSID".  For kernel addresses this
- * is equal to the ESID, for user addresses it is:
- *     (context << 15) | (esid & 0x7fff)
- *
- * The two forms are distinguishable because the top bit is 0 for user
- * addresses, whereas the top two bits are 1 for kernel addresses.
- * Proto-VSIDs with the top two bits equal to 0b10 are reserved for
- * now.
- *
- * The proto-VSIDs are then scrambled into real VSIDs with the
- * multiplicative hash:
- *
- *     VSID = (proto-VSID * VSID_MULTIPLIER) % VSID_MODULUS
- *     where   VSID_MULTIPLIER = 268435399 = 0xFFFFFC7
- *             VSID_MODULUS = 2^36-1 = 0xFFFFFFFFF
- *
- * This scramble is only well defined for proto-VSIDs below
- * 0xFFFFFFFFF, so both proto-VSID and actual VSID 0xFFFFFFFFF are
- * reserved.  VSID_MULTIPLIER is prime, so in particular it is
- * co-prime to VSID_MODULUS, making this a 1:1 scrambling function.
- * Because the modulus is 2^n-1 we can compute it efficiently without
- * a divide or extra multiply (see below).
- *
- * This scheme has several advantages over older methods:
- *
- *     - We have VSIDs allocated for every kernel address
- * (i.e. everything above 0xC000000000000000), except the very top
- * segment, which simplifies several things.
- *
- *     - We allow for 15 significant bits of ESID and 20 bits of
- * context for user addresses.  i.e. 8T (43 bits) of address space for
- * up to 1M contexts (although the page table structure and context
- * allocation will need changes to take advantage of this).
- *
- *     - The scramble function gives robust scattering in the hash
- * table (at least based on some initial results).  The previous
- * method was more susceptible to pathological cases giving excessive
- * hash collisions.
- */
-/*
- * WARNING - If you change these you must make sure the asm
- * implementations in slb_allocate (slb_low.S), do_stab_bolted
- * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
- *
- * You'll also need to change the precomputed VSID values in head.S
- * which are used by the iSeries firmware.
- */
-
-#define VSID_MULTIPLIER        ASM_CONST(200730139)    /* 28-bit prime */
-#define VSID_BITS      36
-#define VSID_MODULUS   ((1UL<<VSID_BITS)-1)
-
-#define CONTEXT_BITS   19
-#define USER_ESID_BITS 16
-
-#define USER_VSID_RANGE        (1UL << (USER_ESID_BITS + SID_SHIFT))
-
-/*
- * This macro generates asm code to compute the VSID scramble
- * function.  Used in slb_allocate() and do_stab_bolted.  The function
- * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS
- *
- *     rt = register continaing the proto-VSID and into which the
- *             VSID will be stored
- *     rx = scratch register (clobbered)
- *
- *     - rt and rx must be different registers
- *     - The answer will end up in the low 36 bits of rt.  The higher
- *       bits may contain other garbage, so you may need to mask the
- *       result.
- */
-#define ASM_VSID_SCRAMBLE(rt, rx)      \
-       lis     rx,VSID_MULTIPLIER@h;                                   \
-       ori     rx,rx,VSID_MULTIPLIER@l;                                \
-       mulld   rt,rt,rx;               /* rt = rt * MULTIPLIER */      \
-                                                                       \
-       srdi    rx,rt,VSID_BITS;                                        \
-       clrldi  rt,rt,(64-VSID_BITS);                                   \
-       add     rt,rt,rx;               /* add high and low bits */     \
-       /* Now, r3 == VSID (mod 2^36-1), and lies between 0 and         \
-        * 2^36-1+2^28-1.  That in particular means that if r3 >=       \
-        * 2^36-1, then r3+1 has the 2^36 bit set.  So, if r3+1 has     \
-        * the bit clear, r3 already has the answer we want, if it      \
-        * doesn't, the answer is the low 36 bits of r3+1.  So in all   \
-        * cases the answer is the low 36 bits of (r3 + ((r3+1) >> 36))*/\
-       addi    rx,rt,1;                                                \
-       srdi    rx,rx,VSID_BITS;        /* extract 2^36 bit */          \
-       add     rt,rt,rx
-
-
-#ifndef __ASSEMBLY__
-
-typedef unsigned long mm_context_id_t;
-
-typedef struct {
-       mm_context_id_t id;
-       u16 user_psize;                 /* page size index */
-       u16 sllp;                       /* SLB entry page size encoding */
-#ifdef CONFIG_HUGETLB_PAGE
-       u16 low_htlb_areas, high_htlb_areas;
+/* 32-bit.  FIXME: split up the 32-bit MMU types, and revise for
+ * arch/powerpc */
+#  include <asm-ppc/mmu.h>
 #endif
-       unsigned long vdso_base;
-} mm_context_t;
-
-
-static inline unsigned long vsid_scramble(unsigned long protovsid)
-{
-#if 0
-       /* The code below is equivalent to this function for arguments
-        * < 2^VSID_BITS, which is all this should ever be called
-        * with.  However gcc is not clever enough to compute the
-        * modulus (2^n-1) without a second multiply. */
-       return ((protovsid * VSID_MULTIPLIER) % VSID_MODULUS);
-#else /* 1 */
-       unsigned long x;
-
-       x = protovsid * VSID_MULTIPLIER;
-       x = (x >> VSID_BITS) + (x & VSID_MODULUS);
-       return (x + ((x+1) >> VSID_BITS)) & VSID_MODULUS;
-#endif /* 1 */
-}
-
-/* This is only valid for addresses >= KERNELBASE */
-static inline unsigned long get_kernel_vsid(unsigned long ea)
-{
-       return vsid_scramble(ea >> SID_SHIFT);
-}
-
-/* This is only valid for user addresses (which are below 2^41) */
-static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
-{
-       return vsid_scramble((context << USER_ESID_BITS)
-                            | (ea >> SID_SHIFT));
-}
-
-#define VSID_SCRAMBLE(pvsid)   (((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS)
-#define KERNEL_VSID(ea)                VSID_SCRAMBLE(GET_ESID(ea))
-
-/* Physical address used by some IO functions */
-typedef unsigned long phys_addr_t;
-
-
-#endif /* __ASSEMBLY */
 
-#endif /* CONFIG_PPC64 */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MMU_H_ */
index cb204a71e91233acc47812847ea1c17a3452e531..e4d5fc5362a02e3389fc75f3d5fd9710fc0488ea 100644 (file)
@@ -199,7 +199,7 @@ enum {
 };
 
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 /* Fixup table entry */
 struct mpic_irq_fixup
 {
@@ -208,7 +208,7 @@ struct mpic_irq_fixup
        u32             data;
        unsigned int    index;
 };
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 
 enum mpic_reg_type {
@@ -239,7 +239,7 @@ struct mpic
 
        /* The "linux" controller struct */
        struct irq_chip         hc_irq;
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
        struct irq_chip         hc_ht_irq;
 #endif
 #ifdef CONFIG_SMP
@@ -268,7 +268,7 @@ struct mpic
        /* Spurious vector to program into unused sources */
        unsigned int            spurious_vec;
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
        /* The fixup table */
        struct mpic_irq_fixup   *fixups;
        spinlock_t              fixup_lock;
@@ -313,7 +313,7 @@ struct mpic
 /* Set this for a big-endian MPIC */
 #define MPIC_BIG_ENDIAN                        0x00000002
 /* Broken U3 MPIC */
-#define MPIC_BROKEN_U3                 0x00000004
+#define MPIC_U3_HT_IRQS                        0x00000004
 /* Broken IPI registers (autodetected) */
 #define MPIC_BROKEN_IPI                        0x00000008
 /* MPIC wants a reset */
@@ -352,7 +352,7 @@ struct mpic
  * @senses_num: number of entries in the array
  *
  * Note about the sense array. If none is passed, all interrupts are
- * setup to be level negative unless MPIC_BROKEN_U3 is set in which
+ * setup to be level negative unless MPIC_U3_HT_IRQS is set in which
  * case they are edge positive (and the array is ignored anyway).
  * The values in the array start at the first source of the MPIC,
  * that is senses[0] correspond to linux irq "irq_offset".
index a889b2005bf558f66d702e4ba74f27ee1eede700..4f1aabe0ce7305cdfcb12f8c2d276894d929408d 100644 (file)
@@ -32,5 +32,8 @@ extern int of_device_register(struct of_device *ofdev);
 extern void of_device_unregister(struct of_device *ofdev);
 extern void of_release_dev(struct device *dev);
 
+extern int of_device_uevent(struct device *dev,
+       char **envp, int num_envp, char *buffer, int buffer_size);
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OF_DEVICE_H */
index 94c0ad2bff961d8bef27e44ca780d99649a01cb4..8d6b47f7b3007f014dafbc3a3c8278513c52db23 100644 (file)
@@ -57,6 +57,8 @@ extern struct op_powerpc_model op_model_rs64;
 extern struct op_powerpc_model op_model_power4;
 extern struct op_powerpc_model op_model_7450;
 extern struct op_powerpc_model op_model_cell;
+extern struct op_powerpc_model op_model_pa6t;
+
 
 /* All the classic PPC parts use these */
 static inline unsigned int classic_ctr_read(unsigned int i)
index 0d3adc09c847bdf20448a9539bfd0c2e8e6622ac..cf95274f735e43ea3e9120b9697e0b0be75177bf 100644 (file)
@@ -70,6 +70,7 @@ struct paca_struct {
        s16 hw_cpu_id;                  /* Physical processor number */
        u8 cpu_start;                   /* At startup, processor spins until */
                                        /* this becomes non-zero. */
+       struct slb_shadow *slb_shadow_ptr;
 
        /*
         * Now, starting in cacheline 2, the exception save areas
@@ -93,6 +94,7 @@ struct paca_struct {
        u64 stab_rr;                    /* stab/slb round-robin counter */
        u64 saved_r1;                   /* r1 save for RTAS calls */
        u64 saved_msr;                  /* MSR saved here by enter_rtas */
+       u16 trap_save;                  /* Used when bad stack is encountered */
        u8 soft_enabled;                /* irq soft-enable flag */
        u8 hard_enabled;                /* set if irqs are enabled in MSR */
        u8 io_sync;                     /* writel() needs spin_unlock sync */
@@ -101,8 +103,6 @@ struct paca_struct {
        u64 user_time;                  /* accumulated usermode TB ticks */
        u64 system_time;                /* accumulated system TB ticks */
        u64 startpurr;                  /* PURR/TB value snapshot */
-
-       struct slb_shadow *slb_shadow_ptr;
 };
 
 extern struct paca_struct paca[];
index 3fca21ddf546c4213f863bffa8cf7790d612e516..b37b81e3727848d66f76a4baa214575c7a187694 100644 (file)
@@ -20,18 +20,18 @@ extern struct parport *parport_pc_probe_port (unsigned long int base,
 static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
 {
        struct device_node *np;
-       u32 *prop;
+       const u32 *prop;
        u32 io1, io2;
        int propsize;
        int count = 0;
        for (np = NULL; (np = of_find_compatible_node(np,
                                                      "parallel",
                                                      "pnpPNP,400")) != NULL;) {
-               prop = (u32 *)get_property(np, "reg", &propsize);
+               prop = of_get_property(np, "reg", &propsize);
                if (!prop || propsize > 6*sizeof(u32))
                        continue;
                io1 = prop[1]; io2 = prop[2];
-               prop = (u32 *)get_property(np, "interrupts", NULL);
+               prop = of_get_property(np, "interrupts", NULL);
                if (!prop)
                        continue;
                if (parport_pc_probe_port(io1, io2, prop[0], autodma, NULL) != NULL)
index ac656ee6bb193215db3cc9a9c6353726f3963a0e..ce0f13e8eb141d6bc65aedd9aadd92a204d8c577 100644 (file)
@@ -70,19 +70,22 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
  */
 #define PCI_DISABLE_MWI
 
-extern struct dma_mapping_ops *pci_dma_ops;
+#ifdef CONFIG_PCI
+extern void set_pci_dma_ops(struct dma_mapping_ops *dma_ops);
+extern struct dma_mapping_ops *get_pci_dma_ops(void);
 
 /* For DAC DMA, we currently don't support it by default, but
  * we let 64-bit platforms override this.
  */
 static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
 {
-       if (pci_dma_ops && pci_dma_ops->dac_dma_supported)
-               return pci_dma_ops->dac_dma_supported(&hwdev->dev, mask);
+       struct dma_mapping_ops *d = get_pci_dma_ops();
+
+       if (d && d->dac_dma_supported)
+               return d->dac_dma_supported(&hwdev->dev, mask);
        return 0;
 }
 
-#ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
                                        unsigned long *strategy_parameter)
@@ -99,6 +102,9 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
        *strat = PCI_DMA_BURST_MULTIPLE;
        *strategy_parameter = cacheline_size;
 }
+#else  /* CONFIG_PCI */
+#define set_pci_dma_ops(d)
+#define get_pci_dma_ops()      NULL
 #endif
 
 extern int pci_domain_nr(struct pci_bus *bus);
index 345d9b07b3e21ec7deca952683dcb35bc39c9d6c..a28fa8bc01da23e06218c0186c63dae61e9457b8 100644 (file)
@@ -97,3 +97,6 @@
 
 #define pud_ERROR(e) \
        printk("%s:%d: bad pud %08lx.\n", __FILE__, __LINE__, pud_val(e))
+
+#define remap_4k_pfn(vma, addr, pfn, prot)     \
+       remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, (prot))
index 4b7126c53f37b4cbc7a4c07f19fc38c9bf5805d2..5e84f070eaf70ef61e960eac97b450d0e0425245 100644 (file)
@@ -35,6 +35,7 @@
 #define _PAGE_HPTE_SUB 0x0ffff000 /* combo only: sub pages HPTE bits */
 #define _PAGE_HPTE_SUB0        0x08000000 /* combo only: first sub page */
 #define _PAGE_COMBO    0x10000000 /* this is a combo 4k page */
+#define _PAGE_4K_PFN   0x20000000 /* PFN is for a single 4k page */
 #define _PAGE_F_SECOND  0x00008000 /* full page: hidx bits */
 #define _PAGE_F_GIX     0x00007000 /* full page: hidx bits */
 
 #define pte_pagesize_index(pte)        \
        (((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
 
+#define remap_4k_pfn(vma, addr, pfn, prot)                             \
+       remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,                \
+                       __pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
+
 #endif /*  __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PGTABLE_64K_H */
index 10f52743f4ffec1e6bec9636a8920f5cd5ca60c3..19edb6982b81ca1194a34578a7fb3cb1bedfc803 100644 (file)
@@ -272,7 +272,10 @@ static inline pte_t pte_mkhuge(pte_t pte) {
        return pte; }
 
 /* Atomic PTE updates */
-static inline unsigned long pte_update(pte_t *p, unsigned long clr)
+static inline unsigned long pte_update(struct mm_struct *mm,
+                                      unsigned long addr,
+                                      pte_t *ptep, unsigned long clr,
+                                      int huge)
 {
        unsigned long old, tmp;
 
@@ -283,20 +286,15 @@ static inline unsigned long pte_update(pte_t *p, unsigned long clr)
        andc    %1,%0,%4 \n\
        stdcx.  %1,0,%3 \n\
        bne-    1b"
-       : "=&r" (old), "=&r" (tmp), "=m" (*p)
-       : "r" (p), "r" (clr), "m" (*p), "i" (_PAGE_BUSY)
+       : "=&r" (old), "=&r" (tmp), "=m" (*ptep)
+       : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY)
        : "cc" );
+
+       if (old & _PAGE_HASHPTE)
+               hpte_need_flush(mm, addr, ptep, old, huge);
        return old;
 }
 
-/* PTE updating functions, this function puts the PTE in the
- * batch, doesn't actually triggers the hash flush immediately,
- * you need to call flush_tlb_pending() to do that.
- * Pass -1 for "normal" size (4K or 64K)
- */
-extern void hpte_update(struct mm_struct *mm, unsigned long addr,
-                       pte_t *ptep, unsigned long pte, int huge);
-
 static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
                                              unsigned long addr, pte_t *ptep)
 {
@@ -304,11 +302,7 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
 
                if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
                return 0;
-       old = pte_update(ptep, _PAGE_ACCESSED);
-       if (old & _PAGE_HASHPTE) {
-               hpte_update(mm, addr, ptep, old, 0);
-               flush_tlb_pending();
-       }
+       old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0);
        return (old & _PAGE_ACCESSED) != 0;
 }
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
@@ -331,9 +325,7 @@ static inline int __ptep_test_and_clear_dirty(struct mm_struct *mm,
 
                if ((pte_val(*ptep) & _PAGE_DIRTY) == 0)
                return 0;
-       old = pte_update(ptep, _PAGE_DIRTY);
-       if (old & _PAGE_HASHPTE)
-               hpte_update(mm, addr, ptep, old, 0);
+       old = pte_update(mm, addr, ptep, _PAGE_DIRTY, 0);
        return (old & _PAGE_DIRTY) != 0;
 }
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
@@ -352,9 +344,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 
                if ((pte_val(*ptep) & _PAGE_RW) == 0)
                        return;
-       old = pte_update(ptep, _PAGE_RW);
-       if (old & _PAGE_HASHPTE)
-               hpte_update(mm, addr, ptep, old, 0);
+       old = pte_update(mm, addr, ptep, _PAGE_RW, 0);
 }
 
 /*
@@ -378,7 +368,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 ({                                                                     \
        int __dirty = __ptep_test_and_clear_dirty((__vma)->vm_mm, __address, \
                                                  __ptep);              \
-       flush_tlb_page(__vma, __address);                               \
        __dirty;                                                        \
 })
 
@@ -386,20 +375,14 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
                                       unsigned long addr, pte_t *ptep)
 {
-       unsigned long old = pte_update(ptep, ~0UL);
-
-       if (old & _PAGE_HASHPTE)
-               hpte_update(mm, addr, ptep, old, 0);
+       unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0);
        return __pte(old);
 }
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
                             pte_t * ptep)
 {
-       unsigned long old = pte_update(ptep, ~0UL);
-
-       if (old & _PAGE_HASHPTE)
-               hpte_update(mm, addr, ptep, old, 0);
+       pte_update(mm, addr, ptep, ~0UL, 0);
 }
 
 /*
@@ -408,10 +391,8 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pte)
 {
-       if (pte_present(*ptep)) {
+       if (pte_present(*ptep))
                pte_clear(mm, addr, ptep);
-               flush_tlb_pending();
-       }
        pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
        *ptep = pte;
 }
@@ -467,16 +448,6 @@ extern pgd_t swapper_pg_dir[];
 
 extern void paging_init(void);
 
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to put a corresponding HPTE into the hash table
- * ahead of time, instead of waiting for the inevitable extra
- * hash-table miss exception.
- */
-struct vm_area_struct;
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-
 /* Encode and de-code a swap entry */
 #define __swp_type(entry)      (((entry).val >> 1) & 0x3f)
 #define __swp_offset(entry)    ((entry).val >> 8)
@@ -522,6 +493,7 @@ void pgtable_cache_init(void);
        return pt;
 }
 
+
 #include <asm-generic/pgtable.h>
 
 #endif /* __ASSEMBLY__ */
index 8588be68e0ad616e987a95746d7b8f8ef9995939..d6a616a1b3ea8f8d4614ea9e236c4758589af605 100644 (file)
@@ -30,6 +30,7 @@ void release_pmc_hardware(void);
 
 #ifdef CONFIG_PPC64
 void power4_enable_pmcs(void);
+void pasemi_enable_pmcs(void);
 #endif
 
 #endif /* __KERNEL__ */
index ab6eddb518c737e3c59a6c63154215dc3998ad1e..d74b2965bb82d007b793a36a593123b0c9cb8e2a 100644 (file)
@@ -10,6 +10,8 @@
 #define _ASM_POWERPC_PPC_PCI_H
 #ifdef __KERNEL__
 
+#ifdef CONFIG_PCI
+
 #include <linux/pci.h>
 #include <asm/pci-bridge.h>
 
@@ -22,7 +24,7 @@ extern void pci_setup_phb_io_dynamic(struct pci_controller *hose, int primary);
 extern struct list_head hose_list;
 extern int global_phb_number;
 
-extern unsigned long find_and_init_phbs(void);
+extern void find_and_init_phbs(void);
 
 extern struct pci_dev *ppc64_isabridge_dev;    /* may be NULL if no ISA bus */
 
@@ -68,7 +70,7 @@ struct pci_dev *pci_get_device_by_addr(unsigned long addr);
 void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
 
 /**
- * rtas_pci_enableo - enable IO transfers for this slot
+ * rtas_pci_enable - enable IO transfers for this slot
  * @pdn:       pci device node
  * @function:  either EEH_THAW_MMIO or EEH_THAW_DMA 
  *
@@ -89,6 +91,7 @@ int rtas_pci_enable(struct pci_dn *pdn, int function);
  * Returns a non-zero value if the reset failed.
  */
 int rtas_set_slot_reset (struct pci_dn *);
+int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs);
 
 /** 
  * eeh_restore_bars - Restore device configuration info.
@@ -126,5 +129,10 @@ struct device_node * find_device_pe(struct device_node *dn);
 
 #endif
 
+#else /* CONFIG_PCI */
+static inline void find_and_init_phbs(void) { }
+static inline void init_pci_config_tokens(void) { }
+#endif /* !CONFIG_PCI */
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PPC_PCI_H */
index a26c32ee5527f300dc45620a7ab582b6bed8d699..d947b160949115894a0bd38caa8d6467a4f2d291 100644 (file)
@@ -133,7 +133,6 @@ struct thread_struct {
        mm_segment_t    fs;             /* for get_fs() validation */
 #ifdef CONFIG_PPC32
        void            *pgdir;         /* root of page-table tree */
-       signed long     last_syscall;
 #endif
 #if defined(CONFIG_4xx) || defined (CONFIG_BOOKE)
        unsigned long   dbcr0;          /* debug control register values */
index 020ed015a94b4fef829b20f20d1db6d58372e279..ec400f608e166c6e6a98584d274f8790a4d4918d 100644 (file)
@@ -18,7 +18,9 @@
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/platform_device.h>
+#include <asm/irq.h>
 #include <asm/atomic.h>
+#include <asm/io.h>
 
 /* Definitions used by the flattened device tree */
 #define OF_DT_HEADER           0xd00dfeed      /* marker */
@@ -58,6 +60,8 @@ struct boot_param_header
        u32     boot_cpuid_phys;        /* Physical CPU id we're booting on */
        /* version 3 fields below */
        u32     dt_strings_size;        /* size of the DT strings block */
+       /* version 17 fields below */
+       u32     dt_struct_size;         /* size of the DT structure block */
 };
 
 
@@ -68,7 +72,7 @@ typedef u32 ihandle;
 struct property {
        char    *name;
        int     length;
-       unsigned char *value;
+       void    *value;
        struct property *next;
 };
 
@@ -108,14 +112,6 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e
 }
 
 
-/* OBSOLETE: Old style node lookup */
-extern struct device_node *find_devices(const char *name);
-extern struct device_node *find_type_devices(const char *type);
-extern struct device_node *find_path_device(const char *path);
-extern struct device_node *find_compatible_devices(const char *type,
-                                                  const char *compat);
-extern struct device_node *find_all_nodes(void);
-
 /* New style node lookup */
 extern struct device_node *of_find_node_by_name(struct device_node *from,
        const char *name);
@@ -159,15 +155,17 @@ extern void of_detach_node(const struct device_node *);
 extern void finish_device_tree(void);
 extern void unflatten_device_tree(void);
 extern void early_init_devtree(void *);
-extern int device_is_compatible(const struct device_node *device,
+extern int of_device_is_compatible(const struct device_node *device,
                                const char *);
+#define device_is_compatible(d, c)     of_device_is_compatible((d), (c))
 extern int machine_is_compatible(const char *compat);
-extern const void *get_property(const struct device_node *node,
+extern const void *of_get_property(const struct device_node *node,
                                const char *name,
                                int *lenp);
+#define get_property(a, b, c)  of_get_property((a), (b), (c))
 extern void print_properties(struct device_node *node);
-extern int prom_n_addr_cells(struct device_node* np);
-extern int prom_n_size_cells(struct device_node* np);
+extern int of_n_addr_cells(struct device_node* np);
+extern int of_n_size_cells(struct device_node* np);
 extern int prom_n_intr_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
 extern int prom_add_property(struct device_node* np, struct property* prop);
@@ -350,6 +348,16 @@ static inline int of_irq_to_resource(struct device_node *dev, int index, struct
        return irq;
 }
 
+static inline void __iomem *of_iomap(struct device_node *np, int index)
+{
+       struct resource res;
+
+       if (of_address_to_resource(np, index, &res))
+               return NULL;
+
+       return ioremap(res.start, 1 + res.end - res.start);
+}
+
 
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PROM_H */
index 0d7f0164ed814ee85cd26b3a2e4f22bbf87ed517..749c7f953b58f126eff6df7708fc2ebad3084028 100644 (file)
 #define SPRN_SIAR      780
 #define SPRN_SDAR      781
 
-#define PA6T_SPRN_PMC0 787
-#define PA6T_SPRN_PMC1 788
-#define PA6T_SPRN_PMC2 789
-#define PA6T_SPRN_PMC3 790
-#define PA6T_SPRN_PMC4 791
-#define PA6T_SPRN_PMC5 792
+#define SPRN_PA6T_MMCR0 795
+#define   PA6T_MMCR0_EN0       0x0000000000000001UL
+#define   PA6T_MMCR0_EN1       0x0000000000000002UL
+#define   PA6T_MMCR0_EN2       0x0000000000000004UL
+#define   PA6T_MMCR0_EN3       0x0000000000000008UL
+#define   PA6T_MMCR0_EN4       0x0000000000000010UL
+#define   PA6T_MMCR0_EN5       0x0000000000000020UL
+#define   PA6T_MMCR0_SUPEN     0x0000000000000040UL
+#define   PA6T_MMCR0_PREN      0x0000000000000080UL
+#define   PA6T_MMCR0_HYPEN     0x0000000000000100UL
+#define   PA6T_MMCR0_FCM0      0x0000000000000200UL
+#define   PA6T_MMCR0_FCM1      0x0000000000000400UL
+#define   PA6T_MMCR0_INTGEN    0x0000000000000800UL
+#define   PA6T_MMCR0_INTEN0    0x0000000000001000UL
+#define   PA6T_MMCR0_INTEN1    0x0000000000002000UL
+#define   PA6T_MMCR0_INTEN2    0x0000000000004000UL
+#define   PA6T_MMCR0_INTEN3    0x0000000000008000UL
+#define   PA6T_MMCR0_INTEN4    0x0000000000010000UL
+#define   PA6T_MMCR0_INTEN5    0x0000000000020000UL
+#define   PA6T_MMCR0_DISCNT    0x0000000000040000UL
+#define   PA6T_MMCR0_UOP       0x0000000000080000UL
+#define   PA6T_MMCR0_TRG       0x0000000000100000UL
+#define   PA6T_MMCR0_TRGEN     0x0000000000200000UL
+#define   PA6T_MMCR0_TRGREG    0x0000000001600000UL
+#define   PA6T_MMCR0_SIARLOG   0x0000000002000000UL
+#define   PA6T_MMCR0_SDARLOG   0x0000000004000000UL
+#define   PA6T_MMCR0_PROEN     0x0000000008000000UL
+#define   PA6T_MMCR0_PROLOG    0x0000000010000000UL
+#define   PA6T_MMCR0_DAMEN2    0x0000000020000000UL
+#define   PA6T_MMCR0_DAMEN3    0x0000000040000000UL
+#define   PA6T_MMCR0_DAMEN4    0x0000000080000000UL
+#define   PA6T_MMCR0_DAMEN5    0x0000000100000000UL
+#define   PA6T_MMCR0_DAMSEL2   0x0000000200000000UL
+#define   PA6T_MMCR0_DAMSEL3   0x0000000400000000UL
+#define   PA6T_MMCR0_DAMSEL4   0x0000000800000000UL
+#define   PA6T_MMCR0_DAMSEL5   0x0000001000000000UL
+#define   PA6T_MMCR0_HANDDIS   0x0000002000000000UL
+#define   PA6T_MMCR0_PCTEN     0x0000004000000000UL
+#define   PA6T_MMCR0_SOCEN     0x0000008000000000UL
+#define   PA6T_MMCR0_SOCMOD    0x0000010000000000UL
+
+#define SPRN_PA6T_MMCR1 798
+#define   PA6T_MMCR1_ES2       0x00000000000000ffUL
+#define   PA6T_MMCR1_ES3       0x000000000000ff00UL
+#define   PA6T_MMCR1_ES4       0x0000000000ff0000UL
+#define   PA6T_MMCR1_ES5       0x00000000ff000000UL
+
+#define SPRN_PA6T_SIAR  780
+#define SPRN_PA6T_UPMC0 771
+#define SPRN_PA6T_UPMC1 772
+#define SPRN_PA6T_UPMC2 773
+#define SPRN_PA6T_UPMC3 774
+#define SPRN_PA6T_UPMC4 775
+#define SPRN_PA6T_UPMC5 776
+#define SPRN_PA6T_UMMCR0 779
+#define SPRN_PA6T_UMMCR1 782
+#define SPRN_PA6T_PMC0  787
+#define SPRN_PA6T_PMC1  788
+#define SPRN_PA6T_PMC2  789
+#define SPRN_PA6T_PMC3  790
+#define SPRN_PA6T_PMC4  791
+#define SPRN_PA6T_PMC5  792
 
 #else /* 32-bit */
 #define SPRN_MMCR0     952     /* Monitor Mode Control Register 0 */
index 8aad0619eb8e5a43e7365bf8a5e27199e5fc264d..02e56a6685a24baf9216336bbe2c3f1c6308829e 100644 (file)
@@ -242,6 +242,7 @@ struct spu_state {
        u64 spu_chnldata_RW[32];
        u32 spu_mailbox_data[4];
        u32 pu_mailbox_data[1];
+       u64 dar, dsisr;
        unsigned long suspend_time;
        spinlock_t register_lock;
 };
index f7b1227d64548ab68f557f78a1ba1fa5afe89bf1..d3e0906ff2bc055bf1df7b566ff293e2faf778c6 100644 (file)
@@ -131,6 +131,7 @@ extern void enable_kernel_altivec(void);
 extern void giveup_altivec(struct task_struct *);
 extern void load_up_altivec(struct task_struct *);
 extern int emulate_altivec(struct pt_regs *);
+extern void enable_kernel_spe(void);
 extern void giveup_spe(struct task_struct *);
 extern void load_up_spe(struct task_struct *);
 extern int fix_alignment(struct pt_regs *);
index 4e2a834683fbcae87e39b4bbdaaefa3b7bbc6b18..0a17682663d8f308411b26e8ba28eb91e1c8fe96 100644 (file)
@@ -38,7 +38,6 @@ extern void pte_free_finish(void);
 
 static inline void tlb_flush(struct mmu_gather *tlb)
 {
-       flush_tlb_pending();
        pte_free_finish();
 }
 
index 93c7d0c7230f5db796ee9115f84f84270ae680a6..86e6266a028bb9a69ad1217b4c5005ffa264156c 100644 (file)
  */
 #ifdef __KERNEL__
 
-
 struct mm_struct;
+struct vm_area_struct;
+
+#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE)
+/*
+ * TLB flushing for software loaded TLB chips
+ *
+ * TODO: (CONFIG_FSL_BOOKE) determine if flush_tlb_range &
+ * flush_tlb_kernel_range are best implemented as tlbia vs
+ * specific tlbie's
+ */
+
+extern void _tlbie(unsigned long address);
+
+#if defined(CONFIG_40x) || defined(CONFIG_8xx)
+#define _tlbia()       asm volatile ("tlbia; sync" : : : "memory")
+#else /* CONFIG_44x || CONFIG_FSL_BOOKE */
+extern void _tlbia(void);
+#endif
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+       _tlbia();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+                                 unsigned long vmaddr)
+{
+       _tlbie(vmaddr);
+}
+
+static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
+                                        unsigned long vmaddr)
+{
+       _tlbie(vmaddr);
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+                                  unsigned long start, unsigned long end)
+{
+       _tlbia();
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start,
+                                         unsigned long end)
+{
+       _tlbia();
+}
 
-#ifdef CONFIG_PPC64
+#elif defined(CONFIG_PPC32)
+/*
+ * TLB flushing for "classic" hash-MMMU 32-bit CPUs, 6xx, 7xx, 7xxx
+ */
+extern void _tlbie(unsigned long address);
+extern void _tlbia(void);
+
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+                           unsigned long end);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+
+#else
+/*
+ * TLB flushing for 64-bit has-MMU CPUs
+ */
 
 #include <linux/percpu.h>
 #include <asm/page.h>
@@ -28,117 +91,90 @@ struct mm_struct;
 #define PPC64_TLB_BATCH_NR 192
 
 struct ppc64_tlb_batch {
-       unsigned long index;
-       struct mm_struct *mm;
-       real_pte_t pte[PPC64_TLB_BATCH_NR];
-       unsigned long vaddr[PPC64_TLB_BATCH_NR];
-       unsigned int psize;
+       int                     active;
+       unsigned long           index;
+       struct mm_struct        *mm;
+       real_pte_t              pte[PPC64_TLB_BATCH_NR];
+       unsigned long           vaddr[PPC64_TLB_BATCH_NR];
+       unsigned int            psize;
 };
 DECLARE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
 
 extern void __flush_tlb_pending(struct ppc64_tlb_batch *batch);
 
-static inline void flush_tlb_pending(void)
+extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
+                           pte_t *ptep, unsigned long pte, int huge);
+
+#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
+
+static inline void arch_enter_lazy_mmu_mode(void)
+{
+       struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
+
+       batch->active = 1;
+}
+
+static inline void arch_leave_lazy_mmu_mode(void)
 {
-       struct ppc64_tlb_batch *batch = &get_cpu_var(ppc64_tlb_batch);
+       struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
 
        if (batch->index)
                __flush_tlb_pending(batch);
-       put_cpu_var(ppc64_tlb_batch);
+       batch->active = 0;
 }
 
+#define arch_flush_lazy_mmu_mode()      do {} while (0)
+
+
 extern void flush_hash_page(unsigned long va, real_pte_t pte, int psize,
                            int local);
 extern void flush_hash_range(unsigned long number, int local);
 
-#else /* CONFIG_PPC64 */
-
-#include <linux/mm.h>
-
-extern void _tlbie(unsigned long address);
-extern void _tlbia(void);
-
-/*
- * TODO: (CONFIG_FSL_BOOKE) determine if flush_tlb_range &
- * flush_tlb_kernel_range are best implemented as tlbia vs
- * specific tlbie's
- */
-
-#if (defined(CONFIG_4xx) && !defined(CONFIG_44x)) || defined(CONFIG_8xx)
-#define flush_tlb_pending()    asm volatile ("tlbia; sync" : : : "memory")
-#elif defined(CONFIG_4xx) || defined(CONFIG_FSL_BOOKE)
-#define flush_tlb_pending()    _tlbia()
-#endif
-
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to ensure coherency between the i-cache and d-cache
- * for the page which has just been mapped in.
- * On machines which use an MMU hash table, we use this to put a
- * corresponding HPTE into the hash table ahead of time, instead of
- * waiting for the inevitable extra hash-table miss exception.
- */
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-
-#endif /* CONFIG_PPC64 */
-
-#if defined(CONFIG_PPC64) || defined(CONFIG_4xx) || \
-       defined(CONFIG_FSL_BOOKE) || defined(CONFIG_8xx)
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
-       flush_tlb_pending();
 }
 
 static inline void flush_tlb_page(struct vm_area_struct *vma,
-                               unsigned long vmaddr)
+                                 unsigned long vmaddr)
 {
-#ifdef CONFIG_PPC64
-       flush_tlb_pending();
-#else
-       _tlbie(vmaddr);
-#endif
 }
 
 static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
                                         unsigned long vmaddr)
 {
-#ifndef CONFIG_PPC64
-       _tlbie(vmaddr);
-#endif
 }
 
 static inline void flush_tlb_range(struct vm_area_struct *vma,
-               unsigned long start, unsigned long end)
+                                  unsigned long start, unsigned long end)
 {
-       flush_tlb_pending();
 }
 
 static inline void flush_tlb_kernel_range(unsigned long start,
-               unsigned long end)
+                                         unsigned long end)
 {
-       flush_tlb_pending();
 }
 
-#else  /* 6xx, 7xx, 7xxx cpus */
-
-extern void flush_tlb_mm(struct mm_struct *mm);
-extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr);
-extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
-                           unsigned long end);
-extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
-
 #endif
 
+/*
+ * This gets called at the end of handling a page fault, when
+ * the kernel has put a new PTE into the page table for the process.
+ * We use it to ensure coherency between the i-cache and d-cache
+ * for the page which has just been mapped in.
+ * On machines which use an MMU hash table, we use this to put a
+ * corresponding HPTE into the hash table ahead of time, instead of
+ * waiting for the inevitable extra hash-table miss exception.
+ */
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+
 /*
  * This is called in munmap when we have freed up some page-table
  * pages.  We don't need to do anything here, there's nothing special
  * about our page-table pages.  -- paulus
  */
 static inline void flush_tlb_pgtables(struct mm_struct *mm,
-               unsigned long start, unsigned long end)
+                                     unsigned long start, unsigned long end)
 {
 }
 
index adbf16b8cfbbbf8e52ece9bf71a089845f8ca71a..8e798e3758bc38137ca15d2f0e23c954e0339c26 100644 (file)
@@ -110,12 +110,18 @@ struct exception_table_entry {
        __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
 #define __put_user(x, ptr) \
        __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
 #ifndef __powerpc64__
 #define __get_user64(x, ptr) \
        __get_user64_nocheck((x), (ptr), sizeof(*(ptr)))
 #define __put_user64(x, ptr) __put_user(x, ptr)
 #endif
 
+#define __get_user_inatomic(x, ptr) \
+       __get_user_nosleep((x), (ptr), sizeof(*(ptr)))
+#define __put_user_inatomic(x, ptr) \
+       __put_user_nosleep((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
 #define __get_user_unaligned __get_user
 #define __put_user_unaligned __put_user
 
@@ -198,6 +204,16 @@ do {                                                               \
        __pu_err;                                                       \
 })
 
+#define __put_user_nosleep(x, ptr, size)                       \
+({                                                             \
+       long __pu_err;                                          \
+       __typeof__(*(ptr)) __user *__pu_addr = (ptr);           \
+       __chk_user_ptr(ptr);                                    \
+       __put_user_size((x), __pu_addr, (size), __pu_err);      \
+       __pu_err;                                               \
+})
+
+
 extern long __get_user_bad(void);
 
 #define __get_user_asm(x, addr, err, op)               \
@@ -297,6 +313,18 @@ do {                                                               \
        __gu_err;                                                       \
 })
 
+#define __get_user_nosleep(x, ptr, size)                       \
+({                                                             \
+       long __gu_err;                                          \
+       unsigned long __gu_val;                                 \
+       const __typeof__(*(ptr)) __user *__gu_addr = (ptr);     \
+       __chk_user_ptr(ptr);                                    \
+       __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
+       (x) = (__typeof__(*(ptr)))__gu_val;                     \
+       __gu_err;                                               \
+})
+
+
 /* more complex routines */
 
 extern unsigned long __copy_tofrom_user(void __user *to,
index 39d1c90fd2caccace8053f80c7195e0b651b8a47..f529f70b1d82f0b011a8e30d924e1b50ed662d65 100644 (file)
@@ -159,6 +159,9 @@ struct ucc_fast_private {
        struct ucc_fast *uf_regs;       /* a pointer to memory map of UCC regs. */
        u32 *p_ucce;            /* a pointer to the event register in memory. */
        u32 *p_uccm;            /* a pointer to the mask register in memory. */
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+       u16 *p_utodr;           /* pointer to the transmit on demand register */
+#endif
        int enabled_tx;         /* Whether channel is enabled for Tx (ENT) */
        int enabled_rx;         /* Whether channel is enabled for Rx (ENR) */
        int stopped_tx;         /* Whether channel has been stopped for Tx
diff --git a/include/asm-powerpc/uic.h b/include/asm-powerpc/uic.h
new file mode 100644 (file)
index 0000000..970eb7e
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * include/asm-powerpc/uic.h
+ *
+ * IBM PPC4xx UIC external definitions and structure.
+ *
+ * Maintainer: David Gibson <dwg@au1.ibm.com>
+ * Copyright 2007 IBM Corporation.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef _ASM_POWERPC_UIC_H
+#define _ASM_POWERPC_UIC_H
+
+#ifdef __KERNEL__
+
+extern void __init uic_init_tree(void);
+extern unsigned int uic_get_irq(void);
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_UIC_H */
index 92fd02d7b17766604a6a74214e378a86ebb10f99..ed6891af05d35de214fd9f25a09b87d8f2315153 100644 (file)
 #include <platforms/4xx/walnut.h>
 #endif
 
-#if defined(CONFIG_XILINX_ML300)
-#include <platforms/4xx/xilinx_ml300.h>
-#endif
-
-#if defined(CONFIG_XILINX_ML403)
-#include <platforms/4xx/xilinx_ml403.h>
+#if defined(CONFIG_XILINX_VIRTEX)
+#include <platforms/4xx/virtex.h>
 #endif
 
 #ifndef __ASSEMBLY__
index 40f197af65085844fc6bcad81942d6982d3f7cbc..de99e92d627b0b02152480e0ca93f66b6755ae79 100644 (file)
@@ -33,8 +33,6 @@
 #include <asm/mpc52xx.h>
 #elif defined(CONFIG_MPC10X_BRIDGE)
 #include <asm/mpc10x.h>
-#elif defined(CONFIG_XILINX_VIRTEX)
-#include <platforms/4xx/virtex.h>
 #else
 #error "need definition of ppc_sys_devices"
 #endif
index adc5ae78492411fd836e31fb48082b63aa795471..901f7fa8b2d7dbda789913eecd180a6d0cadc588 100644 (file)
@@ -34,7 +34,8 @@ extern unsigned long sub_reloc_offset(unsigned long);
  */
 #define machine_is_compatible(x)               0
 #define of_find_compatible_node(f, t, c)       NULL
-#define get_property(p, n, l)                  NULL
+#define of_get_property(p, n, l)               NULL
+#define get_property(a, b, c)                  of_get_property((a), (b), (c))
 
 #endif /* _PPC_PROM_H */
 #endif /* __KERNEL__ */
index 6caeb98e29ddd942c6defabc3eace48702f63b52..edb31bfff68fb3586097173f5dc61b7b215333ab 100644 (file)
@@ -159,11 +159,19 @@ enum {
        ATA_CMD_INIT_DEV_PARAMS = 0x91,
        ATA_CMD_READ_NATIVE_MAX = 0xF8,
        ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
+       ATA_CMD_SET_MAX         = 0xF9,
+       ATA_CMD_SET_MAX_EXT     = 0x37,
        ATA_CMD_READ_LOG_EXT    = 0x2f,
 
        /* READ_LOG_EXT pages */
        ATA_LOG_SATA_NCQ        = 0x10,
 
+       /* READ/WRITE LONG (obsolete) */
+       ATA_CMD_READ_LONG       = 0x22,
+       ATA_CMD_READ_LONG_ONCE  = 0x23,
+       ATA_CMD_WRITE_LONG      = 0x32,
+       ATA_CMD_WRITE_LONG_ONCE = 0x33,
+
        /* SETFEATURES stuff */
        SETFEATURES_XFER        = 0x03,
        XFER_UDMA_7             = 0x47,
@@ -194,6 +202,8 @@ enum {
        SETFEATURES_WC_ON       = 0x02, /* Enable write cache */
        SETFEATURES_WC_OFF      = 0x82, /* Disable write cache */
 
+       SETFEATURES_SPINUP      = 0x07, /* Spin-up drive */
+
        /* ATAPI stuff */
        ATAPI_PKT_DMA           = (1 << 0),
        ATAPI_DMADIR            = (1 << 2),     /* ATAPI data dir:
index 08daf3272c0283b808cbe75ec48348c3efc8a71e..4d85262b4fa4e8a4e9eb984e668f57363fd09183 100644 (file)
@@ -276,7 +276,7 @@ extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool,
 extern mempool_t *bio_split_pool;
 extern void bio_pair_release(struct bio_pair *dbio);
 
-extern struct bio_set *bioset_create(int, int, int);
+extern struct bio_set *bioset_create(int, int);
 extern void bioset_free(struct bio_set *);
 
 extern struct bio *bio_alloc(gfp_t, int);
index 83dcd8c0e97493cb5a385dff744f0856fd484625..a686eabe22d645e8304af1ab33ab6114783523d9 100644 (file)
@@ -116,6 +116,7 @@ struct io_context {
 
        struct as_io_context *aic;
        struct rb_root cic_root;
+       void *ioc_data;
 };
 
 void put_io_context(struct io_context *ioc);
index abb64c437f6fd92b447deb18768549d7cbb45ddc..73710d617775e6f953f9513fb4a99dcdab29abba 100644 (file)
@@ -120,44 +120,5 @@ struct fsl_spi_platform_data {
        u32     sysclk;
 };
 
-/* Ethernet interface (phy management and speed)
-*/
-enum enet_interface {
-       ENET_10_MII,            /* 10 Base T,   MII interface */
-       ENET_10_RMII,           /* 10 Base T,  RMII interface */
-       ENET_10_RGMII,          /* 10 Base T, RGMII interface */
-       ENET_100_MII,           /* 100 Base T,   MII interface */
-       ENET_100_RMII,          /* 100 Base T,  RMII interface */
-       ENET_100_RGMII,         /* 100 Base T, RGMII interface */
-       ENET_1000_GMII,         /* 1000 Base T,  GMII interface */
-       ENET_1000_RGMII,        /* 1000 Base T, RGMII interface */
-       ENET_1000_TBI,          /* 1000 Base T,   TBI interface */
-       ENET_1000_RTBI          /* 1000 Base T,  RTBI interface */
-};
-
-struct ucc_geth_platform_data {
-       /* device specific information */
-       u32                     device_flags;
-       u32                     phy_reg_addr;
-
-       /* board specific information */
-       u32                     board_flags;
-       u8                      rx_clock;
-       u8                      tx_clock;
-       u32                     phy_id;
-       enum enet_interface     phy_interface;
-       u32                     phy_interrupt;
-       u8                      mac_addr[6];
-};
-
-/* Flags related to UCC Gigabit Ethernet device features */
-#define FSL_UGETH_DEV_HAS_GIGABIT              0x00000001
-#define FSL_UGETH_DEV_HAS_COALESCE             0x00000002
-#define FSL_UGETH_DEV_HAS_RMON                 0x00000004
-
-/* Flags in ucc_geth_platform_data */
-#define FSL_UGETH_BRD_HAS_PHY_INTR             0x00000001
-                               /* if not set use a timer */
-
 #endif /* _FSL_DEVICE_H_ */
 #endif /* __KERNEL__ */
index 0fe562af9c8cfb51088df41866362953970c5591..db390c511ada863ce1173b267c066b99509a39a5 100644 (file)
@@ -43,8 +43,7 @@ struct hdlc_proto {
        void (*stop)(struct net_device *dev); /* if open & !DCD */
        void (*detach)(struct net_device *dev);
        int (*ioctl)(struct net_device *dev, struct ifreq *ifr);
-       unsigned short (*type_trans)(struct sk_buff *skb,
-                                    struct net_device *dev);
+       __be16 (*type_trans)(struct sk_buff *skb, struct net_device *dev);
        struct module *module;
        struct hdlc_proto *next; /* next protocol in the list */
 };
index 6859a3b14088459fef9de4e373f36ea0009a0f3a..71ea92319241ef55579609a081a6ff60bc403bf8 100644 (file)
@@ -99,7 +99,6 @@ extern struct resource ioport_resource;
 extern struct resource iomem_resource;
 
 extern int request_resource(struct resource *root, struct resource *new);
-extern struct resource * ____request_resource(struct resource *root, struct resource *new);
 extern int release_resource(struct resource *new);
 extern int insert_resource(struct resource *parent, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,
index 0cfbcb6f08eb79a1841ddb7cc7ccabc7370188d2..d8cfc72ea9c110937161c910813a5f59d447b3b6 100644 (file)
@@ -210,6 +210,7 @@ enum {
 
        /* host set flags */
        ATA_HOST_SIMPLEX        = (1 << 0),     /* Host is simplex, one DMA channel per host only */
+       ATA_HOST_STARTED        = (1 << 1),     /* Host started */
 
        /* various lengths of time */
        ATA_TMOUT_BOOT          = 30 * HZ,      /* heuristic */
@@ -281,11 +282,13 @@ enum {
        ATA_EHI_NO_AUTOPSY      = (1 << 2),  /* no autopsy */
        ATA_EHI_QUIET           = (1 << 3),  /* be quiet */
 
-       ATA_EHI_DID_RESET       = (1 << 16), /* already reset this port */
-       ATA_EHI_PRINTINFO       = (1 << 17), /* print configuration info */
-       ATA_EHI_SETMODE         = (1 << 18), /* configure transfer mode */
-       ATA_EHI_POST_SETMODE    = (1 << 19), /* revaildating after setmode */
+       ATA_EHI_DID_SOFTRESET   = (1 << 16), /* already soft-reset this port */
+       ATA_EHI_DID_HARDRESET   = (1 << 17), /* already soft-reset this port */
+       ATA_EHI_PRINTINFO       = (1 << 18), /* print configuration info */
+       ATA_EHI_SETMODE         = (1 << 19), /* configure transfer mode */
+       ATA_EHI_POST_SETMODE    = (1 << 20), /* revaildating after setmode */
 
+       ATA_EHI_DID_RESET       = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET,
        ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK,
 
        /* max repeat if error condition is still set after ->error_handler */
@@ -367,34 +370,6 @@ struct ata_ioports {
        void __iomem            *scr_addr;
 };
 
-struct ata_probe_ent {
-       struct list_head        node;
-       struct device           *dev;
-       const struct ata_port_operations *port_ops;
-       struct scsi_host_template *sht;
-       struct ata_ioports      port[ATA_MAX_PORTS];
-       unsigned int            n_ports;
-       unsigned int            dummy_port_mask;
-       unsigned int            pio_mask;
-       unsigned int            mwdma_mask;
-       unsigned int            udma_mask;
-       unsigned long           irq;
-       unsigned long           irq2;
-       unsigned int            irq_flags;
-       unsigned long           port_flags;
-       unsigned long           _host_flags;
-       void __iomem * const    *iomap;
-       void                    *private_data;
-
-       /* port_info for the secondary port.  Together with irq2, it's
-        * used to implement non-uniform secondary port.  Currently,
-        * the only user is ata_piix combined mode.  This workaround
-        * will be removed together with ata_probe_ent when init model
-        * is updated.
-        */
-       const struct ata_port_info *pinfo2;
-};
-
 struct ata_host {
        spinlock_t              lock;
        struct device           *dev;
@@ -427,6 +402,7 @@ struct ata_queued_cmd {
        int                     dma_dir;
 
        unsigned int            pad_len;
+       unsigned int            sect_size;
 
        unsigned int            nbytes;
        unsigned int            curbytes;
@@ -472,6 +448,7 @@ struct ata_device {
        struct scsi_device      *sdev;          /* attached SCSI device */
        /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
        u64                     n_sectors;      /* size of device, if ATA */
+       u64                     n_sectors_boot; /* size of ATA device at startup */
        unsigned int            class;          /* ATA_DEV_xxx */
        u16                     id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
        u8                      pio_mode;
@@ -597,11 +574,11 @@ struct ata_port {
 struct ata_port_operations {
        void (*port_disable) (struct ata_port *);
 
-       void (*dev_config) (struct ata_port *, struct ata_device *);
+       void (*dev_config) (struct ata_device *);
 
        void (*set_piomode) (struct ata_port *, struct ata_device *);
        void (*set_dmamode) (struct ata_port *, struct ata_device *);
-       unsigned long (*mode_filter) (const struct ata_port *, struct ata_device *, unsigned long);
+       unsigned long (*mode_filter) (struct ata_device *, unsigned long);
 
        void (*tf_load) (struct ata_port *ap, const struct ata_taskfile *tf);
        void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
@@ -616,6 +593,8 @@ struct ata_port_operations {
 
        void (*post_set_mode) (struct ata_port *ap);
 
+       int (*cable_detect) (struct ata_port *ap);
+
        int  (*check_atapi_dma) (struct ata_queued_cmd *qc);
 
        void (*bmdma_setup) (struct ata_queued_cmd *qc);
@@ -664,6 +643,7 @@ struct ata_port_info {
        unsigned long           mwdma_mask;
        unsigned long           udma_mask;
        const struct ata_port_operations *port_ops;
+       irq_handler_t           irq_handler;
        void                    *private_data;
 };
 
@@ -686,6 +666,7 @@ extern const unsigned long sata_deb_timing_hotplug[];
 extern const unsigned long sata_deb_timing_long[];
 
 extern const struct ata_port_operations ata_dummy_port_ops;
+extern const struct ata_port_info ata_dummy_port_info;
 
 static inline const unsigned long *
 sata_ehc_deb_timing(struct ata_eh_context *ehc)
@@ -701,6 +682,7 @@ static inline int ata_port_is_dummy(struct ata_port *ap)
        return ap->ops == &ata_dummy_port_ops;
 }
 
+extern void sata_print_link_status(struct ata_port *ap);
 extern void ata_port_probe(struct ata_port *);
 extern void __sata_phy_reset(struct ata_port *ap);
 extern void sata_phy_reset(struct ata_port *ap);
@@ -728,7 +710,15 @@ extern int ata_pci_device_resume(struct pci_dev *pdev);
 #endif
 extern int ata_pci_clear_simplex(struct pci_dev *pdev);
 #endif /* CONFIG_PCI */
-extern int ata_device_add(const struct ata_probe_ent *ent);
+extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
+extern struct ata_host *ata_host_alloc_pinfo(struct device *dev,
+                       const struct ata_port_info * const * ppi, int n_ports);
+extern int ata_host_start(struct ata_host *host);
+extern int ata_host_register(struct ata_host *host,
+                            struct scsi_host_template *sht);
+extern int ata_host_activate(struct ata_host *host, int irq,
+                            irq_handler_t irq_handler, unsigned long irq_flags,
+                            struct scsi_host_template *sht);
 extern void ata_host_detach(struct ata_host *host);
 extern void ata_host_init(struct ata_host *, struct device *,
                          unsigned long, const struct ata_port_operations *);
@@ -828,11 +818,17 @@ extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
 extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
                                       int queue_depth);
 extern struct ata_device *ata_dev_pair(struct ata_device *adev);
+extern int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
 extern u8 ata_irq_on(struct ata_port *ap);
 extern u8 ata_dummy_irq_on(struct ata_port *ap);
 extern u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq);
 extern u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq);
 
+extern int ata_cable_40wire(struct ata_port *ap);
+extern int ata_cable_80wire(struct ata_port *ap);
+extern int ata_cable_sata(struct ata_port *ap);
+extern int ata_cable_unknown(struct ata_port *ap);
+
 /*
  * Timing helpers
  */
@@ -870,10 +866,13 @@ struct pci_bits {
        unsigned long           val;
 };
 
-extern struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask);
+extern int ata_pci_init_native_host(struct ata_host *host,
+                                   unsigned int port_mask);
+extern int ata_pci_prepare_native_host(struct pci_dev *pdev,
+                               const struct ata_port_info * const * ppi,
+                               int n_ports, struct ata_host **r_host);
 extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
-extern unsigned long ata_pci_default_filter(const struct ata_port *, struct ata_device *, unsigned long);
+extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long);
 #endif /* CONFIG_PCI */
 
 /*
@@ -1173,6 +1172,7 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
        qc->n_elem = 0;
        qc->err_mask = 0;
        qc->pad_len = 0;
+       qc->sect_size = ATA_SECT_SIZE;
 
        ata_tf_init(qc->dev, &qc->tf);
 
@@ -1220,7 +1220,7 @@ static inline void ata_pad_free(struct ata_port *ap, struct device *dev)
 
 static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host)
 {
-       return (struct ata_port *) &host->hostdata[0];
+       return *(struct ata_port **)&host->hostdata[0];
 }
 
 #endif /* __LINUX_LIBATA_H__ */
index a3ad76221c6ff23d2e6b3c07d874f37aeac79354..972491089ac9622884a4cfb1a4c6d5861754a6c2 100644 (file)
@@ -838,6 +838,7 @@ void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
 void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr);
 void __iomem * const * pcim_iomap_table(struct pci_dev *pdev);
 int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name);
+void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask);
 
 extern int pci_pci_problems;
 #define PCIPCI_FAIL            1       /* No PCI PCI DMA */
index 600308fdf9ce31b6ece7efc34dbbc6fe633888e6..1b0ddbb8a8045ea85fc8fb028b81919dc7ca6baf 100644 (file)
 #define PCI_DEVICE_ID_ATI_IXP400_SATA   0x4379
 #define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a
 #define PCI_DEVICE_ID_ATI_IXP600_SATA  0x4380
-#define PCI_DEVICE_ID_ATI_IXP600_SRAID 0x4381
 #define PCI_DEVICE_ID_ATI_IXP600_SMBUS 0x4385
 #define PCI_DEVICE_ID_ATI_IXP600_IDE   0x438c
 
 
 #define PCI_VENDOR_ID_TOSHIBA_2                0x102f
 #define PCI_DEVICE_ID_TOSHIBA_TC35815CF        0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU      0x0031
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939   0x0032
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE     0x0105
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC    0x0108
 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
index edd4c88ca7d8d1a68e88922bc8466200e59d6214..2a659789f9ca10bcca00497dcfde170023906475 100644 (file)
@@ -55,6 +55,7 @@ typedef enum {
        PHY_INTERFACE_MODE_TBI,
        PHY_INTERFACE_MODE_RMII,
        PHY_INTERFACE_MODE_RGMII,
+       PHY_INTERFACE_MODE_RGMII_ID,
        PHY_INTERFACE_MODE_RTBI
 } phy_interface_t;
 
index 783177387ac61323fdfff6db8c3b717665d62c7c..b0952e532ed52a0e05cfb768bc7a479ce6d2ba34 100644 (file)
@@ -168,24 +168,16 @@ extern int pmu_get_model(void);
 
 struct pmu_sleep_notifier
 {
-       int (*notifier_call)(struct pmu_sleep_notifier *self, int when);
+       void (*notifier_call)(struct pmu_sleep_notifier *self, int when);
        int priority;
        struct list_head list;
 };
 
 /* Code values for calling sleep/wakeup handlers
- *
- * Note: If a sleep request got cancelled, all drivers will get
- * the PBOOK_SLEEP_REJECT, even those who didn't get the PBOOK_SLEEP_REQUEST.
  */
 #define PBOOK_SLEEP_REQUEST    1
 #define PBOOK_SLEEP_NOW                2
-#define PBOOK_SLEEP_REJECT     3
-#define PBOOK_WAKE             4
-
-/* Result codes returned by the notifiers */
-#define PBOOK_SLEEP_OK         0
-#define PBOOK_SLEEP_REFUSE     -1
+#define PBOOK_WAKE             3
 
 /* priority levels in notifiers */
 #define SLEEP_LEVEL_VIDEO      100     /* Video driver (first wake) */
diff --git a/include/linux/sony-laptop.h b/include/linux/sony-laptop.h
new file mode 100644 (file)
index 0000000..e2e036d
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _SONYLAPTOP_H_
+#define _SONYLAPTOP_H_
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+
+/* used only for communication between v4l and sony-laptop */
+
+#define SONY_PIC_COMMAND_GETCAMERA              1      /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERA              2
+#define SONY_PIC_COMMAND_GETCAMERABRIGHTNESS    3      /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERABRIGHTNESS    4
+#define SONY_PIC_COMMAND_GETCAMERACONTRAST      5      /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERACONTRAST      6
+#define SONY_PIC_COMMAND_GETCAMERAHUE           7      /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAHUE           8
+#define SONY_PIC_COMMAND_GETCAMERACOLOR                 9      /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERACOLOR                10
+#define SONY_PIC_COMMAND_GETCAMERASHARPNESS    11      /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERASHARPNESS    12
+#define SONY_PIC_COMMAND_GETCAMERAPICTURE      13      /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAPICTURE      14
+#define SONY_PIC_COMMAND_GETCAMERAAGC          15      /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAAGC          16
+#define SONY_PIC_COMMAND_GETCAMERADIRECTION    17      /* obsolete */
+#define SONY_PIC_COMMAND_GETCAMERAROMVERSION   18      /* obsolete */
+#define SONY_PIC_COMMAND_GETCAMERAREVISION     19      /* obsolete */
+
+int sony_pic_camera_command(int command, u8 value);
+
+#endif /* __KERNEL__ */
+
+#endif /* _SONYLAPTOP_H_ */
index 48759b2f57d7c795057ddec2642a3377b041d400..0987aa7a6cf513281b0c6fb50332bc260f3ca279 100644 (file)
  *     - Wireless Event capability in struct iw_range
  *     - Add support for relative TxPower (yick !)
  *
- * V17 to V18 (From Jouni Malinen <jkmaline@cc.hut.fi>)
+ * V17 to V18 (From Jouni Malinen <j@w1.fi>)
  * ----------
  *     - Add support for WPA/WPA2
  *     - Add extended encoding configuration (SIOCSIWENCODEEXT and
index e02d85f56e601d79c0ccb32ea4157ee890909cd3..d56b2923d61a1cf2093229309f47ef03ae3d98f4 100644 (file)
@@ -6,8 +6,8 @@
  * LAN access point) driver for Intersil Prism2/2.5/3.
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  *
  * Adaption to a generic IEEE 802.11 stack by James Ketrenos
  * <jketreno@linux.intel.com>
index eb476414fd726701d032e9e517751b9d3f7e38df..b3d65e0bedd31fbe370094a421c95c36430703c4 100644 (file)
@@ -3,8 +3,8 @@
  * for Intersil Prism2/2.5/3.
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  *
  * Adaption to a generic IEEE 802.11 stack by James Ketrenos
  * <jketreno@linux.intel.com>
index 429b73892a5fc62f91e4a4b05da40859604fa791..a0c2b41a24d7d2174cd7ca9d7f8c98d8ca1ea56c 100644 (file)
@@ -66,7 +66,9 @@
  */
 #define IEEE80211_RADIOTAP_HDRLEN      64
 
-/* The radio capture header precedes the 802.11 header. */
+/* The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
 struct ieee80211_radiotap_header {
        u8 it_version;          /* Version 0. Only increases
                                 * for drastic changes,
@@ -74,12 +76,12 @@ struct ieee80211_radiotap_header {
                                 * new fields does not count.
                                 */
        u8 it_pad;
-       u16 it_len;             /* length of the whole
+       __le16 it_len;          /* length of the whole
                                 * header in bytes, including
                                 * it_version, it_pad,
                                 * it_len, and data fields.
                                 */
-       u32 it_present;         /* A bitmap telling which
+       __le32 it_present;      /* A bitmap telling which
                                 * fields are present. Set bit 31
                                 * (0x80000000) to extend the
                                 * bitmap by another 32 bits.
@@ -88,89 +90,102 @@ struct ieee80211_radiotap_header {
                                 */
 };
 
-/* Name                                 Data type       Units
- * ----                                 ---------       -----
+/* Name                                 Data type    Units
+ * ----                                 ---------    -----
  *
- * IEEE80211_RADIOTAP_TSFT              u64       microseconds
+ * IEEE80211_RADIOTAP_TSFT              __le64       microseconds
  *
  *      Value in microseconds of the MAC's 64-bit 802.11 Time
  *      Synchronization Function timer when the first bit of the
  *      MPDU arrived at the MAC. For received frames, only.
  *
- * IEEE80211_RADIOTAP_CHANNEL           2 x u16   MHz, bitmap
+ * IEEE80211_RADIOTAP_CHANNEL           2 x __le16   MHz, bitmap
  *
  *      Tx/Rx frequency in MHz, followed by flags (see below).
  *
- * IEEE80211_RADIOTAP_FHSS              u16       see below
+ * IEEE80211_RADIOTAP_FHSS              __le16       see below
  *
  *      For frequency-hopping radios, the hop set (first byte)
  *      and pattern (second byte).
  *
- * IEEE80211_RADIOTAP_RATE              u8        500kb/s
+ * IEEE80211_RADIOTAP_RATE              u8           500kb/s
  *
  *      Tx/Rx data rate
  *
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     int8_t          decibels from
- *                                                      one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     s8           decibels from
+ *                                                   one milliwatt (dBm)
  *
  *      RF signal power at the antenna, decibel difference from
  *      one milliwatt.
  *
- * IEEE80211_RADIOTAP_DBM_ANTNOISE      int8_t          decibels from
- *                                                      one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE      s8           decibels from
+ *                                                   one milliwatt (dBm)
  *
  *      RF noise power at the antenna, decibel difference from one
  *      milliwatt.
  *
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL      u8        decibel (dB)
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL      u8           decibel (dB)
  *
  *      RF signal power at the antenna, decibel difference from an
  *      arbitrary, fixed reference.
  *
- * IEEE80211_RADIOTAP_DB_ANTNOISE       u8        decibel (dB)
+ * IEEE80211_RADIOTAP_DB_ANTNOISE       u8           decibel (dB)
  *
  *      RF noise power at the antenna, decibel difference from an
  *      arbitrary, fixed reference point.
  *
- * IEEE80211_RADIOTAP_LOCK_QUALITY      u16       unitless
+ * IEEE80211_RADIOTAP_LOCK_QUALITY      __le16       unitless
  *
  *      Quality of Barker code lock. Unitless. Monotonically
  *      nondecreasing with "better" lock strength. Called "Signal
  *      Quality" in datasheets.  (Is there a standard way to measure
  *      this?)
  *
- * IEEE80211_RADIOTAP_TX_ATTENUATION    u16       unitless
+ * IEEE80211_RADIOTAP_TX_ATTENUATION    __le16       unitless
  *
  *      Transmit power expressed as unitless distance from max
  *      power set at factory calibration.  0 is max power.
  *      Monotonically nondecreasing with lower power levels.
  *
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u16       decibels (dB)
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16       decibels (dB)
  *
  *      Transmit power expressed as decibel distance from max power
  *      set at factory calibration.  0 is max power.  Monotonically
  *      nondecreasing with lower power levels.
  *
- * IEEE80211_RADIOTAP_DBM_TX_POWER      int8_t          decibels from
- *                                                      one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_TX_POWER      s8           decibels from
+ *                                                   one milliwatt (dBm)
  *
  *      Transmit power expressed as dBm (decibels from a 1 milliwatt
  *      reference). This is the absolute power level measured at
  *      the antenna port.
  *
- * IEEE80211_RADIOTAP_FLAGS             u8        bitmap
+ * IEEE80211_RADIOTAP_FLAGS             u8           bitmap
  *
  *      Properties of transmitted and received frames. See flags
  *      defined below.
  *
- * IEEE80211_RADIOTAP_ANTENNA           u8        antenna index
+ * IEEE80211_RADIOTAP_ANTENNA           u8           antenna index
  *
  *      Unitless indication of the Rx/Tx antenna for this packet.
  *      The first antenna is antenna 0.
  *
- * IEEE80211_RADIOTAP_FCS              u32       data
+ * IEEE80211_RADIOTAP_RX_FLAGS          __le16       bitmap
+ *
+ *     Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS          __le16       bitmap
+ *
+ *     Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES       u8           data
+ *
+ *     Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES      u8           data
+ *
+ *     Number of unicast retries a transmitted frame used.
  *
- *     FCS from frame in network byte order.
  */
 enum ieee80211_radiotap_type {
        IEEE80211_RADIOTAP_TSFT = 0,
@@ -187,7 +202,11 @@ enum ieee80211_radiotap_type {
        IEEE80211_RADIOTAP_ANTENNA = 11,
        IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
        IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
-       IEEE80211_RADIOTAP_EXT = 31,
+       IEEE80211_RADIOTAP_RX_FLAGS = 14,
+       IEEE80211_RADIOTAP_TX_FLAGS = 15,
+       IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+       IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+       IEEE80211_RADIOTAP_EXT = 31
 };
 
 /* Channel flags. */
@@ -219,6 +238,14 @@ enum ieee80211_radiotap_type {
                                                 * 802.11 header and payload
                                                 * (to 32-bit boundary)
                                                 */
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001  /* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL   0x0001  /* failed due to excessive
+                                                * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS    0x0002  /* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS    0x0004  /* used rts/cts handshake */
 
 /* Ugly macro to convert literal channel numbers into their mhz equivalents
  * There are certianly some conditions that will break this (like feeding it '30')
index bdb55a33f9691e2f79765eeba502d075f71d067c..9bd14fd3e6de5bcb5be171a8d3e8772a3a0cf91a 100644 (file)
@@ -212,27 +212,6 @@ int request_resource(struct resource *root, struct resource *new)
 
 EXPORT_SYMBOL(request_resource);
 
-/**
- * ____request_resource - reserve a resource, with resource conflict returned
- * @root: root resource descriptor
- * @new: resource descriptor desired by caller
- *
- * Returns:
- * On success, NULL is returned.
- * On error, a pointer to the conflicting resource is returned.
- */
-struct resource *____request_resource(struct resource *root, struct resource *new)
-{
-       struct resource *conflict;
-
-       write_lock(&resource_lock);
-       conflict = __request_resource(root, new);
-       write_unlock(&resource_lock);
-       return conflict;
-}
-
-EXPORT_SYMBOL(____request_resource);
-
 /**
  * release_resource - release a previously reserved resource
  * @old: resource pointer
index eb38849aa71702445e7e8e42744ad384fe512f48..b1d336ce7f3d0c34f694844c8bd7dfd0f1dc687d 100644 (file)
@@ -296,5 +296,31 @@ int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name)
        return rc;
 }
 EXPORT_SYMBOL(pcim_iomap_regions);
+
+/**
+ * pcim_iounmap_regions - Unmap and release PCI BARs
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to unmap and release
+ *
+ * Unamp and release regions specified by @mask.
+ */
+void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask)
+{
+       void __iomem * const *iomap;
+       int i;
+
+       iomap = pcim_iomap_table(pdev);
+       if (!iomap)
+               return;
+
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+               if (!(mask & (1 << i)))
+                       continue;
+
+               pcim_iounmap(pdev, iomap[i]);
+               pci_release_region(pdev, i);
+       }
+}
+EXPORT_SYMBOL(pcim_iounmap_regions);
 #endif
 #endif
index 5ed0a98b2d7680ae2d3a8b169a4e5664842b0444..df5592c9339fab3030e887dcd9cb3af76e14b0ac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Host AP crypto routines
  *
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
  *
  * This program is free software; you can redistribute it and/or modify
index 35aa3426c3fa2f34d176fb980dafd54e4c363891..b016b4104de6d4893ba0dae8546bc7f1347026af 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
  *
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -338,7 +338,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 
        if (ccmp_replay_check(pn, key->rx_pn)) {
                if (net_ratelimit()) {
-                       printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
+                       IEEE80211_DEBUG_DROP("CCMP: replay detected: STA=" MAC_FMT
                               " previous PN %02x%02x%02x%02x%02x%02x "
                               "received PN %02x%02x%02x%02x%02x%02x\n",
                               MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
index fc1f99a597327b7f80acd98d90e9650d78dc129c..5a48d8e0aec1a98a73761cfe9626d32c4fd47383 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
  *
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -465,7 +465,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 
        if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
                if (net_ratelimit()) {
-                       printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+                       IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=" MAC_FMT
                               " previous TSC %08x%04x received TSC "
                               "%08x%04x\n", MAC_ARG(hdr->addr2),
                               tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
@@ -507,7 +507,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
                        tkey->rx_phase1_done = 0;
                }
                if (net_ratelimit()) {
-                       printk(KERN_DEBUG "TKIP: ICV error detected: STA="
+                       IEEE80211_DEBUG_DROP("TKIP: ICV error detected: STA="
                               MAC_FMT "\n", MAC_ARG(hdr->addr2));
                }
                tkey->dot11RSNAStatsTKIPICVErrors++;
index 4eb35079e4347ead2a557fe19c994bfa445f9b04..8d182459344e9a94d7f992c97da3fae33e8a2e25 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Host AP crypt: host-based WEP encryption implementation for Host AP driver
  *
- * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
index b1c6d1f717d9e73a6ea43d93506cd26319c9b65d..7ec6610841bab68435cdba151ab2102ef15e1c53 100644 (file)
@@ -5,8 +5,8 @@
   Portions of this file are based on the WEP enablement code provided by the
   Host AP project hostap-drivers v0.1.3
   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
-  <jkmaline@cc.hut.fi>
-  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+  <j@w1.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
 
   This program is free software; you can redistribute it and/or modify it
   under the terms of version 2 of the GNU General Public License as
@@ -229,6 +229,7 @@ void free_ieee80211(struct net_device *dev)
 
 static int debug = 0;
 u32 ieee80211_debug_level = 0;
+EXPORT_SYMBOL_GPL(ieee80211_debug_level);
 static struct proc_dir_entry *ieee80211_proc = NULL;
 
 static int show_debug_level(char *page, char **start, off_t offset,
index 6ae036b1920f279e6139f5a7fd082a1f9b8a9c9e..f2de2e48b021cc960417cd330f8e9a72a648cc5c 100644 (file)
@@ -3,8 +3,8 @@
  * for Intersil Prism2/2.5/3 - hostap.o module, common routines
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2004-2005, Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
index 40d7a55fe03e8158d49b85e8dd18da705cf3250f..cee5e13bc4270687f76cea2330543f3d373930c7 100644 (file)
@@ -5,8 +5,8 @@
   Portions of this file are based on the WEP enablement code provided by the
   Host AP project hostap-drivers v0.1.3
   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
-  <jkmaline@cc.hut.fi>
-  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+  <j@w1.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
 
   This program is free software; you can redistribute it and/or modify it
   under the terms of version 2 of the GNU General Public License as
index b00fc4842c9327ecf0bf9a82bf5e24596b8b1937..7f980be5d0606d0f9783412301b9986164c6f808 100644 (file)
@@ -1062,9 +1062,9 @@ static int onyx_i2c_attach(struct i2c_adapter *adapter)
 
        while ((dev = of_get_next_child(busnode, dev)) != NULL) {
                if (device_is_compatible(dev, "pcm3052")) {
-                       u32 *addr;
+                       const u32 *addr;
                        printk(KERN_DEBUG PFX "found pcm3052\n");
-                       addr = (u32 *) get_property(dev, "reg", NULL);
+                       addr = of_get_property(dev, "reg", NULL);
                        if (!addr)
                                return -ENODEV;
                        return onyx_create(adapter, dev, (*addr)>>1);
index 2cd81fa07ce100b2e12b3ba89425457845270b42..ceca38486eae7d4a54797f981ff383e150e6a27b 100644 (file)
@@ -939,9 +939,9 @@ static int tas_i2c_attach(struct i2c_adapter *adapter)
 
        while ((dev = of_get_next_child(busnode, dev)) != NULL) {
                if (device_is_compatible(dev, "tas3004")) {
-                       u32 *addr;
+                       const u32 *addr;
                        printk(KERN_DEBUG PFX "found tas3004\n");
-                       addr = (u32 *) get_property(dev, "reg", NULL);
+                       addr = of_get_property(dev, "reg", NULL);
                        if (!addr)
                                continue;
                        return tas_create(adapter, dev, ((*addr) >> 1) & 0x7f);
@@ -950,9 +950,10 @@ static int tas_i2c_attach(struct i2c_adapter *adapter)
                 * property that says 'tas3004', they just have a 'deq'
                 * node without any such property... */
                if (strcmp(dev->name, "deq") == 0) {
-                       u32 *_addr, addr;
+                       const u32 *_addr;
+                       u32 addr;
                        printk(KERN_DEBUG PFX "found 'deq' node\n");
-                       _addr = (u32 *) get_property(dev, "i2c-address", NULL);
+                       _addr = of_get_property(dev, "i2c-address", NULL);
                        if (!_addr)
                                continue;
                        addr = ((*_addr) >> 1) & 0x7f;
index 2b03bc798bcb784a11b61a34c9d52045db8fdd52..805dcbff22572c79748783b0ee6ae4022ed3e1f8 100644 (file)
@@ -55,7 +55,7 @@ static struct device_node *get_gpio(char *name,
                                    int *gpioactiveptr)
 {
        struct device_node *np, *gpio;
-       u32 *reg;
+       const u32 *reg;
        const char *audio_gpio;
 
        *gpioptr = -1;
@@ -71,7 +71,7 @@ static struct device_node *get_gpio(char *name,
                if (!gpio)
                        return NULL;
                while ((np = of_get_next_child(gpio, np))) {
-                       audio_gpio = get_property(np, "audio-gpio", NULL);
+                       audio_gpio = of_get_property(np, "audio-gpio", NULL);
                        if (!audio_gpio)
                                continue;
                        if (strcmp(audio_gpio, name) == 0)
@@ -84,7 +84,7 @@ static struct device_node *get_gpio(char *name,
                        return NULL;
        }
 
-       reg = (u32 *)get_property(np, "reg", NULL);
+       reg = of_get_property(np, "reg", NULL);
        if (!reg)
                return NULL;
 
@@ -96,7 +96,7 @@ static struct device_node *get_gpio(char *name,
        if (*gpioptr < 0x50)
                *gpioptr += 0x50;
 
-       reg = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
+       reg = of_get_property(np, "audio-gpio-active-state", NULL);
        if (!reg)
                /* Apple seems to default to 1, but
                 * that doesn't seem right at least on most
index 1b94ba6dd2798a6f207534462ee1c8fcad1217a8..98806283d1b2d3682353d915bcb0ddd2ff32aec4 100644 (file)
@@ -724,7 +724,7 @@ static int check_codec(struct aoa_codec *codec,
                       struct layout_dev *ldev,
                       struct codec_connect_info *cci)
 {
-       u32 *ref;
+       const u32 *ref;
        char propname[32];
        struct codec_connection *cc;
 
@@ -732,7 +732,7 @@ static int check_codec(struct aoa_codec *codec,
        if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
                snprintf(propname, sizeof(propname),
                         "platform-%s-codec-ref", codec->name);
-               ref = (u32*)get_property(ldev->sound, propname, NULL);
+               ref = of_get_property(ldev->sound, propname, NULL);
                if (!ref) {
                        printk(KERN_INFO "snd-aoa-fabric-layout: "
                                "required property %s not present\n", propname);
@@ -946,7 +946,7 @@ static struct aoa_fabric layout_fabric = {
 static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
 {
        struct device_node *sound = NULL;
-       unsigned int *layout_id;
+       const unsigned int *layout_id;
        struct layout *layout;
        struct layout_dev *ldev = NULL;
        int err;
@@ -962,7 +962,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
        }
        if (!sound) return -ENODEV;
 
-       layout_id = (unsigned int *) get_property(sound, "layout-id", NULL);
+       layout_id = of_get_property(sound, "layout-id", NULL);
        if (!layout_id)
                goto outnodev;
        printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n",
index 418a98a10c73b0548bebdb958be82b2e3f927a2a..8b2e9b905cda8271f15355baeff04364cf3fc564 100644 (file)
@@ -61,7 +61,7 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
 {
        struct soundbus_dev * soundbus_dev;
        struct of_device * of;
-       char *compat;
+       const char *compat;
        int retval = 0, i = 0, length = 0;
        int cplen, seen = 0;
 
@@ -91,7 +91,7 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
         * it's not really legal to split it out with commas. We split it
         * up using a number of environment variables instead. */
 
-       compat = (char *) get_property(of->node, "compatible", &cplen);
+       compat = of_get_property(of->node, "compatible", &cplen);
        while (compat && cplen > 0) {
                int tmp = length;
                retval = add_uevent_var(envp, num_envp, &i,
index e36f6aa448d46594694c6383a80af504135b3cab..79fc4bc09e5e0e8de5a5b73f068324e4de6cd109 100644 (file)
@@ -122,7 +122,7 @@ static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
 {
        struct device_node *parent;
        int pindex, rc = -ENXIO;
-       u32 *reg;
+       const u32 *reg;
 
        /* Machines with layout 76 and 36 (K2 based) have a weird device
         * tree what we need to special case.
@@ -141,7 +141,7 @@ static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
        rc = of_address_to_resource(parent, pindex, res);
        if (rc)
                goto bail;
-       reg = (u32 *)get_property(np, "reg", NULL);
+       reg = of_get_property(np, "reg", NULL);
        if (reg == NULL) {
                rc = -ENXIO;
                goto bail;
@@ -188,8 +188,8 @@ static int i2sbus_add_dev(struct macio_dev *macio,
                }
        }
        if (i == 1) {
-               u32 *layout_id;
-               layout_id = (u32*) get_property(sound, "layout-id", NULL);
+               const u32 *layout_id =
+                       of_get_property(sound, "layout-id", NULL);
                if (layout_id) {
                        layout = *layout_id;
                        snprintf(dev->sound.modalias, 32,
index 37773b1deea51e25e4d864fb405ab75528bca756..730fa1d001a5c7b366ef6814475f833319f93a9d 100644 (file)
@@ -257,7 +257,7 @@ static volatile struct dbdma_cmd *emergency_dbdma_cmd;
 /*
  * Stuff for restoring after a sleep.
  */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
 struct pmu_sleep_notifier awacs_sleep_notifier = {
        awacs_sleep_notify, SLEEP_LEVEL_SOUND,
 };
@@ -346,36 +346,42 @@ int gpio_headphone_irq;
 int
 setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol)
 {
+       struct device_node *gpiop;
        struct device_node *np;
        const u32* pp;
+       int ret = -ENODEV;
 
-       np = find_devices("gpio");
-       if (!np)
-               return -ENODEV;
+       gpiop = of_find_node_by_name(NULL, "gpio");
+       if (!gpiop)
+               goto done;
 
-       np = np->child;
+       np = of_get_next_child(gpiop, NULL);
        while(np != 0) {
                if (name) {
                        const char *property =
-                               get_property(np,"audio-gpio",NULL);
+                               of_get_property(np,"audio-gpio",NULL);
                        if (property != 0 && strcmp(property,name) == 0)
                                break;
                } else if (compatible && device_is_compatible(np, compatible))
                        break;
-               np = np->sibling;
+               np = of_get_next_child(gpiop, np);
        }
        if (!np)
-               return -ENODEV;
-       pp = get_property(np, "AAPL,address", NULL);
+               goto done;
+       pp = of_get_property(np, "AAPL,address", NULL);
        if (!pp)
-               return -ENODEV;
+               goto done;
        *gpio_addr = (*pp) & 0x0000ffff;
-       pp = get_property(np, "audio-gpio-active-state", NULL);
+       pp = of_get_property(np, "audio-gpio-active-state", NULL);
        if (pp)
                *gpio_pol = *pp;
        else
                *gpio_pol = 1;
-       return irq_of_parse_and_map(np, 0);
+       ret = irq_of_parse_and_map(np, 0);
+done:
+       of_node_put(np);
+       of_node_put(gpiop);
+       return ret;
 }
 
 static inline void
@@ -578,7 +584,7 @@ tas_mixer_ioctl(u_int cmd, u_long arg)
 }
 
 static void __init
-tas_init_frame_rates(unsigned int *prop, unsigned int l)
+tas_init_frame_rates(const unsigned int *prop, unsigned int l)
 {
        int i ;
        if (prop) {
@@ -1419,7 +1425,7 @@ load_awacs(void)
  * Save state when going to sleep, restore it afterwards.
  */
 /* FIXME: sort out disabling/re-enabling of read stuff as well */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
+static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
 {
        unsigned long flags;
 
@@ -1548,7 +1554,6 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
                spin_unlock_irqrestore(&dmasound.lock, flags);
                UNLOCK();
        }
-       return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PM */
 
@@ -2553,32 +2558,33 @@ set_model(void)
 static struct device_node* __init
 get_snd_io_node(void)
 {
-       struct device_node *np = NULL;
+       struct device_node *np;
 
        /* set up awacs_node for early OF which doesn't have a full set of
         * properties on davbus
-       */
-
-       awacs_node = find_devices("awacs");
+        */
+       awacs_node = of_find_node_by_name(NULL, "awacs");
        if (awacs_node)
                awacs_revision = AWACS_AWACS;
 
        /* powermac models after 9500 (other than those which use DACA or
         * Tumbler) have a node called "davbus".
         */
-       np = find_devices("davbus");
+       np = of_find_node_by_name(NULL, "davbus");
        /*
         * if we didn't find a davbus device, try 'i2s-a' since
         * this seems to be what iBooks (& Tumbler) have.
         */
-       if (np == NULL)
-               np = i2s_node = find_devices("i2s-a");
+       if (np == NULL) {
+               i2s_node = of_find_node_by_name(NULL, "i2s-a");
+               np = of_node_get(i2s_node);
+       }
 
        /* if we didn't find this - perhaps we are on an early model
         * which _only_ has an 'awacs' node
        */
        if (np == NULL && awacs_node)
-               np = awacs_node ;
+               np = of_node_get(awacs_node);
 
        /* if we failed all these return null - this will cause the
         * driver to give up...
@@ -2597,9 +2603,9 @@ get_snd_info_node(struct device_node *io)
 {
        struct device_node *info;
 
-       info = find_devices("sound");
-       while (info && info->parent != io)
-               info = info->next;
+       for_each_node_by_name(info, "sound")
+               if (info->parent == io)
+                       break;
        return info;
 }
 
@@ -2635,11 +2641,17 @@ get_codec_type(struct device_node *info)
 static void __init
 get_expansion_type(void)
 {
-       if (find_devices("perch") != NULL)
+       struct device_node *dn;
+
+       dn = of_find_node_by_name(NULL, "perch");
+       if (dn != NULL)
                has_perch = 1;
+       of_node_put(dn);
 
-       if (find_devices("pb-ziva-pc") != NULL)
+       dn = of_find_node_by_name(NULL, "pb-ziva-pc");
+       if (dn != NULL)
                has_ziva = 1;
+       of_node_put(dn);
        /* need to work out how we deal with iMac SRS module */
 }
 
@@ -2652,7 +2664,7 @@ get_expansion_type(void)
 */
 
 static void __init
-awacs_init_frame_rates(unsigned int *prop, unsigned int l)
+awacs_init_frame_rates(const unsigned int *prop, unsigned int l)
 {
        int i ;
        if (prop) {
@@ -2675,7 +2687,7 @@ awacs_init_frame_rates(unsigned int *prop, unsigned int l)
 }
 
 static void __init
-burgundy_init_frame_rates(unsigned int *prop, unsigned int l)
+burgundy_init_frame_rates(const unsigned int *prop, unsigned int l)
 {
        int temp[9] ;
        int i = 0 ;
@@ -2701,7 +2713,7 @@ if (i > 1){
 }
 
 static void __init
-daca_init_frame_rates(unsigned int *prop, unsigned int l)
+daca_init_frame_rates(const unsigned int *prop, unsigned int l)
 {
        int temp[9] ;
        int i = 0 ;
@@ -2728,7 +2740,7 @@ if (i > 1){
 }
 
 static void __init
-init_frame_rates(unsigned int *prop, unsigned int l)
+init_frame_rates(const unsigned int *prop, unsigned int l)
 {
        switch (awacs_revision) {
                case AWACS_TUMBLER:
@@ -2828,7 +2840,7 @@ int __init dmasound_awacs_init(void)
 #ifdef DEBUG_DMASOUND
 printk("dmasound_pmac: couldn't find sound io OF node\n");
 #endif
-               return -ENODEV ;
+               goto no_device;
        }
 
        /* find the OF node that tells us about the sound sub-system
@@ -2840,7 +2852,7 @@ printk("dmasound_pmac: couldn't find sound io OF node\n");
 #ifdef DEBUG_DMASOUND
 printk("dmasound_pmac: couldn't find 'sound' OF node\n");
 #endif
-                       return -ENODEV ;
+                       goto no_device;
                }
        }
 
@@ -2849,7 +2861,7 @@ printk("dmasound_pmac: couldn't find 'sound' OF node\n");
 #ifdef DEBUG_DMASOUND
 printk("dmasound_pmac: couldn't find a Codec we can handle\n");
 #endif
-               return -ENODEV ; /* we don't know this type of h/w */
+               goto no_device; /* we don't know this type of h/w */
        }
 
        /* set up perch, ziva, SRS or whatever else we have as sound
@@ -2867,11 +2879,12 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
                 * machines).
                 */
                if (awacs_node) {
-                       io = awacs_node ;
+                       of_node_put(io);
+                       io = of_node_get(awacs_node);
                        if (of_get_address(io, 2, NULL, NULL) == NULL) {
                                printk("dmasound_pmac: can't use %s\n",
                                       io->full_name);
-                               return -ENODEV;
+                               goto no_device;
                        }
                } else
                        printk("dmasound_pmac: can't use %s\n", io->full_name);
@@ -2882,7 +2895,7 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
                               awacs_rsrc[0].end - awacs_rsrc[0].start + 1,
                               " (IO)") == NULL) {
                printk(KERN_ERR "dmasound: can't request IO resource !\n");
-               return -ENODEV;
+               goto no_device;
        }
        if (of_address_to_resource(io, 1, &awacs_rsrc[1]) ||
            request_mem_region(awacs_rsrc[1].start,
@@ -2891,7 +2904,7 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
                release_mem_region(awacs_rsrc[0].start,
                                   awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
                printk(KERN_ERR "dmasound: can't request Tx DMA resource !\n");
-               return -ENODEV;
+               goto no_device;
        }
        if (of_address_to_resource(io, 2, &awacs_rsrc[2]) ||
            request_mem_region(awacs_rsrc[2].start,
@@ -2902,7 +2915,7 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
                release_mem_region(awacs_rsrc[1].start,
                                   awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
                printk(KERN_ERR "dmasound: can't request Rx DMA resource !\n");
-               return -ENODEV;
+               goto no_device;
        }
 
        awacs_beep_dev = input_allocate_device();
@@ -2914,7 +2927,7 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
                release_mem_region(awacs_rsrc[2].start,
                                   awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
                printk(KERN_ERR "dmasound: can't allocate input device !\n");
-               return -ENOMEM;
+               goto no_device;
        }
 
        awacs_beep_dev->name = "dmasound beeper";
@@ -2942,7 +2955,8 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
        awacs_rx_irq = irq_of_parse_and_map(io, 2);
 
        /* Hack for legacy crap that will be killed someday */
-       awacs_node = io;
+       of_node_put(awacs_node);
+       awacs_node = of_node_get(io);
 
        /* if we have an awacs or screamer - probe the chip to make
         * sure we have the right revision.
@@ -2973,24 +2987,26 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
        */
 
        if (info) {
-               unsigned int *prop, l;
+               const unsigned int *prop;
+               unsigned int l;
 
                sound_device_id = 0;
                /* device ID appears post g3 b&w */
-               prop = (unsigned int *)get_property(info, "device-id", NULL);
+               prop = of_get_property(info, "device-id", NULL);
                if (prop != 0)
                        sound_device_id = *prop;
 
                /* look for a property saying what sample rates
                   are available */
 
-               prop = (unsigned int *)get_property(info, "sample-rates", &l);
+               prop = of_get_property(info, "sample-rates", &l);
                if (prop == 0)
-                       prop = (unsigned int *) get_property
-                               (info, "output-frame-rates", &l);
+                       prop = of_get_property(info, "output-frame-rates", &l);
 
                /* if it's there use it to set up frame rates */
                init_frame_rates(prop, l) ;
+               of_node_put(info);
+               info = NULL;
        }
 
        if (awacs)
@@ -3160,7 +3176,16 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
         */
        input_register_device(awacs_beep_dev);
 
+       of_node_put(io);
+
        return dmasound_init();
+
+no_device:
+       of_node_put(info);
+       of_node_put(awacs_node);
+       of_node_put(i2s_node);
+       of_node_put(io);
+       return -ENODEV ;
 }
 
 static void __exit dmasound_awacs_cleanup(void)
@@ -3179,6 +3204,8 @@ static void __exit dmasound_awacs_cleanup(void)
        }
        dmasound_deinit();
 
+       of_node_put(awacs_node);
+       of_node_put(i2s_node);
 }
 
 MODULE_DESCRIPTION("PowerMac built-in audio driver.");
index 665e85b5562bd56785494bbfbd428b9459afaa5a..b295ef6821928b40764a1370e9bbbc4849c08d1a 100644 (file)
@@ -41,7 +41,6 @@
 
 static u8 tas_i2c_address = 0x34;
 static struct i2c_client *tas_client;
-static struct device_node* tas_node;
 
 static int tas_attach_adapter(struct i2c_adapter *);
 static int tas_detach_client(struct i2c_client *);
@@ -190,17 +189,18 @@ tas_cleanup(void)
 int __init
 tas_init(int driver_id, const char *driver_name)
 {
-       u32* paddr;
+       const u32* paddr;
+       struct device_node *tas_node;
 
        printk(KERN_INFO "tas driver [%s])\n", driver_name);
 
 #ifndef CONFIG_I2C_POWERMAC
        request_module("i2c-powermac");
 #endif
-       tas_node = find_devices("deq");
+       tas_node = of_find_node_by_name("deq");
        if (tas_node == NULL)
                return -ENODEV;
-       paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
+       paddr = of_get_property(tas_node, "i2c-address", NULL);
        if (paddr) {
                tas_i2c_address = (*paddr) >> 1;
                printk(KERN_INFO "using i2c address: 0x%x from device-tree\n",
@@ -208,6 +208,7 @@ tas_init(int driver_id, const char *driver_name)
        } else    
                printk(KERN_INFO "using i2c address: 0x%x (default)\n",
                                tas_i2c_address);
+       of_node_put(tas_node);
 
        return i2c_add_driver(&tas_driver);
 }
index c64af55865d492851e6f8b803532b8f3b36b9ac7..2bae9c1a2b54b9daa134a9765a99d8eec035bb87 100644 (file)
@@ -816,6 +816,7 @@ static int snd_pmac_free(struct snd_pmac *chip)
 
        if (chip->pdev)
                pci_dev_put(chip->pdev);
+       of_node_put(chip->node);
        kfree(chip);
        return 0;
 }
@@ -863,8 +864,10 @@ static void __init detect_byte_swap(struct snd_pmac *chip)
  */
 static int __init snd_pmac_detect(struct snd_pmac *chip)
 {
-       struct device_node *sound = NULL;
-       unsigned int *prop, l;
+       struct device_node *sound;
+       struct device_node *dn;
+       const unsigned int *prop;
+       unsigned int l;
        struct macio_chip* macio;
 
        if (!machine_is(powermac))
@@ -890,22 +893,21 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
        else if (machine_is_compatible("PowerBook1,1")
                 || machine_is_compatible("AAPL,PowerBook1998"))
                chip->is_pbook_G3 = 1;
-       chip->node = find_devices("awacs");
-       if (chip->node)
-               sound = chip->node;
+       chip->node = of_find_node_by_name(NULL, "awacs");
+       sound = of_node_get(chip->node);
 
        /*
         * powermac G3 models have a node called "davbus"
         * with a child called "sound".
         */
        if (!chip->node)
-               chip->node = find_devices("davbus");
+               chip->node = of_find_node_by_name(NULL, "davbus");
        /*
         * if we didn't find a davbus device, try 'i2s-a' since
         * this seems to be what iBooks have
         */
        if (! chip->node) {
-               chip->node = find_devices("i2s-a");
+               chip->node = of_find_node_by_name(NULL, "i2s-a");
                if (chip->node && chip->node->parent &&
                    chip->node->parent->parent) {
                        if (device_is_compatible(chip->node->parent->parent,
@@ -917,22 +919,25 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
                return -ENODEV;
 
        if (!sound) {
-               sound = find_devices("sound");
+               sound = of_find_node_by_name(NULL, "sound");
                while (sound && sound->parent != chip->node)
-                       sound = sound->next;
+                       sound = of_find_node_by_name(sound, "sound");
        }
-       if (! sound)
+       if (! sound) {
+               of_node_put(chip->node);
                return -ENODEV;
-       prop = (unsigned int *) get_property(sound, "sub-frame", NULL);
+       }
+       prop = of_get_property(sound, "sub-frame", NULL);
        if (prop && *prop < 16)
                chip->subframe = *prop;
-       prop = (unsigned int *) get_property(sound, "layout-id", NULL);
+       prop = of_get_property(sound, "layout-id", NULL);
        if (prop) {
                /* partly deprecate snd-powermac, for those machines
                 * that have a layout-id property for now */
                printk(KERN_INFO "snd-powermac no longer handles any "
                                 "machines with a layout-id property "
                                 "in the device-tree, use snd-aoa.\n");
+               of_node_put(chip->node);
                return -ENODEV;
        }
        /* This should be verified on older screamers */
@@ -967,10 +972,12 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
                chip->freq_table = tumbler_freqs;
                chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
        }
-       prop = (unsigned int *)get_property(sound, "device-id", NULL);
+       prop = of_get_property(sound, "device-id", NULL);
        if (prop)
                chip->device_id = *prop;
-       chip->has_iic = (find_devices("perch") != NULL);
+       dn = of_find_node_by_name(NULL, "perch");
+       chip->has_iic = (dn != NULL);
+       of_node_put(dn);
 
        /* We need the PCI device for DMA allocations, let's use a crude method
         * for now ...
@@ -997,10 +1004,9 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
 
        /* look for a property saying what sample rates
           are available */
-       prop = (unsigned int *) get_property(sound, "sample-rates", &l);
+       prop = of_get_property(sound, "sample-rates", &l);
        if (! prop)
-               prop = (unsigned int *) get_property(sound,
-                                                    "output-frame-rates", &l);
+               prop = of_get_property(sound, "output-frame-rates", &l);
        if (prop) {
                int i;
                chip->freqs_ok = 0;
@@ -1021,6 +1027,7 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
                chip->freqs_ok = 1;
        }
 
+       of_node_put(sound);
        return 0;
 }
 
index 8f074c7936e67870329a12b7c9069a346d99fe1f..54e333fbb1d06e0710cb7a1ece09eccd2bb416d5 100644 (file)
@@ -1031,32 +1031,40 @@ static irqreturn_t headphone_intr(int irq, void *devid)
 /* look for audio-gpio device */
 static struct device_node *find_audio_device(const char *name)
 {
+       struct device_node *gpiop;
        struct device_node *np;
   
-       if (! (np = find_devices("gpio")))
+       gpiop = of_find_node_by_name(NULL, "gpio");
+       if (! gpiop)
                return NULL;
   
-       for (np = np->child; np; np = np->sibling) {
-               const char *property = get_property(np, "audio-gpio", NULL);
+       for (np = of_get_next_child(gpiop, NULL); np;
+                       np = of_get_next_child(gpiop, np)) {
+               const char *property = of_get_property(np, "audio-gpio", NULL);
                if (property && strcmp(property, name) == 0)
-                       return np;
+                       break;
        }  
-       return NULL;
+       of_node_put(gpiop);
+       return np;
 }
 
 /* look for audio-gpio device */
 static struct device_node *find_compatible_audio_device(const char *name)
 {
+       struct device_node *gpiop;
        struct device_node *np;
   
-       if (! (np = find_devices("gpio")))
+       gpiop = of_find_node_by_name(NULL, "gpio");
+       if (!gpiop)
                return NULL;
   
-       for (np = np->child; np; np = np->sibling) {
+       for (np = of_get_next_child(gpiop, NULL); np;
+                       np = of_get_next_child(gpiop, np)) {
                if (device_is_compatible(np, name))
-                       return np;
+                       break;
        }  
-       return NULL;
+       of_node_put(gpiop);
+       return np;
 }
 
 /* find an audio device and get its address */
@@ -1066,6 +1074,7 @@ static long tumbler_find_device(const char *device, const char *platform,
        struct device_node *node;
        const u32 *base;
        u32 addr;
+       long ret;
 
        if (is_compatible)
                node = find_compatible_audio_device(device);
@@ -1077,12 +1086,13 @@ static long tumbler_find_device(const char *device, const char *platform,
                return -ENODEV;
        }
 
-       base = get_property(node, "AAPL,address", NULL);
+       base = of_get_property(node, "AAPL,address", NULL);
        if (! base) {
-               base = get_property(node, "reg", NULL);
+               base = of_get_property(node, "reg", NULL);
                if (!base) {
                        DBG("(E) cannot find address for device %s !\n", device);
                        snd_printd("cannot find address for device %s\n", device);
+                       of_node_put(node);
                        return -ENODEV;
                }
                addr = *base;
@@ -1093,7 +1103,7 @@ static long tumbler_find_device(const char *device, const char *platform,
 
        gp->addr = addr & 0x0000ffff;
        /* Try to find the active state, default to 0 ! */
-       base = get_property(node, "audio-gpio-active-state", NULL);
+       base = of_get_property(node, "audio-gpio-active-state", NULL);
        if (base) {
                gp->active_state = *base;
                gp->active_val = (*base) ? 0x5 : 0x4;
@@ -1108,7 +1118,7 @@ static long tumbler_find_device(const char *device, const char *platform,
                 * as we don't yet have an interpreter for these things
                 */
                if (platform)
-                       prop = get_property(node, platform, NULL);
+                       prop = of_get_property(node, platform, NULL);
                if (prop) {
                        if (prop[3] == 0x9 && prop[4] == 0x9) {
                                gp->active_val = 0xd;
@@ -1124,7 +1134,9 @@ static long tumbler_find_device(const char *device, const char *platform,
        DBG("(I) GPIO device %s found, offset: %x, active state: %d !\n",
            device, gp->addr, gp->active_state);
 
-       return irq_of_parse_and_map(node, 0);
+       ret = irq_of_parse_and_map(node, 0);
+       of_node_put(node);
+       return ret;
 }
 
 /* reset audio */
@@ -1310,7 +1322,7 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
 {
        int i, err;
        struct pmac_tumbler *mix;
-       u32 *paddr;
+       const u32 *paddr;
        struct device_node *tas_node, *np;
        char *chipname;
 
@@ -1331,9 +1343,9 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
 
        for (np = chip->node->child; np; np = np->sibling) {
                if (!strcmp(np->name, "sound")) {
-                       if (get_property(np, "has-anded-reset", NULL))
+                       if (of_get_property(np, "has-anded-reset", NULL))
                                mix->anded_reset = 1;
-                       if (get_property(np, "layout-id", NULL))
+                       if (of_get_property(np, "layout-id", NULL))
                                mix->reset_on_sleep = 0;
                        break;
                }
@@ -1342,19 +1354,20 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
                return err;
 
        /* set up TAS */
-       tas_node = find_devices("deq");
+       tas_node = of_find_node_by_name(NULL, "deq");
        if (tas_node == NULL)
-               tas_node = find_devices("codec");
+               tas_node = of_find_node_by_name(NULL, "codec");
        if (tas_node == NULL)
                return -ENODEV;
 
-       paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
+       paddr = of_get_property(tas_node, "i2c-address", NULL);
        if (paddr == NULL)
-               paddr = (u32 *)get_property(tas_node, "reg", NULL);
+               paddr = of_get_property(tas_node, "reg", NULL);
        if (paddr)
                mix->i2c.addr = (*paddr) >> 1;
        else
                mix->i2c.addr = TAS_I2C_ADDR;
+       of_node_put(tas_node);
 
        DBG("(I) TAS i2c address is: %x\n", mix->i2c.addr);