aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/kernel-api.tmpl6
-rw-r--r--Documentation/kernel-parameters.txt32
-rw-r--r--Documentation/networking/bcm43xx.txt97
-rw-r--r--Documentation/powerpc/booting-without-of.txt256
-rw-r--r--Documentation/sony-laptop.txt25
-rw-r--r--Documentation/thinkpad-acpi.txt (renamed from Documentation/ibm-acpi.txt)585
-rw-r--r--Documentation/video4linux/meye.txt7
-rw-r--r--MAINTAINERS38
-rw-r--r--arch/i386/defconfig1
-rw-r--r--arch/i386/kernel/acpi/earlyquirk.c5
-rw-r--r--arch/mips/mips-boards/sim/Makefile3
-rw-r--r--arch/mips/mips-boards/sim/sim_platform.c35
-rw-r--r--arch/parisc/configs/c3000_defconfig1
-rw-r--r--arch/powerpc/Kconfig472
-rw-r--r--arch/powerpc/Kconfig.debug12
-rw-r--r--arch/powerpc/Makefile11
-rw-r--r--arch/powerpc/boot/.gitignore3
-rw-r--r--arch/powerpc/boot/Makefile122
-rw-r--r--arch/powerpc/boot/crt0.S37
-rw-r--r--arch/powerpc/boot/cuboot-83xx.c68
-rw-r--r--arch/powerpc/boot/cuboot-85xx.c69
-rw-r--r--arch/powerpc/boot/devtree.c307
-rw-r--r--arch/powerpc/boot/dts/kuroboxHD.dts7
-rw-r--r--arch/powerpc/boot/dts/kuroboxHG.dts7
-rw-r--r--arch/powerpc/boot/dts/lite5200.dts1
-rw-r--r--arch/powerpc/boot/dts/lite5200b.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc7448hpc2.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8272ads.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8313erdb.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc832x_mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc832x_rdb.dts291
-rw-r--r--arch/powerpc/boot/dts/mpc8349emitx.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8349emitxgp.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc834x_mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc836x_mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8540ads.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8541cds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8544ds.dts136
-rw-r--r--arch/powerpc/boot/dts/mpc8548cds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8555cds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8560ads.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8568mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8641_hpcn.dts25
-rw-r--r--arch/powerpc/boot/dts/mpc866ads.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc885ads.dts1
-rw-r--r--arch/powerpc/boot/elf.h8
-rw-r--r--arch/powerpc/boot/elf_util.c76
-rw-r--r--arch/powerpc/boot/flatdevtree.c199
-rw-r--r--arch/powerpc/boot/flatdevtree.h7
-rw-r--r--arch/powerpc/boot/flatdevtree_misc.c42
-rw-r--r--arch/powerpc/boot/gunzip_util.c206
-rw-r--r--arch/powerpc/boot/gunzip_util.h45
-rw-r--r--arch/powerpc/boot/main.c369
-rw-r--r--arch/powerpc/boot/ns16550.c9
-rw-r--r--arch/powerpc/boot/of.c21
-rw-r--r--arch/powerpc/boot/ops.h103
-rw-r--r--arch/powerpc/boot/ppcboot.h108
-rw-r--r--arch/powerpc/boot/reg.h22
-rw-r--r--arch/powerpc/boot/simple_alloc.c31
-rw-r--r--arch/powerpc/boot/stdio.h5
-rwxr-xr-xarch/powerpc/boot/wrapper53
-rw-r--r--arch/powerpc/boot/zImage.coff.lds.S3
-rw-r--r--arch/powerpc/boot/zImage.lds.S1
-rw-r--r--arch/powerpc/configs/cell_defconfig57
-rw-r--r--arch/powerpc/configs/g5_defconfig2
-rw-r--r--arch/powerpc/configs/maple_defconfig2
-rw-r--r--arch/powerpc/configs/mpc832x_rdb_defconfig1292
-rw-r--r--arch/powerpc/configs/mpc8544_ds_defconfig1077
-rw-r--r--arch/powerpc/configs/ppc64_defconfig2
-rw-r--r--arch/powerpc/kernel/Makefile4
-rw-r--r--arch/powerpc/kernel/align.c56
-rw-r--r--arch/powerpc/kernel/asm-offsets.c2
-rw-r--r--arch/powerpc/kernel/btext.c22
-rw-r--r--arch/powerpc/kernel/cpu_setup_pa6t.S2
-rw-r--r--arch/powerpc/kernel/cputable.c14
-rw-r--r--arch/powerpc/kernel/entry_32.S1
-rw-r--r--arch/powerpc/kernel/head_64.S16
-rw-r--r--arch/powerpc/kernel/ibmebus.c288
-rw-r--r--arch/powerpc/kernel/iommu.c35
-rw-r--r--arch/powerpc/kernel/irq.c2
-rw-r--r--arch/powerpc/kernel/kprobes.c36
-rw-r--r--arch/powerpc/kernel/legacy_serial.c24
-rw-r--r--arch/powerpc/kernel/lparcfg.c58
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c14
-rw-r--r--arch/powerpc/kernel/misc_32.S4
-rw-r--r--arch/powerpc/kernel/of_device.c112
-rw-r--r--arch/powerpc/kernel/of_platform.c5
-rw-r--r--arch/powerpc/kernel/pci_32.c42
-rw-r--r--arch/powerpc/kernel/pci_64.c32
-rw-r--r--arch/powerpc/kernel/pci_dn.c9
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c1
-rw-r--r--arch/powerpc/kernel/process.c54
-rw-r--r--arch/powerpc/kernel/prom.c167
-rw-r--r--arch/powerpc/kernel/prom_init.c55
-rw-r--r--arch/powerpc/kernel/prom_parse.c51
-rw-r--r--arch/powerpc/kernel/rtas-proc.c4
-rw-r--r--arch/powerpc/kernel/rtas.c19
-rw-r--r--arch/powerpc/kernel/rtas_pci.c14
-rw-r--r--arch/powerpc/kernel/setup-common.c68
-rw-r--r--arch/powerpc/kernel/setup_32.c17
-rw-r--r--arch/powerpc/kernel/setup_64.c11
-rw-r--r--arch/powerpc/kernel/smp.c4
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c4
-rw-r--r--arch/powerpc/kernel/sysfs.c17
-rw-r--r--arch/powerpc/kernel/time.c2
-rw-r--r--arch/powerpc/kernel/traps.c76
-rw-r--r--arch/powerpc/kernel/vio.c17
-rw-r--r--arch/powerpc/lib/copyuser_64.S6
-rw-r--r--arch/powerpc/lib/locks.c4
-rw-r--r--arch/powerpc/lib/mem_64.S6
-rw-r--r--arch/powerpc/lib/memcpy_64.S6
-rw-r--r--arch/powerpc/lib/sstep.c45
-rw-r--r--arch/powerpc/mm/hash_low_32.S22
-rw-r--r--arch/powerpc/mm/hash_low_64.S5
-rw-r--r--arch/powerpc/mm/hash_native_64.c2
-rw-r--r--arch/powerpc/mm/hash_utils_64.c127
-rw-r--r--arch/powerpc/mm/hugetlbpage.c16
-rw-r--r--arch/powerpc/mm/init_32.c4
-rw-r--r--arch/powerpc/mm/lmb.c4
-rw-r--r--arch/powerpc/mm/mem.c3
-rw-r--r--arch/powerpc/mm/mmu_decl.h5
-rw-r--r--arch/powerpc/mm/numa.c24
-rw-r--r--arch/powerpc/mm/pgtable_32.c76
-rw-r--r--arch/powerpc/mm/ppc_mmu_32.c4
-rw-r--r--arch/powerpc/mm/tlb_64.c68
-rw-r--r--arch/powerpc/oprofile/Makefile2
-rw-r--r--arch/powerpc/oprofile/common.c3
-rw-r--r--arch/powerpc/oprofile/op_model_cell.c3
-rw-r--r--arch/powerpc/oprofile/op_model_pa6t.c234
-rw-r--r--arch/powerpc/platforms/4xx/Kconfig372
-rw-r--r--arch/powerpc/platforms/52xx/Kconfig35
-rw-r--r--arch/powerpc/platforms/52xx/efika.c15
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c12
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_common.c2
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pci.c2
-rw-r--r--arch/powerpc/platforms/82xx/Kconfig45
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx.c6
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx_ads.c12
-rw-r--r--arch/powerpc/platforms/83xx/Kconfig15
-rw-r--r--arch/powerpc/platforms/83xx/Makefile1
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.c1
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.h19
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_rdb.c138
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_itx.h23
-rw-r--r--arch/powerpc/platforms/83xx/pci.c2
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig38
-rw-r--r--arch/powerpc/platforms/85xx/Makefile1
-rw-r--r--arch/powerpc/platforms/85xx/mpc8544_ds.c144
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.c2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.c2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c2
-rw-r--r--arch/powerpc/platforms/85xx/pci.c2
-rw-r--r--arch/powerpc/platforms/86xx/Kconfig18
-rw-r--r--arch/powerpc/platforms/86xx/Makefile2
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_hpcn.c4
-rw-r--r--arch/powerpc/platforms/86xx/pci.c4
-rw-r--r--arch/powerpc/platforms/8xx/Kconfig67
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c8
-rw-r--r--arch/powerpc/platforms/8xx/mpc86xads.h2
-rw-r--r--arch/powerpc/platforms/8xx/mpc86xads_setup.c4
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads.h2
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads_setup.c4
-rw-r--r--arch/powerpc/platforms/Kconfig259
-rw-r--r--arch/powerpc/platforms/cell/Kconfig24
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq.c112
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c168
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.h5
-rw-r--r--arch/powerpc/platforms/cell/cbe_thermal.c181
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c4
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.c2
-rw-r--r--arch/powerpc/platforms/cell/iommu.c16
-rw-r--r--arch/powerpc/platforms/cell/ras.c160
-rw-r--r--arch/powerpc/platforms/cell/setup.c12
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c8
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c163
-rw-r--r--arch/powerpc/platforms/cell/spu_coredump.c34
-rw-r--r--arch/powerpc/platforms/cell/spu_manage.c18
-rw-r--r--arch/powerpc/platforms/cell/spufs/Makefile2
-rw-r--r--arch/powerpc/platforms/cell/spufs/backing_ops.c6
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c45
-rw-r--r--arch/powerpc/platforms/cell/spufs/coredump.c19
-rw-r--r--arch/powerpc/platforms/cell/spufs/fault.c211
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c152
-rw-r--r--arch/powerpc/platforms/cell/spufs/hw_ops.c9
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c44
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c123
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c113
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h34
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c8
-rw-r--r--arch/powerpc/platforms/celleb/Kconfig9
-rw-r--r--arch/powerpc/platforms/celleb/iommu.c6
-rw-r--r--arch/powerpc/platforms/celleb/pci.c18
-rw-r--r--arch/powerpc/platforms/celleb/setup.c12
-rw-r--r--arch/powerpc/platforms/chrp/Kconfig11
-rw-r--r--arch/powerpc/platforms/chrp/nvram.c2
-rw-r--r--arch/powerpc/platforms/chrp/pci.c25
-rw-r--r--arch/powerpc/platforms/chrp/setup.c52
-rw-r--r--arch/powerpc/platforms/chrp/time.c13
-rw-r--r--arch/powerpc/platforms/embedded6xx/Kconfig264
-rw-r--r--arch/powerpc/platforms/embedded6xx/linkstation.c8
-rw-r--r--arch/powerpc/platforms/embedded6xx/ls_uart.c4
-rw-r--r--arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c15
-rw-r--r--arch/powerpc/platforms/iseries/Kconfig4
-rw-r--r--arch/powerpc/platforms/iseries/iommu.c4
-rw-r--r--arch/powerpc/platforms/iseries/irq.c4
-rw-r--r--arch/powerpc/platforms/iseries/pci.c5
-rw-r--r--arch/powerpc/platforms/iseries/setup.c10
-rw-r--r--arch/powerpc/platforms/iseries/viopath.c2
-rw-r--r--arch/powerpc/platforms/maple/Kconfig17
-rw-r--r--arch/powerpc/platforms/maple/pci.c8
-rw-r--r--arch/powerpc/platforms/maple/setup.c17
-rw-r--r--arch/powerpc/platforms/pasemi/Kconfig19
-rw-r--r--arch/powerpc/platforms/pasemi/Makefile3
-rw-r--r--arch/powerpc/platforms/pasemi/cpufreq.c308
-rw-r--r--arch/powerpc/platforms/pasemi/gpio_mdio.c339
-rw-r--r--arch/powerpc/platforms/pasemi/idle.c9
-rw-r--r--arch/powerpc/platforms/pasemi/iommu.c6
-rw-r--r--arch/powerpc/platforms/pasemi/pasemi.h8
-rw-r--r--arch/powerpc/platforms/pasemi/pci.c16
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c28
-rw-r--r--arch/powerpc/platforms/powermac/Kconfig20
-rw-r--r--arch/powerpc/platforms/powermac/backlight.c9
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_32.c24
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c16
-rw-r--r--arch/powerpc/platforms/powermac/feature.c101
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c15
-rw-r--r--arch/powerpc/platforms/powermac/pci.c41
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_base.c2
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_core.c5
-rw-r--r--arch/powerpc/platforms/powermac/pic.c8
-rw-r--r--arch/powerpc/platforms/powermac/setup.c61
-rw-r--r--arch/powerpc/platforms/powermac/smp.c11
-rw-r--r--arch/powerpc/platforms/powermac/time.c38
-rw-r--r--arch/powerpc/platforms/powermac/udbg_scc.c6
-rw-r--r--arch/powerpc/platforms/prep/Kconfig9
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig16
-rw-r--r--arch/powerpc/platforms/ps3/htab.c2
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig10
-rw-r--r--arch/powerpc/platforms/pseries/Makefile5
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c204
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c78
-rw-r--r--arch/powerpc/platforms/pseries/eeh_event.c8
-rw-r--r--arch/powerpc/platforms/pseries/firmware.c2
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c4
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c67
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c6
-rw-r--r--arch/powerpc/platforms/pseries/nvram.c2
-rw-r--r--arch/powerpc/platforms/pseries/pci.c3
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c1
-rw-r--r--arch/powerpc/platforms/pseries/ras.c2
-rw-r--r--arch/powerpc/platforms/pseries/rtasd.c2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c44
-rw-r--r--arch/powerpc/platforms/pseries/xics.c17
-rw-r--r--arch/powerpc/sysdev/Makefile5
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c4
-rw-r--r--arch/powerpc/sysdev/dcr.c14
-rw-r--r--arch/powerpc/sysdev/fsl_pcie.c (renamed from arch/powerpc/platforms/86xx/mpc86xx_pcie.c)2
-rw-r--r--arch/powerpc/sysdev/fsl_pcie.h94
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c90
-rw-r--r--arch/powerpc/sysdev/mpic.c32
-rw-r--r--arch/powerpc/sysdev/pmi.c29
-rw-r--r--arch/powerpc/sysdev/qe_lib/Kconfig10
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe.c4
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_io.c6
-rw-r--r--arch/powerpc/sysdev/qe_lib/ucc_fast.c3
-rw-r--r--arch/powerpc/sysdev/qe_lib/ucc_slow.c4
-rw-r--r--arch/powerpc/sysdev/timer.c71
-rw-r--r--arch/powerpc/sysdev/tsi108_dev.c16
-rw-r--r--arch/powerpc/sysdev/tsi108_pci.c2
-rw-r--r--arch/powerpc/sysdev/uic.c342
-rw-r--r--arch/powerpc/xmon/xmon.c11
-rw-r--r--arch/ppc/8xx_io/Kconfig4
-rw-r--r--arch/ppc/8xx_io/Makefile1
-rw-r--r--arch/ppc/8xx_io/cs4218.h166
-rw-r--r--arch/ppc/8xx_io/cs4218_tdm.c2833
-rw-r--r--arch/ppc/boot/common/misc-common.c15
-rw-r--r--arch/ppc/boot/simple/Makefile1
-rw-r--r--arch/ppc/boot/simple/uartlite_tty.c37
-rw-r--r--arch/ppc/kernel/asm-offsets.c1
-rw-r--r--arch/ppc/kernel/entry.S1
-rw-r--r--arch/ppc/platforms/4xx/Kconfig15
-rw-r--r--arch/ppc/platforms/4xx/Makefile1
-rw-r--r--arch/ppc/platforms/4xx/ocotea.c4
-rw-r--r--arch/ppc/platforms/4xx/taishan.c2
-rw-r--r--arch/ppc/platforms/4xx/virtex.c56
-rw-r--r--arch/ppc/platforms/4xx/virtex.h34
-rw-r--r--arch/ppc/platforms/4xx/xilinx_ml300.c65
-rw-r--r--arch/ppc/platforms/4xx/xilinx_ml300.h45
-rw-r--r--arch/ppc/platforms/4xx/xilinx_ml403.c66
-rw-r--r--arch/ppc/platforms/4xx/xilinx_ml403.h49
-rw-r--r--arch/ppc/platforms/4xx/xparameters/xparameters.h60
-rw-r--r--arch/ppc/platforms/rpxclassic.h4
-rw-r--r--arch/ppc/platforms/rpxhiox.h41
-rw-r--r--arch/ppc/platforms/rpxlite.h4
-rw-r--r--arch/ppc/syslib/Makefile3
-rw-r--r--arch/ppc/syslib/cpc710.h81
-rw-r--r--arch/ppc/syslib/m8xx_setup.c2
-rw-r--r--arch/ppc/syslib/ppc4xx_sgdma.c1
-rw-r--r--arch/ppc/syslib/virtex_devices.c233
-rw-r--r--arch/ppc/syslib/virtex_devices.h27
-rw-r--r--arch/x86_64/defconfig1
-rw-r--r--block/cfq-iosched.c853
-rw-r--r--block/elevator.c17
-rw-r--r--block/ll_rw_blk.c1
-rw-r--r--crypto/michael_mic.c4
-rw-r--r--drivers/acpi/Kconfig44
-rw-r--r--drivers/acpi/Makefile10
-rw-r--r--drivers/acpi/acpi_memhotplug.c13
-rw-r--r--drivers/acpi/bus.c4
-rw-r--r--drivers/acpi/container.c6
-rw-r--r--drivers/acpi/dock.c25
-rw-r--r--drivers/acpi/ec.c495
-rw-r--r--drivers/acpi/i2c_ec.c403
-rw-r--r--drivers/acpi/i2c_ec.h23
-rw-r--r--drivers/acpi/ibm_acpi.c2798
-rw-r--r--drivers/acpi/processor_core.c4
-rw-r--r--drivers/acpi/processor_idle.c8
-rw-r--r--drivers/acpi/sbs.c1291
-rw-r--r--drivers/acpi/scan.c4
-rw-r--r--drivers/acpi/sleep/proc.c16
-rw-r--r--drivers/acpi/tables/tbfadt.c12
-rw-r--r--drivers/ata/Kconfig43
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c473
-rw-r--r--drivers/ata/ata_generic.c32
-rw-r--r--drivers/ata/ata_piix.c56
-rw-r--r--drivers/ata/libata-core.c1015
-rw-r--r--drivers/ata/libata-eh.c15
-rw-r--r--drivers/ata/libata-scsi.c85
-rw-r--r--drivers/ata/libata-sff.c631
-rw-r--r--drivers/ata/libata.h10
-rw-r--r--drivers/ata/pata_ali.c74
-rw-r--r--drivers/ata/pata_amd.c89
-rw-r--r--drivers/ata/pata_artop.c26
-rw-r--r--drivers/ata/pata_atiixp.c26
-rw-r--r--drivers/ata/pata_cmd640.c312
-rw-r--r--drivers/ata/pata_cmd64x.c34
-rw-r--r--drivers/ata/pata_cs5520.c145
-rw-r--r--drivers/ata/pata_cs5530.c15
-rw-r--r--drivers/ata/pata_cs5535.c24
-rw-r--r--drivers/ata/pata_cypress.c14
-rw-r--r--drivers/ata/pata_efar.c31
-rw-r--r--drivers/ata/pata_hpt366.c26
-rw-r--r--drivers/ata/pata_hpt37x.c381
-rw-r--r--drivers/ata/pata_hpt3x2n.c74
-rw-r--r--drivers/ata/pata_hpt3x3.c22
-rw-r--r--drivers/ata/pata_isapnp.c44
-rw-r--r--drivers/ata/pata_it8213.c36
-rw-r--r--drivers/ata/pata_it821x.c36
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c40
-rw-r--r--drivers/ata/pata_legacy.c45
-rw-r--r--drivers/ata/pata_marvell.c20
-rw-r--r--drivers/ata/pata_mpc52xx.c49
-rw-r--r--drivers/ata/pata_mpiix.c40
-rw-r--r--drivers/ata/pata_netcell.c31
-rw-r--r--drivers/ata/pata_ns87410.c6
-rw-r--r--drivers/ata/pata_oldpiix.c6
-rw-r--r--drivers/ata/pata_opti.c5
-rw-r--r--drivers/ata/pata_optidma.c54
-rw-r--r--drivers/ata/pata_pcmcia.c77
-rw-r--r--drivers/ata/pata_pdc2027x.c158
-rw-r--r--drivers/ata/pata_pdc202xx_old.c45
-rw-r--r--drivers/ata/pata_platform.c44
-rw-r--r--drivers/ata/pata_qdi.c47
-rw-r--r--drivers/ata/pata_radisys.c37
-rw-r--r--drivers/ata/pata_rz1000.c28
-rw-r--r--drivers/ata/pata_sc1200.c1
-rw-r--r--drivers/ata/pata_scc.c51
-rw-r--r--drivers/ata/pata_serverworks.c34
-rw-r--r--drivers/ata/pata_sil680.c11
-rw-r--r--drivers/ata/pata_sis.c109
-rw-r--r--drivers/ata/pata_sl82c105.c2
-rw-r--r--drivers/ata/pata_triflex.c4
-rw-r--r--drivers/ata/pata_via.c27
-rw-r--r--drivers/ata/pata_winbond.c101
-rw-r--r--drivers/ata/pdc_adma.c85
-rw-r--r--drivers/ata/sata_inic162x.c86
-rw-r--r--drivers/ata/sata_mv.c213
-rw-r--r--drivers/ata/sata_nv.c130
-rw-r--r--drivers/ata/sata_promise.c398
-rw-r--r--drivers/ata/sata_qstor.c62
-rw-r--r--drivers/ata/sata_sil.c118
-rw-r--r--drivers/ata/sata_sil24.c122
-rw-r--r--drivers/ata/sata_sis.c50
-rw-r--r--drivers/ata/sata_svw.c107
-rw-r--r--drivers/ata/sata_sx4.c150
-rw-r--r--drivers/ata/sata_uli.c65
-rw-r--r--drivers/ata/sata_via.c217
-rw-r--r--drivers/ata/sata_vsc.c72
-rw-r--r--drivers/char/briq_panel.c7
-rw-r--r--drivers/char/hvc_console.c49
-rw-r--r--drivers/char/hvc_iseries.c2
-rw-r--r--drivers/char/hvc_vio.c2
-rw-r--r--drivers/char/hvsi.c4
-rw-r--r--drivers/char/sonypi.c53
-rw-r--r--drivers/char/tpm/tpm_atmel.h4
-rw-r--r--drivers/char/watchdog/Kconfig2
-rw-r--r--drivers/clocksource/acpi_pm.c2
-rw-r--r--drivers/hwmon/ams/ams-core.c4
-rw-r--r--drivers/hwmon/ams/ams-i2c.c4
-rw-r--r--drivers/hwmon/ams/ams-pmu.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c4
-rw-r--r--drivers/macintosh/adb.c42
-rw-r--r--drivers/macintosh/ans-lcd.c9
-rw-r--r--drivers/macintosh/apm_emu.c13
-rw-r--r--drivers/macintosh/mac_hid.c2
-rw-r--r--drivers/macintosh/macio-adb.c16
-rw-r--r--drivers/macintosh/macio_asic.c100
-rw-r--r--drivers/macintosh/macio_sysfs.c10
-rw-r--r--drivers/macintosh/rack-meter.c2
-rw-r--r--drivers/macintosh/smu.c8
-rw-r--r--drivers/macintosh/therm_adt746x.c8
-rw-r--r--drivers/macintosh/therm_pm72.c8
-rw-r--r--drivers/macintosh/therm_windtunnel.c2
-rw-r--r--drivers/macintosh/via-cuda.c2
-rw-r--r--drivers/macintosh/via-pmu-led.c10
-rw-r--r--drivers/macintosh/via-pmu.c55
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c2
-rw-r--r--drivers/macintosh/windfarm_max6690_sensor.c2
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c8
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c8
-rw-r--r--drivers/macintosh/windfarm_smu_sensors.c6
-rw-r--r--drivers/md/dm-crypt.c2
-rw-r--r--drivers/md/dm-io.c2
-rw-r--r--drivers/md/dm.c2
-rw-r--r--drivers/media/video/Kconfig6
-rw-r--r--drivers/media/video/meye.c62
-rw-r--r--drivers/media/video/meye.h2
-rw-r--r--drivers/media/video/planb.c5
-rw-r--r--drivers/misc/Kconfig66
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/asus-laptop.c151
-rw-r--r--drivers/misc/sony-laptop.c2131
-rw-r--r--drivers/misc/thinkpad_acpi.c4312
-rw-r--r--drivers/misc/thinkpad_acpi.h572
-rw-r--r--drivers/net/3c509.c1
-rw-r--r--drivers/net/Kconfig24
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/chelsio/Makefile4
-rw-r--r--drivers/net/chelsio/common.h6
-rw-r--r--drivers/net/chelsio/cphy.h16
-rw-r--r--drivers/net/chelsio/gmac.h10
-rw-r--r--drivers/net/chelsio/ixf1010.c505
-rw-r--r--drivers/net/chelsio/mac.c2
-rw-r--r--drivers/net/chelsio/mv88e1xxx.c8
-rw-r--r--drivers/net/chelsio/mv88x201x.c8
-rw-r--r--drivers/net/chelsio/my3126.c8
-rw-r--r--drivers/net/chelsio/pm3393.c8
-rw-r--r--drivers/net/chelsio/subr.c199
-rw-r--r--drivers/net/chelsio/vsc7326.c2
-rw-r--r--drivers/net/chelsio/vsc8244.c367
-rw-r--r--drivers/net/chelsio/vsc8244_reg.h172
-rw-r--r--drivers/net/e100.c159
-rw-r--r--drivers/net/e1000/e1000.h3
-rw-r--r--drivers/net/e1000/e1000_ethtool.c34
-rw-r--r--drivers/net/e1000/e1000_main.c45
-rw-r--r--drivers/net/e1000/e1000_param.c4
-rw-r--r--drivers/net/eexpress.c9
-rw-r--r--drivers/net/ehea/ehea.h42
-rw-r--r--drivers/net/ehea/ehea_ethtool.c115
-rw-r--r--drivers/net/ehea/ehea_main.c940
-rw-r--r--drivers/net/ehea/ehea_phyp.c6
-rw-r--r--drivers/net/ehea/ehea_phyp.h6
-rw-r--r--drivers/net/ehea/ehea_qmr.c184
-rw-r--r--drivers/net/ehea/ehea_qmr.h16
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c13
-rw-r--r--drivers/net/ibmveth.c10
-rw-r--r--drivers/net/ixgb/ixgb.h3
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c4
-rw-r--r--drivers/net/ixgb/ixgb_main.c4
-rw-r--r--drivers/net/ixgb/ixgb_param.c8
-rw-r--r--drivers/net/mii.c57
-rw-r--r--drivers/net/mipsnet.c53
-rw-r--r--drivers/net/mv643xx_eth.c59
-rw-r--r--drivers/net/mv643xx_eth.h4
-rw-r--r--drivers/net/netxen/netxen_nic.h189
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c212
-rw-r--r--drivers/net/netxen/netxen_nic_hdr.h12
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c401
-rw-r--r--drivers/net/netxen/netxen_nic_hw.h85
-rw-r--r--drivers/net/netxen/netxen_nic_init.c130
-rw-r--r--drivers/net/netxen/netxen_nic_isr.c101
-rw-r--r--drivers/net/netxen/netxen_nic_main.c769
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c168
-rw-r--r--drivers/net/netxen/netxen_nic_phan_reg.h134
-rw-r--r--drivers/net/pcnet32.c159
-rw-r--r--drivers/net/phy/mdio_bus.c19
-rw-r--r--drivers/net/phy/phy.c194
-rw-r--r--drivers/net/phy/phy_device.c114
-rwxr-xr-xdrivers/net/qla3xxx.c371
-rwxr-xr-xdrivers/net/qla3xxx.h33
-rw-r--r--drivers/net/s2io-regs.h2
-rw-r--r--drivers/net/s2io.c78
-rw-r--r--drivers/net/s2io.h8
-rw-r--r--drivers/net/sb1250-mac.c294
-rw-r--r--drivers/net/sgiseeq.c28
-rw-r--r--drivers/net/sk98lin/skge.c20
-rw-r--r--drivers/net/skfp/h/lnkstat.h84
-rw-r--r--drivers/net/skge.c30
-rw-r--r--drivers/net/skge.h10
-rw-r--r--drivers/net/smc911x.c2
-rw-r--r--drivers/net/tc35815.c2554
-rw-r--r--drivers/net/tulip/dmfe.c118
-rw-r--r--drivers/net/tulip/interrupt.c4
-rw-r--r--drivers/net/tulip/media.c40
-rw-r--r--drivers/net/tulip/tulip.h9
-rw-r--r--drivers/net/tulip/tulip_core.c6
-rw-r--r--drivers/net/tulip/winbond-840.c2
-rw-r--r--drivers/net/ucc_geth.c946
-rw-r--r--drivers/net/ucc_geth.h114
-rw-r--r--drivers/net/ucc_geth_mii.c279
-rw-r--r--drivers/net/ucc_geth_mii.h100
-rw-r--r--drivers/net/ucc_geth_phy.c785
-rw-r--r--drivers/net/ucc_geth_phy.h217
-rw-r--r--drivers/net/wan/hdlc_cisco.c29
-rw-r--r--drivers/net/wan/hdlc_fr.c18
-rw-r--r--drivers/net/wireless/Kconfig13
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/README25
-rw-r--r--drivers/net/wireless/airo.c70
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h3
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c23
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.h4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c196
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_common.h4
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c9
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c2
-rw-r--r--drivers/net/wireless/ipw2100.c4
-rw-r--r--drivers/net/wireless/ipw2200.c47
-rw-r--r--drivers/net/wireless/libertas/11d.c754
-rw-r--r--drivers/net/wireless/libertas/11d.h105
-rw-r--r--drivers/net/wireless/libertas/LICENSE16
-rw-r--r--drivers/net/wireless/libertas/Makefile21
-rw-r--r--drivers/net/wireless/libertas/README1044
-rw-r--r--drivers/net/wireless/libertas/assoc.c588
-rw-r--r--drivers/net/wireless/libertas/assoc.h30
-rw-r--r--drivers/net/wireless/libertas/cmd.c1958
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c1031
-rw-r--r--drivers/net/wireless/libertas/debugfs.c1935
-rw-r--r--drivers/net/wireless/libertas/debugfs.h6
-rw-r--r--drivers/net/wireless/libertas/decl.h83
-rw-r--r--drivers/net/wireless/libertas/defs.h369
-rw-r--r--drivers/net/wireless/libertas/dev.h403
-rw-r--r--drivers/net/wireless/libertas/ethtool.c184
-rw-r--r--drivers/net/wireless/libertas/fw.c361
-rw-r--r--drivers/net/wireless/libertas/fw.h13
-rw-r--r--drivers/net/wireless/libertas/host.h338
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h693
-rw-r--r--drivers/net/wireless/libertas/if_bootcmd.c38
-rw-r--r--drivers/net/wireless/libertas/if_usb.c952
-rw-r--r--drivers/net/wireless/libertas/if_usb.h109
-rw-r--r--drivers/net/wireless/libertas/ioctl.c2500
-rw-r--r--drivers/net/wireless/libertas/join.c1055
-rw-r--r--drivers/net/wireless/libertas/join.h64
-rw-r--r--drivers/net/wireless/libertas/main.c1258
-rw-r--r--drivers/net/wireless/libertas/radiotap.h57
-rw-r--r--drivers/net/wireless/libertas/rx.c459
-rw-r--r--drivers/net/wireless/libertas/sbi.h40
-rw-r--r--drivers/net/wireless/libertas/scan.c2044
-rw-r--r--drivers/net/wireless/libertas/scan.h216
-rw-r--r--drivers/net/wireless/libertas/thread.h52
-rw-r--r--drivers/net/wireless/libertas/tx.c285
-rw-r--r--drivers/net/wireless/libertas/types.h289
-rw-r--r--drivers/net/wireless/libertas/version.h8
-rw-r--r--drivers/net/wireless/libertas/wext.c2769
-rw-r--r--drivers/net/wireless/libertas/wext.h147
-rw-r--r--drivers/net/wireless/todo.txt15
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c47
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c23
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.c18
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h11
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al2230.c91
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al7230b.c317
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_rf2959.c4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c24
-rw-r--r--drivers/pci/pci-acpi.c4
-rw-r--r--drivers/pci/quirks.c113
-rw-r--r--drivers/ps3/vuart.c8
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c7
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c3
-rw-r--r--drivers/scsi/ipr.c3
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/serial/pmac_zilog.c4
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/aty/radeon_pm.c2
-rw-r--r--drivers/video/controlfb.c16
-rw-r--r--fs/bio.c41
-rw-r--r--fs/proc/proc_devtree.c2
-rw-r--r--include/acpi/actbl.h1
-rw-r--r--include/asm-powerpc/asm-compat.h10
-rw-r--r--include/asm-powerpc/cacheflush.h6
-rw-r--r--include/asm-powerpc/cell-pmu.h5
-rw-r--r--include/asm-powerpc/cputable.h11
-rw-r--r--include/asm-powerpc/current.h1
-rw-r--r--include/asm-powerpc/edac.h40
-rw-r--r--include/asm-powerpc/eeh_event.h6
-rw-r--r--include/asm-powerpc/ibmebus.h44
-rw-r--r--include/asm-powerpc/immap_86xx.h75
-rw-r--r--include/asm-powerpc/io.h7
-rw-r--r--include/asm-powerpc/kprobes.h5
-rw-r--r--include/asm-powerpc/machdep.h3
-rw-r--r--include/asm-powerpc/mmu-hash64.h400
-rw-r--r--include/asm-powerpc/mmu.h405
-rw-r--r--include/asm-powerpc/mpic.h12
-rw-r--r--include/asm-powerpc/of_device.h3
-rw-r--r--include/asm-powerpc/oprofile_impl.h2
-rw-r--r--include/asm-powerpc/paca.h4
-rw-r--r--include/asm-powerpc/parport.h6
-rw-r--r--include/asm-powerpc/pci.h14
-rw-r--r--include/asm-powerpc/pgtable-4k.h3
-rw-r--r--include/asm-powerpc/pgtable-64k.h5
-rw-r--r--include/asm-powerpc/pgtable.h60
-rw-r--r--include/asm-powerpc/pmc.h1
-rw-r--r--include/asm-powerpc/ppc-pci.h12
-rw-r--r--include/asm-powerpc/processor.h1
-rw-r--r--include/asm-powerpc/prom.h34
-rw-r--r--include/asm-powerpc/reg.h68
-rw-r--r--include/asm-powerpc/spu_csa.h1
-rw-r--r--include/asm-powerpc/system.h1
-rw-r--r--include/asm-powerpc/tlb.h1
-rw-r--r--include/asm-powerpc/tlbflush.h172
-rw-r--r--include/asm-powerpc/uaccess.h28
-rw-r--r--include/asm-powerpc/ucc_fast.h3
-rw-r--r--include/asm-powerpc/uic.h23
-rw-r--r--include/asm-ppc/ibm4xx.h8
-rw-r--r--include/asm-ppc/ppc_sys.h2
-rw-r--r--include/asm-ppc/prom.h3
-rw-r--r--include/linux/ata.h10
-rw-r--r--include/linux/bio.h2
-rw-r--r--include/linux/blkdev.h1
-rw-r--r--include/linux/fsl_devices.h39
-rw-r--r--include/linux/hdlc.h3
-rw-r--r--include/linux/ioport.h1
-rw-r--r--include/linux/libata.h78
-rw-r--r--include/linux/pci.h1
-rw-r--r--include/linux/pci_ids.h3
-rw-r--r--include/linux/phy.h1
-rw-r--r--include/linux/pmu.h12
-rw-r--r--include/linux/sony-laptop.h34
-rw-r--r--include/linux/wireless.h2
-rw-r--r--include/net/ieee80211.h4
-rw-r--r--include/net/ieee80211_crypt.h4
-rw-r--r--include/net/ieee80211_radiotap.h77
-rw-r--r--kernel/resource.c21
-rw-r--r--lib/devres.c26
-rw-r--r--net/ieee80211/ieee80211_crypt.c2
-rw-r--r--net/ieee80211/ieee80211_crypt_ccmp.c4
-rw-r--r--net/ieee80211/ieee80211_crypt_tkip.c6
-rw-r--r--net/ieee80211/ieee80211_crypt_wep.c2
-rw-r--r--net/ieee80211/ieee80211_module.c5
-rw-r--r--net/ieee80211/ieee80211_rx.c4
-rw-r--r--net/ieee80211/ieee80211_wx.c4
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-onyx.c4
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-tas.c9
-rw-r--r--sound/aoa/core/snd-aoa-gpio-feature.c8
-rw-r--r--sound/aoa/fabrics/snd-aoa-fabric-layout.c8
-rw-r--r--sound/aoa/soundbus/core.c4
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-core.c8
-rw-r--r--sound/oss/dmasound/dmasound_awacs.c121
-rw-r--r--sound/oss/dmasound/tas_common.c9
-rw-r--r--sound/ppc/pmac.c41
-rw-r--r--sound/ppc/tumbler.c55
669 files changed, 53570 insertions, 22547 deletions
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 0bb90237e230..b61dfc79e1b8 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -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
-->
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 2017942e0966..84c3bd05c639 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -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
diff --git a/Documentation/networking/bcm43xx.txt b/Documentation/networking/bcm43xx.txt
index 28541d2bee1e..a136721499bf 100644
--- a/Documentation/networking/bcm43xx.txt
+++ b/Documentation/networking/bcm43xx.txt
@@ -2,35 +2,88 @@
BCM43xx Linux Driver Project
============================
-About this software
--------------------
+Introduction
+------------
-The goal of this project is to develop a linux driver for Broadcom
-BCM43xx chips, based on the specification at
-http://bcm-specs.sipsolutions.net/
+Many of the wireless devices found in modern notebook computers are
+based on the wireless chips produced by Broadcom. These devices have
+been a problem for Linux users as there is no open-source driver
+available. In addition, Broadcom has not released specifications
+for the device, and driver availability has been limited to the
+binary-only form used in the GPL versions of AP hardware such as the
+Linksys WRT54G, and the Windows and OS X drivers. Before this project
+began, the only way to use these devices were to use the Windows or
+OS X drivers with either the Linuxant or ndiswrapper modules. There
+is a strong penalty if this method is used as loading the binary-only
+module "taints" the kernel, and no kernel developer will help diagnose
+any kernel problems.
-The project page is http://bcm43xx.berlios.de/
+Development
+-----------
+This driver has been developed using
+a clean-room technique that is described at
+http://bcm-specs.sipsolutions.net/ReverseEngineeringProcess. For legal
+reasons, none of the clean-room crew works on the on the Linux driver,
+and none of the Linux developers sees anything but the specifications,
+which are the ultimate product of the reverse-engineering group.
-Requirements
-------------
+Software
+--------
+
+Since the release of the 2.6.17 kernel, the bcm43xx driver has been
+distributed with the kernel source, and is prebuilt in most, if not
+all, distributions. There is, however, additional software that is
+required. The firmware used by the chip is the intellectual property
+of Broadcom and they have not given the bcm43xx team redistribution
+rights to this firmware. Since we cannot legally redistribute
+the firwmare we cannot include it with the driver. Furthermore, it
+cannot be placed in the downloadable archives of any distributing
+organization; therefore, the user is responsible for obtaining the
+firmware and placing it in the appropriate location so that the driver
+can find it when initializing.
+
+To help with this process, the bcm43xx developers provide a separate
+program named bcm43xx-fwcutter to "cut" the firmware out of a
+Windows or OS X driver and write the extracted files to the proper
+location. This program is usually provided with the distribution;
+however, it may be downloaded from
+
+http://developer.berlios.de/project/showfiles.php?group_id=4547
-1) Linux Kernel 2.6.16 or later
- http://www.kernel.org/
+The firmware is available in two versions. V3 firmware is used with
+the in-kernel bcm43xx driver that uses a software MAC layer called
+SoftMAC, and will have a microcode revision of 0x127 or smaller. The
+V4 firmware is used by an out-of-kernel driver employing a variation of
+the Devicescape MAC layer known as d80211. Once bcm43xx-d80211 reaches
+a satisfactory level of development, it will replace bcm43xx-softmac
+in the kernel as it is much more flexible and powerful.
- You may want to configure your kernel with:
+A source for the latest V3 firmware is
- CONFIG_DEBUG_FS (optional):
- -> Kernel hacking
- -> Debug Filesystem
+http://downloads.openwrt.org/sources/wl_apsta-3.130.20.0.o
-2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211
- modules:
- http://softmac.sipsolutions.net/
+Once this file is downloaded, the command
+'bcm43xx-fwcutter -w <dir> <filename>'
+will extract the microcode and write it to directory
+<dir>. The correct directory will depend on your distribution;
+however, most use '/lib/firmware'. Once this step is completed,
+the bcm3xx driver should load when the system is booted. To see
+any messages relating to the driver, issue the command 'dmesg |
+grep bcm43xx' from a terminal window. If there are any problems,
+please send that output to Bcm43xx-dev@lists.berlios.de.
-3) Firmware Files
+Although the driver has been in-kernel since 2.6.17, the earliest
+version is quite limited in its capability. Patches that include
+all features of later versions are available for the stable kernel
+versions from 2.6.18. These will be needed if you use a BCM4318,
+or a PCI Express version (BCM4311 and BCM4312). In addition, if you
+have an early BCM4306 and more than 1 GB RAM, your kernel will need
+to be patched. These patches, which are being updated regularly,
+are available at ftp://lwfinger.dynalias.org/patches. Look for
+combined_2.6.YY.patch. Of course you will need kernel source downloaded
+from kernel.org, or the source from your distribution.
- Please try fwcutter. Fwcutter can extract the firmware from various
- binary driver files. It supports driver files from Windows, MacOS and
- Linux. You can get fwcutter from http://bcm43xx.berlios.de/.
- Also, fwcutter comes with a README file for further instructions.
+If you build your own kernel, please enable CONFIG_BCM43XX_DEBUG
+and CONFIG_IEEE80211_SOFTMAC_DEBUG. The log information provided is
+essential for solving any problems.
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index b41397d6430a..033a3f3b3ab7 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -39,7 +39,7 @@
and property data. The old style variable
alignment would make it impossible to do
"simple" insertion of properties using
- memove (thanks Milton for
+ memmove (thanks Milton for
noticing). Updated kernel patch as well
- Correct a few more alignment constraints
- Add a chapter about the device-tree
@@ -55,7 +55,7 @@
ToDo:
- Add some definitions of interrupt tree (simple/complex)
- - Add some definitions for pci host bridges
+ - Add some definitions for PCI host bridges
- Add some common address format examples
- Add definitions for standard properties and "compatible"
names for cells that are not already defined by the existing
@@ -114,7 +114,7 @@ it with special cases.
forth words isn't required), you can enter the kernel with:
r5 : OF callback pointer as defined by IEEE 1275
- bindings to powerpc. Only the 32 bit client interface
+ bindings to powerpc. Only the 32-bit client interface
is currently supported
r3, r4 : address & length of an initrd if any or 0
@@ -194,7 +194,7 @@ it with special cases.
for this is to keep kernels on embedded systems small and efficient;
part of this is due to the fact the code is already that way. In the
future, a kernel may support multiple platforms, but only if the
- platforms feature the same core architectire. A single kernel build
+ platforms feature the same core architecture. A single kernel build
cannot support both configurations with Book E and configurations
with classic Powerpc architectures.
@@ -215,7 +215,7 @@ of the boot sequences.... someone speak up if this is wrong!
enable another config option to select the specific board
supported.
-NOTE: If ben doesn't merge the setup files, may need to change this to
+NOTE: If Ben doesn't merge the setup files, may need to change this to
point to setup_32.c
@@ -256,7 +256,7 @@ struct boot_param_header {
u32 off_dt_struct; /* offset to structure */
u32 off_dt_strings; /* offset to strings */
u32 off_mem_rsvmap; /* offset to memory reserve map
-*/
+ */
u32 version; /* format version */
u32 last_comp_version; /* last compatible version */
@@ -265,6 +265,9 @@ struct boot_param_header {
booting on */
/* version 3 fields below */
u32 size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ u32 size_dt_struct; /* size of the DT structure block */
};
Along with the constants:
@@ -273,7 +276,7 @@ struct boot_param_header {
#define OF_DT_HEADER 0xd00dfeed /* 4: version,
4: total size */
#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name
-*/
+ */
#define OF_DT_END_NODE 0x2 /* End node */
#define OF_DT_PROP 0x3 /* Property: name off,
size, content */
@@ -310,9 +313,8 @@ struct boot_param_header {
- off_mem_rsvmap
This is an offset from the beginning of the header to the start
- of the reserved memory map. This map is a list of pairs of 64
+ of the reserved memory map. This map is a list of pairs of 64-
bit integers. Each pair is a physical address and a size. The
-
list is terminated by an entry of size 0. This map provides the
kernel with a list of physical memory areas that are "reserved"
and thus not to be used for memory allocations, especially during
@@ -325,7 +327,7 @@ struct boot_param_header {
contain _at least_ this DT block itself (header,total_size). If
you are passing an initrd to the kernel, you should reserve it as
well. You do not need to reserve the kernel image itself. The map
- should be 64 bit aligned.
+ should be 64-bit aligned.
- version
@@ -335,10 +337,13 @@ struct boot_param_header {
to reallocate it easily at boot and free up the unused flattened
structure after expansion. Version 16 introduces a new more
"compact" format for the tree itself that is however not backward
- compatible. You should always generate a structure of the highest
- version defined at the time of your implementation. Currently
- that is version 16, unless you explicitly aim at being backward
- compatible.
+ compatible. Version 17 adds an additional field, size_dt_struct,
+ allowing it to be reallocated or moved more easily (this is
+ particularly useful for bootloaders which need to make
+ adjustments to a device tree based on probed information). You
+ should always generate a structure of the highest version defined
+ at the time of your implementation. Currently that is version 17,
+ unless you explicitly aim at being backward compatible.
- last_comp_version
@@ -347,7 +352,7 @@ struct boot_param_header {
is backward compatible with version 1 (that is, a kernel build
for version 1 will be able to boot with a version 2 format). You
should put a 1 in this field if you generate a device tree of
- version 1 to 3, or 0x10 if you generate a tree of version 0x10
+ version 1 to 3, or 16 if you generate a tree of version 16 or 17
using the new unit name format.
- boot_cpuid_phys
@@ -360,6 +365,17 @@ struct boot_param_header {
point (see further chapters for more informations on the required
device-tree contents)
+ - size_dt_strings
+
+ This field only exists on version 3 and later headers. It
+ gives the size of the "strings" section of the device tree (which
+ starts at the offset given by off_dt_strings).
+
+ - size_dt_struct
+
+ This field only exists on version 17 and later headers. It gives
+ the size of the "structure" section of the device tree (which
+ starts at the offset given by off_dt_struct).
So the typical layout of a DT block (though the various parts don't
need to be in that order) looks like this (addresses go from top to
@@ -417,7 +433,7 @@ root node who has no parent.
A node has 2 names. The actual node name is generally contained in a
property of type "name" in the node property list whose value is a
zero terminated string and is mandatory for version 1 to 3 of the
-format definition (as it is in Open Firmware). Version 0x10 makes it
+format definition (as it is in Open Firmware). Version 16 makes it
optional as it can generate it from the unit name defined below.
There is also a "unit name" that is used to differentiate nodes with
@@ -461,7 +477,7 @@ referencing another node via "phandle" is when laying out the
interrupt tree which will be described in a further version of this
document.
-This "linux, phandle" property is a 32 bit value that uniquely
+This "linux, phandle" property is a 32-bit value that uniquely
identifies a node. You are free to use whatever values or system of
values, internal pointers, or whatever to generate these, the only
requirement is that every node for which you provide that property has
@@ -471,7 +487,7 @@ Here is an example of a simple device-tree. In this example, an "o"
designates a node followed by the node unit name. Properties are
presented with their name followed by their content. "content"
represents an ASCII string (zero terminated) value, while <content>
-represents a 32 bit hexadecimal value. The various nodes in this
+represents a 32-bit hexadecimal value. The various nodes in this
example will be discussed in a later chapter. At this point, it is
only meant to give you a idea of what a device-tree looks like. I have
purposefully kept the "name" and "linux,phandle" properties which
@@ -543,15 +559,15 @@ Here's the basic structure of a single node:
* [align gap to next 4 bytes boundary]
* for each property:
* token OF_DT_PROP (that is 0x00000003)
- * 32 bit value of property value size in bytes (or 0 of no
- * value)
- * 32 bit value of offset in string block of property name
+ * 32-bit value of property value size in bytes (or 0 if no
+ value)
+ * 32-bit value of offset in string block of property name
* property value data if any
* [align gap to next 4 bytes boundary]
* [child nodes if any]
* token OF_DT_END_NODE (that is 0x00000002)
-So the node content can be summarised as a start token, a full path,
+So the node content can be summarized as a start token, a full path,
a list of properties, a list of child nodes, and an end token. Every
child node is a full node structure itself as defined above.
@@ -583,7 +599,7 @@ provide those properties yourself.
----------------------------------------------
The general rule is documented in the various Open Firmware
-documentations. If you chose to describe a bus with the device-tree
+documentations. If you choose to describe a bus with the device-tree
and there exist an OF bus binding, then you should follow the
specification. However, the kernel does not require every single
device or bus to be described by the device tree.
@@ -596,9 +612,9 @@ those properties defining addresses format for devices directly mapped
on the processor bus.
Those 2 properties define 'cells' for representing an address and a
-size. A "cell" is a 32 bit number. For example, if both contain 2
+size. A "cell" is a 32-bit number. For example, if both contain 2
like the example tree given above, then an address and a size are both
-composed of 2 cells, and each is a 64 bit number (cells are
+composed of 2 cells, and each is a 64-bit number (cells are
concatenated and expected to be in big endian format). Another example
is the way Apple firmware defines them, with 2 cells for an address
and one cell for a size. Most 32-bit implementations should define
@@ -632,7 +648,7 @@ prom_parse.c file of the recent kernels for your bus type.
The "reg" property only defines addresses and sizes (if #size-cells
is non-0) within a given bus. In order to translate addresses upward
-(that is into parent bus addresses, and possibly into cpu physical
+(that is into parent bus addresses, and possibly into CPU physical
addresses), all busses must contain a "ranges" property. If the
"ranges" property is missing at a given level, it's assumed that
translation isn't possible. The format of the "ranges" property for a
@@ -648,9 +664,9 @@ example, for a PCI host controller, that would be a CPU address. For a
PCI<->ISA bridge, that would be a PCI address. It defines the base
address in the parent bus where the beginning of that range is mapped.
-For a new 64 bit powerpc board, I recommend either the 2/2 format or
+For a new 64-bit powerpc board, I recommend either the 2/2 format or
Apple's 2/1 format which is slightly more compact since sizes usually
-fit in a single 32 bit word. New 32 bit powerpc boards should use a
+fit in a single 32-bit word. New 32-bit powerpc boards should use a
1/1 format, unless the processor supports physical addresses greater
than 32-bits, in which case a 2/1 format is recommended.
@@ -764,7 +780,7 @@ address which can extend beyond that limit.
Required properties:
- device_type : has to be "cpu"
- - reg : This is the physical cpu number, it's a single 32 bit cell
+ - reg : This is the physical CPU number, it's a single 32-bit cell
and is also used as-is as the unit number for constructing the
unit name in the full path. For example, with 2 CPUs, you would
have the full path:
@@ -785,7 +801,7 @@ address which can extend beyond that limit.
the kernel timebase/decrementer calibration based on this
value.
- clock-frequency : a cell indicating the CPU core clock frequency
- in Hz. A new property will be defined for 64 bit values, but if
+ in Hz. A new property will be defined for 64-bit values, but if
your frequency is < 4Ghz, one cell is enough. Here as well as
for the above, the common code doesn't use that property, but
you are welcome to re-use the pSeries or Maple one. A future
@@ -832,8 +848,7 @@ address which can extend beyond that limit.
This node is a bit "special". Normally, that's where open firmware
puts some variable environment information, like the arguments, or
- phandle pointers to nodes like the main interrupt controller, or the
- default input/output devices.
+ the default input/output devices.
This specification makes a few of these mandatory, but also defines
some linux-specific properties that would be normally constructed by
@@ -853,14 +868,14 @@ address which can extend beyond that limit.
that the kernel tries to find out the default console and has
knowledge of various types like 8250 serial ports. You may want
to extend this function to add your own.
- - interrupt-controller : This is one cell containing a phandle
- value that matches the "linux,phandle" property of your main
- interrupt controller node. May be used for interrupt routing.
-
Note that u-boot creates and fills in the chosen node for platforms
that use it.
+ (Note: a practice that is now obsolete was to include a property
+ under /chosen called interrupt-controller which had a phandle value
+ that pointed to the main interrupt controller)
+
f) the /soc<SOCname> node
This node is used to represent a system-on-a-chip (SOC) and must be
@@ -908,8 +923,7 @@ address which can extend beyond that limit.
The SOC node may contain child nodes for each SOC device that the
platform uses. Nodes should not be created for devices which exist
on the SOC but are not used by a particular platform. See chapter VI
- for more information on how to specify devices that are part of an
-SOC.
+ for more information on how to specify devices that are part of a SOC.
Example SOC node for the MPC8540:
@@ -972,7 +986,7 @@ The syntax of the dtc tool is
[-o output-filename] [-V output_version] input_filename
-The "output_version" defines what versio of the "blob" format will be
+The "output_version" defines what version of the "blob" format will be
generated. Supported versions are 1,2,3 and 16. The default is
currently version 3 but that may change in the future to version 16.
@@ -994,12 +1008,12 @@ supported currently at the toplevel.
*/
property2 = <1234abcd>; /* define a property containing a
- * numerical 32 bits value (hexadecimal)
+ * numerical 32-bit value (hexadecimal)
*/
property3 = <12345678 12345678 deadbeef>;
/* define a property containing 3
- * numerical 32 bits values (cells) in
+ * numerical 32-bit values (cells) in
* hexadecimal
*/
property4 = [0a 0b 0c 0d de ea ad be ef];
@@ -1068,7 +1082,7 @@ while all this has been defined and implemented.
its usage in early_init_devtree(), and the corresponding various
early_init_dt_scan_*() callbacks. That code can be re-used in a
GPL bootloader, and as the author of that code, I would be happy
- to discuss possible free licencing to any vendor who wishes to
+ to discuss possible free licensing to any vendor who wishes to
integrate all or part of this code into a non-GPL bootloader.
@@ -1077,7 +1091,7 @@ VI - System-on-a-chip devices and nodes
=======================================
Many companies are now starting to develop system-on-a-chip
-processors, where the processor core (cpu) and many peripheral devices
+processors, where the processor core (CPU) and many peripheral devices
exist on a single piece of silicon. For these SOCs, an SOC node
should be used that defines child nodes for the devices that make
up the SOC. While platforms are not required to use this model in
@@ -1109,42 +1123,7 @@ See appendix A for an example partial SOC node definition for the
MPC8540.
-2) Specifying interrupt information for SOC devices
----------------------------------------------------
-
-Each device that is part of an SOC and which generates interrupts
-should have the following properties:
-
- - interrupt-parent : contains the phandle of the interrupt
- controller which handles interrupts for this device
- - interrupts : a list of tuples representing the interrupt
- number and the interrupt sense and level for each interrupt
- for this device.
-
-This information is used by the kernel to build the interrupt table
-for the interrupt controllers in the system.
-
-Sense and level information should be encoded as follows:
-
- Devices connected to openPIC-compatible controllers should encode
- sense and polarity as follows:
-
- 0 = low to high edge sensitive type enabled
- 1 = active low level sensitive type enabled
- 2 = active high level sensitive type enabled
- 3 = high to low edge sensitive type enabled
-
- ISA PIC interrupt controllers should adhere to the ISA PIC
- encodings listed below:
-
- 0 = active low level sensitive type enabled
- 1 = active high level sensitive type enabled
- 2 = high to low edge sensitive type enabled
- 3 = low to high edge sensitive type enabled
-
-
-
-3) Representing devices without a current OF specification
+2) Representing devices without a current OF specification
----------------------------------------------------------
Currently, there are many devices on SOCs that do not have a standard
@@ -1201,6 +1180,13 @@ platforms are moved over to use the flattened-device-tree model.
- phy-handle : The phandle for the PHY connected to this ethernet
controller.
+ Recommended properties:
+
+ - linux,network-index : This is the intended "index" of this
+ network device. This is used by the bootwrapper to interpret
+ MAC addresses passed by the firmware when no information other
+ than indices is available to associate an address with a device.
+
Example:
ethernet@24000 {
@@ -1312,10 +1298,10 @@ platforms are moved over to use the flattened-device-tree model.
and additions :
Required properties :
- - compatible : Should be "fsl-usb2-mph" for multi port host usb
- controllers, or "fsl-usb2-dr" for dual role usb controllers
- - phy_type : For multi port host usb controllers, should be one of
- "ulpi", or "serial". For dual role usb controllers, should be
+ - compatible : Should be "fsl-usb2-mph" for multi port host USB
+ controllers, or "fsl-usb2-dr" for dual role USB controllers
+ - phy_type : For multi port host USB controllers, should be one of
+ "ulpi", or "serial". For dual role USB controllers, should be
one of "ulpi", "utmi", "utmi_wide", or "serial".
- reg : Offset and length of the register set for the device
- port0 : boolean; if defined, indicates port0 is connected for
@@ -1339,7 +1325,7 @@ platforms are moved over to use the flattened-device-tree model.
- interrupt-parent : the phandle for the interrupt controller that
services interrupts for this device.
- Example multi port host usb controller device node :
+ Example multi port host USB controller device node :
usb@22000 {
device_type = "usb";
compatible = "fsl-usb2-mph";
@@ -1353,7 +1339,7 @@ platforms are moved over to use the flattened-device-tree model.
port1;
};
- Example dual role usb controller device node :
+ Example dual role USB controller device node :
usb@23000 {
device_type = "usb";
compatible = "fsl-usb2-dr";
@@ -1387,7 +1373,7 @@ platforms are moved over to use the flattened-device-tree model.
- channel-fifo-len : An integer representing the number of
descriptor pointers each channel fetch fifo can hold.
- exec-units-mask : The bitmask representing what execution units
- (EUs) are available. It's a single 32 bit cell. EU information
+ (EUs) are available. It's a single 32-bit cell. EU information
should be encoded following the SEC's Descriptor Header Dword
EU_SEL0 field documentation, i.e. as follows:
@@ -1403,7 +1389,7 @@ platforms are moved over to use the flattened-device-tree model.
bits 8 through 31 are reserved for future SEC EUs.
- descriptor-types-mask : The bitmask representing what descriptors
- are available. It's a single 32 bit cell. Descriptor type
+ are available. It's a single 32-bit cell. Descriptor type
information should be encoded following the SEC's Descriptor
Header Dword DESC_TYPE field documentation, i.e. as follows:
@@ -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
========================================
diff --git a/Documentation/sony-laptop.txt b/Documentation/sony-laptop.txt
index dfd26df056f4..7a5c1a81905c 100644
--- a/Documentation/sony-laptop.txt
+++ b/Documentation/sony-laptop.txt
@@ -3,12 +3,18 @@ Sony Notebook Control Driver (SNC) Readme
Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net>
Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
-This mini-driver drives the SNC device present in the ACPI BIOS of
-the Sony Vaio laptops.
+This mini-driver drives the SNC and SPIC device present in the ACPI BIOS of the
+Sony Vaio laptops. This driver mixes both devices functions under the same
+(hopefully consistent) interface. This also means that the sonypi driver is
+obsoleted by sony-laptop now.
-It gives access to some extra laptop functionalities. In its current
-form, this driver let the user set or query the screen brightness
-through the backlight subsystem and remove/apply power to some devices.
+Fn keys (hotkeys):
+------------------
+Some models report hotkeys through the SNC or SPIC devices, such events are
+reported both through the ACPI subsystem as acpi events and through the INPUT
+subsystem. See the logs of acpid or /proc/acpi/event and
+/proc/bus/input/devices to find out what those events are and which input
+devices are created by the driver.
Backlight control:
------------------
@@ -39,6 +45,8 @@ The files are:
audiopower power on/off the internal sound card
lanpower power on/off the internal ethernet card
(only in debug mode)
+ bluetoothpower power on/off the internal bluetooth device
+ fanspeed get/set the fan speed
Note that some files may be missing if they are not supported
by your particular laptop model.
@@ -76,9 +84,9 @@ The sony-laptop driver creates, for some of those methods (the most
current ones found on several Vaio models), an entry under
/sys/devices/platform/sony-laptop, just like the 'cdpower' one.
You can create other entries corresponding to your own laptop methods by
-further editing the source (see the 'sony_acpi_values' table, and add a new
+further editing the source (see the 'sony_nc_values' table, and add a new
entry to this table with your get/set method names using the
-HANDLE_NAMES macro).
+SNC_HANDLE_NAMES macro).
Your mission, should you accept it, is to try finding out what
those entries are for, by reading/writing random values from/to those
@@ -87,6 +95,9 @@ files and find out what is the impact on your laptop.
Should you find anything interesting, please report it back to me,
I will not disavow all knowledge of your actions :)
+See also http://www.linux.it/~malattia/wiki/index.php/Sony_drivers for other
+useful info.
+
Bugs/Limitations:
-----------------
diff --git a/Documentation/ibm-acpi.txt b/Documentation/thinkpad-acpi.txt
index 0132d363feb5..2d4803359a04 100644
--- a/Documentation/ibm-acpi.txt
+++ b/Documentation/thinkpad-acpi.txt
@@ -1,16 +1,22 @@
- IBM ThinkPad ACPI Extras Driver
+ ThinkPad ACPI Extras Driver
- Version 0.12
- 17 August 2005
+ Version 0.14
+ April 21st, 2007
Borislav Deianov <borislav@users.sf.net>
+ Henrique de Moraes Holschuh <hmh@hmh.eng.br>
http://ibm-acpi.sf.net/
-This is a Linux ACPI driver for the IBM ThinkPad laptops. It supports
-various features of these laptops which are accessible through the
-ACPI framework but not otherwise supported by the generic Linux ACPI
-drivers.
+This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It
+supports various features of these laptops which are accessible
+through the ACPI and ACPI EC framework, but not otherwise fully
+supported by the generic Linux ACPI drivers.
+
+This driver used to be named ibm-acpi until kernel 2.6.21 and release
+0.13-20070314. It used to be in the drivers/acpi tree, but it was
+moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
+2.6.22, and release 0.14.
Status
@@ -21,7 +27,7 @@ detailed description):
- Fn key combinations
- Bluetooth enable and disable
- - video output switching, expansion control
+ - video output switching, expansion control
- ThinkLight on and off
- limited docking and undocking
- UltraBay eject
@@ -32,7 +38,7 @@ detailed description):
- Experimental: embedded controller register dump
- LCD brightness control
- Volume control
- - Experimental: fan speed, fan enable/disable
+ - Fan control and monitoring: fan speed, fan enable/disable
- Experimental: WAN enable and disable
A compatibility table by model and feature is maintained on the web
@@ -42,6 +48,8 @@ Please include the following information in your report:
- ThinkPad model name
- a copy of your DSDT, from /proc/acpi/dsdt
+ - a copy of the output of dmidecode, with serial numbers
+ and UUIDs masked off
- which driver features work and which don't
- the observed behavior of non-working features
@@ -52,25 +60,85 @@ Installation
------------
If you are compiling this driver as included in the Linux kernel
-sources, simply enable the CONFIG_ACPI_IBM option (Power Management /
-ACPI / IBM ThinkPad Laptop Extras).
+sources, simply enable the CONFIG_THINKPAD_ACPI option, and optionally
+enable the CONFIG_THINKPAD_ACPI_BAY option if you want the
+thinkpad-specific bay functionality.
Features
--------
-The driver creates the /proc/acpi/ibm directory. There is a file under
-that directory for each feature described below. Note that while the
-driver is still in the alpha stage, the exact proc file format and
-commands supported by the various features is guaranteed to change
-frequently.
+The driver exports two different interfaces to userspace, which can be
+used to access the features it provides. One is a legacy procfs-based
+interface, which will be removed at some time in the distant future.
+The other is a new sysfs-based interface which is not complete yet.
-Driver version -- /proc/acpi/ibm/driver
----------------------------------------
+The procfs interface creates the /proc/acpi/ibm directory. There is a
+file under that directory for each feature it supports. The procfs
+interface is mostly frozen, and will change very little if at all: it
+will not be extended to add any new functionality in the driver, instead
+all new functionality will be implemented on the sysfs interface.
+
+The sysfs interface tries to blend in the generic Linux sysfs subsystems
+and classes as much as possible. Since some of these subsystems are not
+yet ready or stabilized, it is expected that this interface will change,
+and any and all userspace programs must deal with it.
+
+
+Notes about the sysfs interface:
+
+Unlike what was done with the procfs interface, correctness when talking
+to the sysfs interfaces will be enforced, as will correctness in the
+thinkpad-acpi's implementation of sysfs interfaces.
+
+Also, any bugs in the thinkpad-acpi sysfs driver code or in the
+thinkpad-acpi's implementation of the sysfs interfaces will be fixed for
+maximum correctness, even if that means changing an interface in
+non-compatible ways. As these interfaces mature both in the kernel and
+in thinkpad-acpi, such changes should become quite rare.
+
+Applications interfacing to the thinkpad-acpi sysfs interfaces must
+follow all sysfs guidelines and correctly process all errors (the sysfs
+interface makes extensive use of errors). File descriptors and open /
+close operations to the sysfs inodes must also be properly implemented.
+
+The version of thinkpad-acpi's sysfs interface is exported by the driver
+as a driver attribute (see below).
+
+Sysfs driver attributes are on the driver's sysfs attribute space,
+for 2.6.20 this is /sys/bus/platform/drivers/thinkpad-acpi/.
+
+Sysfs device attributes are on the driver's sysfs attribute space,
+for 2.6.20 this is /sys/devices/platform/thinkpad-acpi/.
+
+Driver version
+--------------
+
+procfs: /proc/acpi/ibm/driver
+sysfs driver attribute: version
The driver name and version. No commands can be written to this file.
-Hot keys -- /proc/acpi/ibm/hotkey
----------------------------------
+Sysfs interface version
+-----------------------
+
+sysfs driver attribute: interface_version
+
+Version of the thinkpad-acpi sysfs interface, as an unsigned long
+(output in hex format: 0xAAAABBCC), where:
+ AAAA - major revision
+ BB - minor revision
+ CC - bugfix revision
+
+The sysfs interface version changelog for the driver can be found at the
+end of this document. Changes to the sysfs interface done by the kernel
+subsystems are not documented here, nor are they tracked by this
+attribute.
+
+Hot keys
+--------
+
+procfs: /proc/acpi/ibm/hotkey
+sysfs device attribute: hotkey/*
Without this driver, only the Fn-F4 key (sleep button) generates an
ACPI event. With the driver loaded, the hotkey feature enabled and the
@@ -84,15 +152,6 @@ All labeled Fn-Fx key combinations generate distinct events. In
addition, the lid microswitch and some docking station buttons may
also generate such events.
-The following commands can be written to this file:
-
- echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
- echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
- echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
- echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
- ... any other 4-hex-digit mask ...
- echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
-
The bit mask allows some control over which hot keys generate ACPI
events. Not all bits in the mask can be modified. Not all bits that
can be modified do anything. Not all hot keys can be individually
@@ -124,15 +183,77 @@ buttons do not generate ACPI events even with this driver. They *can*
be used through the "ThinkPad Buttons" utility, see
http://www.nongnu.org/tpb/
-Bluetooth -- /proc/acpi/ibm/bluetooth
--------------------------------------
+procfs notes:
+
+The following commands can be written to the /proc/acpi/ibm/hotkey file:
+
+ echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
+ echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
+ echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
+ echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
+ ... any other 4-hex-digit mask ...
+ echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
+
+sysfs notes:
+
+ The hot keys attributes are in a hotkey/ subdirectory off the
+ thinkpad device.
+
+ bios_enabled:
+ Returns the status of the hot keys feature when
+ thinkpad-acpi was loaded. Upon module unload, the hot
+ key feature status will be restored to this value.
+
+ 0: hot keys were disabled
+ 1: hot keys were enabled
+
+ bios_mask:
+ Returns the hot keys mask when thinkpad-acpi was loaded.
+ Upon module unload, the hot keys mask will be restored
+ to this value.
+
+ enable:
+ Enables/disables the hot keys feature, and reports
+ current status of the hot keys feature.
+
+ 0: disables the hot keys feature / feature disabled
+ 1: enables the hot keys feature / feature enabled
+
+ mask:
+ bit mask to enable ACPI event generation for each hot
+ key (see above). Returns the current status of the hot
+ keys mask, and allows one to modify it.
+
-This feature shows the presence and current state of a Bluetooth
-device. If Bluetooth is installed, the following commands can be used:
+Bluetooth
+---------
+
+procfs: /proc/acpi/ibm/bluetooth
+sysfs device attribute: bluetooth/enable
+
+This feature shows the presence and current state of a ThinkPad
+Bluetooth device in the internal ThinkPad CDC slot.
+
+Procfs notes:
+
+If Bluetooth is installed, the following commands can be used:
echo enable > /proc/acpi/ibm/bluetooth
echo disable > /proc/acpi/ibm/bluetooth
+Sysfs notes:
+
+ If the Bluetooth CDC card is installed, it can be enabled /
+ disabled through the "bluetooth/enable" thinkpad-acpi device
+ attribute, and its current status can also be queried.
+
+ enable:
+ 0: disables Bluetooth / Bluetooth is disabled
+ 1: enables Bluetooth / Bluetooth is enabled.
+
+ Note: this interface will be probably be superseeded by the
+ generic rfkill class.
+
Video output control -- /proc/acpi/ibm/video
--------------------------------------------
@@ -209,7 +330,7 @@ hot plugging of devices in the Linux ACPI framework. If the laptop was
booted while not in the dock, the following message is shown in the
logs:
- Mar 17 01:42:34 aero kernel: ibm_acpi: dock device not present
+ Mar 17 01:42:34 aero kernel: thinkpad_acpi: dock device not present
In this case, no dock-related events are generated but the dock and
undock commands described below still work. They can be executed
@@ -269,7 +390,7 @@ This is due to the current lack of support for hot plugging of devices
in the Linux ACPI framework. If the laptop was booted without the
UltraBay, the following message is shown in the logs:
- Mar 17 01:42:34 aero kernel: ibm_acpi: bay device not present
+ Mar 17 01:42:34 aero kernel: thinkpad_acpi: bay device not present
In this case, no bay-related events are generated but the eject
command described below still works. It can be executed manually or
@@ -313,23 +434,19 @@ supported. Use "eject2" instead of "eject" for the second bay.
Note: the UltraBay eject support on the 600e/x, A22p and A3x is
EXPERIMENTAL and may not work as expected. USE WITH CAUTION!
-CMOS control -- /proc/acpi/ibm/cmos
------------------------------------
+CMOS control
+------------
+
+procfs: /proc/acpi/ibm/cmos
+sysfs device attribute: cmos_command
This feature is used internally by the ACPI firmware to control the
ThinkLight on most newer ThinkPad models. It may also control LCD
brightness, sounds volume and more, but only on some models.
-The commands are non-negative integer numbers:
-
- echo 0 >/proc/acpi/ibm/cmos
- echo 1 >/proc/acpi/ibm/cmos
- echo 2 >/proc/acpi/ibm/cmos
- ...
-
-The range of valid numbers is 0 to 21, but not all have an effect and
-the behavior varies from model to model. Here is the behavior on the
-X40 (tpb is the ThinkPad Buttons utility):
+The range of valid cmos command numbers is 0 to 21, but not all have an
+effect and the behavior varies from model to model. Here is the behavior
+on the X40 (tpb is the ThinkPad Buttons utility):
0 - no effect but tpb reports "Volume down"
1 - no effect but tpb reports "Volume up"
@@ -342,6 +459,9 @@ X40 (tpb is the ThinkPad Buttons utility):
13 - ThinkLight off
14 - no effect but tpb reports ThinkLight status change
+The cmos command interface is prone to firmware split-brain problems, as
+in newer ThinkPads it is just a compatibility layer.
+
LED control -- /proc/acpi/ibm/led
---------------------------------
@@ -393,17 +513,17 @@ X40:
16 - one medium-pitched beep repeating constantly, stop with 17
17 - stop 16
-Temperature sensors -- /proc/acpi/ibm/thermal
----------------------------------------------
+Temperature sensors
+-------------------
+
+procfs: /proc/acpi/ibm/thermal
+sysfs device attributes: (hwmon) temp*_input
Most ThinkPads include six or more separate temperature sensors but
only expose the CPU temperature through the standard ACPI methods.
This feature shows readings from up to eight different sensors on older
ThinkPads, and it has experimental support for up to sixteen different
-sensors on newer ThinkPads. Readings from sensors that are not available
-return -128.
-
-No commands can be written to this file.
+sensors on newer ThinkPads.
EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the
implementation directly accesses hardware registers and may not work as
@@ -460,6 +580,20 @@ The A31 has a very atypical layout for the thermal sensors
8: Bay Battery: secondary sensor
+Procfs notes:
+ Readings from sensors that are not available return -128.
+ No commands can be written to this file.
+
+Sysfs notes:
+ Sensors that are not available return the ENXIO error. This
+ status may change at runtime, as there are hotplug thermal
+ sensors, like those inside the batteries and docks.
+
+ thinkpad-acpi thermal sensors are reported through the hwmon
+ subsystem, and follow all of the hwmon guidelines at
+ Documentation/hwmon.
+
+
EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
------------------------------------------------------------------------
@@ -472,7 +606,7 @@ This feature dumps the values of 256 embedded controller
registers. Values which have changed since the last time the registers
were dumped are marked with a star:
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
+[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00
EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00
@@ -503,7 +637,7 @@ vary. The second ensures that the fan-related values do vary, since
the fan speed fluctuates a bit. The third will (hopefully) mark the
fan register with a star:
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
+[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00
EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00
@@ -533,19 +667,59 @@ registers contain the current battery capacity, etc. If you experiment
with this, do send me your results (including some complete dumps with
a description of the conditions when they were taken.)
-LCD brightness control -- /proc/acpi/ibm/brightness
----------------------------------------------------
+LCD brightness control
+----------------------
+
+procfs: /proc/acpi/ibm/brightness
+sysfs backlight device "thinkpad_screen"
This feature allows software control of the LCD brightness on ThinkPad
-models which don't have a hardware brightness slider. The available
-commands are:
+models which don't have a hardware brightness slider.
+
+It has some limitations: the LCD backlight cannot be actually turned on or off
+by this interface, and in many ThinkPad models, the "dim while on battery"
+functionality will be enabled by the BIOS when this interface is used, and
+cannot be controlled.
+
+The backlight control has eight levels, ranging from 0 to 7. Some of the
+levels may not be distinct.
+
+Procfs notes:
+
+ The available commands are:
echo up >/proc/acpi/ibm/brightness
echo down >/proc/acpi/ibm/brightness
echo 'level <level>' >/proc/acpi/ibm/brightness
-The <level> number range is 0 to 7, although not all of them may be
-distinct. The current brightness level is shown in the file.
+Sysfs notes:
+
+The interface is implemented through the backlight sysfs class, which is poorly
+documented at this time.
+
+Locate the thinkpad_screen device under /sys/class/backlight, and inside it
+there will be the following attributes:
+
+ max_brightness:
+ Reads the maximum brightness the hardware can be set to.
+ The minimum is always zero.
+
+ actual_brightness:
+ Reads what brightness the screen is set to at this instant.
+
+ brightness:
+ Writes request the driver to change brightness to the given
+ value. Reads will tell you what brightness the driver is trying
+ to set the display to when "power" is set to zero and the display
+ has not been dimmed by a kernel power management event.
+
+ power:
+ power management mode, where 0 is "display on", and 1 to 3 will
+ dim the display backlight to brightness level 0 because
+ thinkpad-acpi cannot really turn the backlight off. Kernel
+ power management events can temporarily increase the current
+ power management level, i.e. they can dim the display.
+
Volume control -- /proc/acpi/ibm/volume
---------------------------------------
@@ -563,41 +737,42 @@ distinct. The unmute the volume after the mute command, use either the
up or down command (the level command will not unmute the volume).
The current volume level and mute state is shown in the file.
-EXPERIMENTAL: fan speed, fan enable/disable -- /proc/acpi/ibm/fan
------------------------------------------------------------------
+Fan control and monitoring: fan speed, fan enable/disable
+---------------------------------------------------------
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
+procfs: /proc/acpi/ibm/fan
+sysfs device attributes: (hwmon) fan_input, pwm1, pwm1_enable
+
+NOTE NOTE NOTE: fan control operations are disabled by default for
+safety reasons. To enable them, the module parameter "fan_control=1"
+must be given to thinkpad-acpi.
This feature attempts to show the current fan speed, control mode and
other fan data that might be available. The speed is read directly
from the hardware registers of the embedded controller. This is known
-to work on later R, T and X series ThinkPads but may show a bogus
+to work on later R, T, X and Z series ThinkPads but may show a bogus
value on other models.
-Most ThinkPad fans work in "levels". Level 0 stops the fan. The higher
-the level, the higher the fan speed, although adjacent levels often map
-to the same fan speed. 7 is the highest level, where the fan reaches
-the maximum recommended speed. Level "auto" means the EC changes the
-fan level according to some internal algorithm, usually based on
-readings from the thermal sensors. Level "disengaged" means the EC
-disables the speed-locked closed-loop fan control, and drives the fan as
-fast as it can go, which might exceed hardware limits, so use this level
-with caution.
+Fan levels:
-The fan usually ramps up or down slowly from one speed to another,
-and it is normal for the EC to take several seconds to react to fan
-commands.
+Most ThinkPad fans work in "levels" at the firmware interface. Level 0
+stops the fan. The higher the level, the higher the fan speed, although
+adjacent levels often map to the same fan speed. 7 is the highest
+level, where the fan reaches the maximum recommended speed.
-The fan may be enabled or disabled with the following commands:
+Level "auto" means the EC changes the fan level according to some
+internal algorithm, usually based on readings from the thermal sensors.
- echo enable >/proc/acpi/ibm/fan
- echo disable >/proc/acpi/ibm/fan
+There is also a "full-speed" level, also known as "disengaged" level.
+In this level, the EC disables the speed-locked closed-loop fan control,
+and drives the fan as fast as it can go, which might exceed hardware
+limits, so use this level with caution.
-Placing a fan on level 0 is the same as disabling it. Enabling a fan
-will try to place it in a safe level if it is too slow or disabled.
+The fan usually ramps up or down slowly from one speed to another, and
+it is normal for the EC to take several seconds to react to fan
+commands. The full-speed level may take up to two minutes to ramp up to
+maximum speed, and in some ThinkPads, the tachometer readings go stale
+while the EC is transitioning to the full-speed level.
WARNING WARNING WARNING: do not leave the fan disabled unless you are
monitoring all of the temperature sensor readings and you are ready to
@@ -615,46 +790,146 @@ fan is turned off when the CPU temperature drops to 49 degrees and the
HDD temperature drops to 41 degrees. These thresholds cannot
currently be controlled.
+The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
+certain conditions are met. It will override any fan programming done
+through thinkpad-acpi.
+
+The thinkpad-acpi kernel driver can be programmed to revert the fan
+level to a safe setting if userspace does not issue one of the procfs
+fan commands: "enable", "disable", "level" or "watchdog", or if there
+are no writes to pwm1_enable (or to pwm1 *if and only if* pwm1_enable is
+set to 1, manual mode) within a configurable amount of time of up to
+120 seconds. This functionality is called fan safety watchdog.
+
+Note that the watchdog timer stops after it enables the fan. It will be
+rearmed again automatically (using the same interval) when one of the
+above mentioned fan commands is received. The fan watchdog is,
+therefore, not suitable to protect against fan mode changes made through
+means other than the "enable", "disable", and "level" procfs fan
+commands, or the hwmon fan control sysfs interface.
+
+Procfs notes:
+
+The fan may be enabled or disabled with the following commands:
+
+ echo enable >/proc/acpi/ibm/fan
+ echo disable >/proc/acpi/ibm/fan
+
+Placing a fan on level 0 is the same as disabling it. Enabling a fan
+will try to place it in a safe level if it is too slow or disabled.
+
The fan level can be controlled with the command:
- echo 'level <level>' > /proc/acpi/ibm/thermal
+ echo 'level <level>' > /proc/acpi/ibm/fan
-Where <level> is an integer from 0 to 7, or one of the words "auto"
-or "disengaged" (without the quotes). Not all ThinkPads support the
-"auto" and "disengaged" levels.
+Where <level> is an integer from 0 to 7, or one of the words "auto" or
+"full-speed" (without the quotes). Not all ThinkPads support the "auto"
+and "full-speed" levels. The driver accepts "disengaged" as an alias for
+"full-speed", and reports it as "disengaged" for backwards
+compatibility.
On the X31 and X40 (and ONLY on those models), the fan speed can be
-controlled to a certain degree. Once the fan is running, it can be
+controlled to a certain degree. Once the fan is running, it can be
forced to run faster or slower with the following command:
- echo 'speed <speed>' > /proc/acpi/ibm/thermal
+ echo 'speed <speed>' > /proc/acpi/ibm/fan
-The sustainable range of fan speeds on the X40 appears to be from
-about 3700 to about 7350. Values outside this range either do not have
-any effect or the fan speed eventually settles somewhere in that
-range. The fan cannot be stopped or started with this command.
+The sustainable range of fan speeds on the X40 appears to be from about
+3700 to about 7350. Values outside this range either do not have any
+effect or the fan speed eventually settles somewhere in that range. The
+fan cannot be stopped or started with this command. This functionality
+is incomplete, and not available through the sysfs interface.
-The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
-certain conditions are met. It will override any fan programming done
-through ibm-acpi.
+To program the safety watchdog, use the "watchdog" command.
-EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
----------------------------------------
+ echo 'watchdog <interval in seconds>' > /proc/acpi/ibm/fan
+
+If you want to disable the watchdog, use 0 as the interval.
+
+Sysfs notes:
+
+The sysfs interface follows the hwmon subsystem guidelines for the most
+part, and the exception is the fan safety watchdog.
+
+Writes to any of the sysfs attributes may return the EINVAL error if
+that operation is not supported in a given ThinkPad or if the parameter
+is out-of-bounds, and EPERM if it is forbidden. They may also return
+EINTR (interrupted system call), and EIO (I/O error while trying to talk
+to the firmware).
+
+Features not yet implemented by the driver return ENOSYS.
+
+hwmon device attribute pwm1_enable:
+ 0: PWM offline (fan is set to full-speed mode)
+ 1: Manual PWM control (use pwm1 to set fan level)
+ 2: Hardware PWM control (EC "auto" mode)
+ 3: reserved (Software PWM control, not implemented yet)
+
+ Modes 0 and 2 are not supported by all ThinkPads, and the
+ driver is not always able to detect this. If it does know a
+ mode is unsupported, it will return -EINVAL.
+
+hwmon device attribute pwm1:
+ Fan level, scaled from the firmware values of 0-7 to the hwmon
+ scale of 0-255. 0 means fan stopped, 255 means highest normal
+ speed (level 7).
+
+ This attribute only commands the fan if pmw1_enable is set to 1
+ (manual PWM control).
+
+hwmon device attribute fan1_input:
+ Fan tachometer reading, in RPM. May go stale on certain
+ ThinkPads while the EC transitions the PWM to offline mode,
+ which can take up to two minutes. May return rubbish on older
+ ThinkPads.
+
+driver attribute fan_watchdog:
+ Fan safety watchdog timer interval, in seconds. Minimum is
+ 1 second, maximum is 120 seconds. 0 disables the watchdog.
+
+To stop the fan: set pwm1 to zero, and pwm1_enable to 1.
+
+To start the fan in a safe mode: set pwm1_enable to 2. If that fails
+with EINVAL, try to set pwm1_enable to 1 and pwm1 to at least 128 (255
+would be the safest choice, though).
+
+
+EXPERIMENTAL: WAN
+-----------------
+
+procfs: /proc/acpi/ibm/wan
+sysfs device attribute: wwan/enable
This feature is marked EXPERIMENTAL because the implementation
directly accesses hardware registers and may not work as expected. USE
WITH CAUTION! To use this feature, you need to supply the
experimental=1 parameter when loading the module.
-This feature shows the presence and current state of a WAN (Sierra
-Wireless EV-DO) device. If WAN is installed, the following commands can
-be used:
+This feature shows the presence and current state of a W-WAN (Sierra
+Wireless EV-DO) device.
+
+It was tested on a Lenovo Thinkpad X60. It should probably work on other
+Thinkpad models which come with this module installed.
+
+Procfs notes:
+
+If the W-WAN card is installed, the following commands can be used:
echo enable > /proc/acpi/ibm/wan
echo disable > /proc/acpi/ibm/wan
-It was tested on a Lenovo Thinkpad X60. It should probably work on other
-Thinkpad models which come with this module installed.
+Sysfs notes:
+
+ If the W-WAN card is installed, it can be enabled /
+ disabled through the "wwan/enable" thinkpad-acpi device
+ attribute, and its current status can also be queried.
+
+ enable:
+ 0: disables WWAN card / WWAN card is disabled
+ 1: enables WWAN card / WWAN card is enabled.
+
+ Note: this interface will be probably be superseeded by the
+ generic rfkill class.
Multiple Commands, Module Parameters
------------------------------------
@@ -665,64 +940,42 @@ separating them with commas, for example:
echo enable,0xffff > /proc/acpi/ibm/hotkey
echo lcd_disable,crt_enable > /proc/acpi/ibm/video
-Commands can also be specified when loading the ibm_acpi module, for
-example:
-
- modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable
-
-The ibm-acpi kernel driver can be programmed to revert the fan level
-to a safe setting if userspace does not issue one of the fan commands:
-"enable", "disable", "level" or "watchdog" within a configurable
-ammount of time. To do this, use the "watchdog" command.
-
- echo 'watchdog <interval>' > /proc/acpi/ibm/fan
-
-Interval is the ammount of time in seconds to wait for one of the
-above mentioned fan commands before reseting the fan level to a safe
-one. If set to zero, the watchdog is disabled (default). When the
-watchdog timer runs out, it does the exact equivalent of the "enable"
-fan command.
-
-Note that the watchdog timer stops after it enables the fan. It will
-be rearmed again automatically (using the same interval) when one of
-the above mentioned fan commands is received. The fan watchdog is,
-therefore, not suitable to protect against fan mode changes made
-through means other than the "enable", "disable", and "level" fan
-commands.
-
-
-Example Configuration
----------------------
-
-The ACPI support in the kernel is intended to be used in conjunction
-with a user-space daemon, acpid. The configuration files for this
-daemon control what actions are taken in response to various ACPI
-events. An example set of configuration files are included in the
-config/ directory of the tarball package available on the web
-site. Note that these are provided for illustration purposes only and
-may need to be adapted to your particular setup.
-
-The following utility scripts are used by the example action
-scripts (included with ibm-acpi for completeness):
-
- /usr/local/sbin/idectl -- from the hdparm source distribution,
- see http://www.ibiblio.org/pub/Linux/system/hardware
- /usr/local/sbin/laptop_mode -- from the Linux kernel source
- distribution, see Documentation/laptop-mode.txt
- /sbin/service -- comes with Redhat/Fedora distributions
- /usr/sbin/hibernate -- from the Software Suspend 2 distribution,
- see http://softwaresuspend.berlios.de/
-
-Toan T Nguyen <ntt@physics.ucla.edu> notes that Suse uses the
-powersave program to suspend ('powersave --suspend-to-ram') or
-hibernate ('powersave --suspend-to-disk'). This means that the
-hibernate script is not needed on that distribution.
-
-Henrik Brix Andersen <brix@gentoo.org> has written a Gentoo ACPI event
-handler script for the X31. You can get the latest version from
-http://dev.gentoo.org/~brix/files/x31.sh
-
-David Schweikert <dws@ee.eth.ch> has written an alternative blank.sh
-script which works on Debian systems. This scripts has now been
-extended to also work on Fedora systems and included as the default
-blank.sh in the distribution.
+Commands can also be specified when loading the thinkpad-acpi module,
+for example:
+
+ modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable
+
+Enabling debugging output
+-------------------------
+
+The module takes a debug paramater which can be used to selectively
+enable various classes of debugging output, for example:
+
+ modprobe ibm_acpi debug=0xffff
+
+will enable all debugging output classes. It takes a bitmask, so
+to enable more than one output class, just add their values.
+
+ Debug bitmask Description
+ 0x0001 Initialization and probing
+ 0x0002 Removal
+
+There is also a kernel build option to enable more debugging
+information, which may be necessary to debug driver problems.
+
+The level of debugging information output by the driver can be changed
+at runtime through sysfs, using the driver attribute debug_level. The
+attribute takes the same bitmask as the debug module parameter above.
+
+Force loading of module
+-----------------------
+
+If thinkpad-acpi refuses to detect your ThinkPad, you can try to specify
+the module parameter force_load=1. Regardless of whether this works or
+not, please contact ibm-acpi-devel@lists.sourceforge.net with a report.
+
+
+Sysfs interface changelog:
+
+0x000100: Initial sysfs support, as a single platform driver and
+ device.
diff --git a/Documentation/video4linux/meye.txt b/Documentation/video4linux/meye.txt
index ecb34160e61d..5e51c59bf2b0 100644
--- a/Documentation/video4linux/meye.txt
+++ b/Documentation/video4linux/meye.txt
@@ -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.
diff --git a/MAINTAINERS b/MAINTAINERS
index 77bff8ce1a44..af1c7926c153 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index f4efd66e1ee5..c96911c37aea 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -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
diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c
index a7d22d9f3d7e..8f7efd38254d 100644
--- a/arch/i386/kernel/acpi/earlyquirk.c
+++ b/arch/i386/kernel/acpi/earlyquirk.c
@@ -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 "
diff --git a/arch/mips/mips-boards/sim/Makefile b/arch/mips/mips-boards/sim/Makefile
index 6aeebc9122f2..dc0bfda11427 100644
--- a/arch/mips/mips-boards/sim/Makefile
+++ b/arch/mips/mips-boards/sim/Makefile
@@ -17,7 +17,8 @@
# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#
-obj-y := sim_setup.o sim_mem.o sim_time.o sim_int.o sim_cmdline.o
+obj-y := sim_platform.o sim_setup.o sim_mem.o sim_time.o sim_int.o \
+ sim_cmdline.o
obj-$(CONFIG_EARLY_PRINTK) += sim_console.o
obj-$(CONFIG_SMP) += sim_smp.o
diff --git a/arch/mips/mips-boards/sim/sim_platform.c b/arch/mips/mips-boards/sim/sim_platform.c
new file mode 100644
index 000000000000..53210a8c5dec
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_platform.c
@@ -0,0 +1,35 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007 by Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/init.h>
+#include <linux/if_ether.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+static char mipsnet_string[] = "mipsnet";
+
+static struct platform_device eth1_device = {
+ .name = mipsnet_string,
+ .id = 0,
+};
+
+/*
+ * Create a platform device for the GPI port that receives the
+ * image data from the embedded camera.
+ */
+static int __init mipsnet_devinit(void)
+{
+ int err;
+
+ err = platform_device_register(&eth1_device);
+ if (err)
+ printk(KERN_ERR "%s: registration failed\n", mipsnet_string);
+
+ return err;
+}
+
+device_initcall(mipsnet_devinit);
diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig
index 782906b644dd..eb2f9a3d515c 100644
--- a/arch/parisc/configs/c3000_defconfig
+++ b/arch/parisc/configs/c3000_defconfig
@@ -435,7 +435,6 @@ CONFIG_SCSI_SATA_SIL=m
# CONFIG_SCSI_SATA_ULI is not set
CONFIG_SCSI_SATA_VIA=m
# CONFIG_SCSI_SATA_VITESSE is not set
-CONFIG_SCSI_SATA_INTEL_COMBINED=y
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_IPS is not set
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 6dfbd52694ab..a54a9a2e36f3 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -11,6 +11,11 @@ config PPC64
This option selects whether a 32-bit or a 64-bit kernel
will be built.
+config PPC_PM_NEEDS_RTC_LIB
+ bool
+ select RTC_LIB
+ default y if PM
+
config PPC32
bool
default y if !PPC64
@@ -89,7 +94,7 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER
config ARCH_MAY_HAVE_PC_FDC
bool
- default y
+ default !PPC_PSERIES || PCI
config PPC_OF
def_bool y
@@ -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"
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index d39d13327e6d..86aa3745af7f 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -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)"
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index a00fe7236555..794992025d8d 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -102,9 +102,9 @@ CFLAGS += $(call cc-option,-mno-altivec)
# kernel considerably.
CFLAGS += $(call cc-option,-funit-at-a-time)
-ifndef CONFIG_FSL_BOOKE
-CFLAGS += -mstring
-endif
+# Never use string load/store instructions as they are
+# often slow when they are implemented at all
+CFLAGS += -mno-string
ifeq ($(CONFIG_6xx),y)
CFLAGS += -mcpu=powerpc
@@ -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)
diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore
index 0734b2fc1d95..eec7af7e5993 100644
--- a/arch/powerpc/boot/.gitignore
+++ b/arch/powerpc/boot/.gitignore
@@ -18,6 +18,9 @@ kernel-vmlinux.strip.c
kernel-vmlinux.strip.gz
mktree
uImage
+cuImage
+cuImage.bin.gz
+cuImage.elf
zImage
zImage.chrp
zImage.coff
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index dc779407de14..3716594ea33e 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -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))
diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
index 70e65b13e033..5a4215c4b014 100644
--- a/arch/powerpc/boot/crt0.S
+++ b/arch/powerpc/boot/crt0.S
@@ -16,8 +16,11 @@
_zimage_start_opd:
.long _zimage_start, 0, 0, 0
+ .weak _zimage_start
.globl _zimage_start
_zimage_start:
+ .globl _zimage_start_lib
+_zimage_start_lib:
/* Work out the offset between the address we were linked at
and the address where we're running. */
bl 1f
@@ -44,7 +47,7 @@ _zimage_start:
addi r9,r9,4
bdnz 2b
- /* Do a cache flush for our text, in case OF didn't */
+ /* Do a cache flush for our text, in case the loader didn't */
3: lis r9,_start@ha
addi r9,r9,_start@l
add r9,r0,r9
@@ -59,6 +62,34 @@ _zimage_start:
sync
isync
- mr r6,r1
- b start
+ /* Clear the BSS */
+ lis r9,__bss_start@ha
+ addi r9,r9,__bss_start@l
+ add r9,r0,r9
+ lis r8,_end@ha
+ addi r8,r8,_end@l
+ add r8,r0,r8
+ li r10,0
+5: stw r10,0(r9)
+ addi r9,r9,4
+ cmplw cr0,r9,r8
+ blt 5b
+ /* Possibly set up a custom stack */
+.weak _platform_stack_top
+ lis r8,_platform_stack_top@ha
+ addi r8,r8,_platform_stack_top@l
+ cmpwi r8,0
+ beq 6f
+ add r8,r0,r8
+ lwz r1,0(r8)
+ add r1,r0,r1
+ li r0,0
+ stwu r0,-16(r1) /* establish a stack frame */
+6:
+
+ /* Call platform_init() */
+ bl platform_init
+
+ /* Call start */
+ b start
diff --git a/arch/powerpc/boot/cuboot-83xx.c b/arch/powerpc/boot/cuboot-83xx.c
new file mode 100644
index 000000000000..6cbc20afb4d8
--- /dev/null
+++ b/arch/powerpc/boot/cuboot-83xx.c
@@ -0,0 +1,68 @@
+/*
+ * Old U-boot compatibility for 83xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+
+#define TARGET_83xx
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+extern char _dtb_start[], _dtb_end[];
+
+static void platform_fixups(void)
+{
+ void *soc;
+
+ dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+ dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr);
+ dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq);
+
+ /* Unfortunately, the specific model number is encoded in the
+ * soc node name in existing dts files -- once that is fixed,
+ * this can do a simple path lookup.
+ */
+ soc = find_node_by_devtype(NULL, "soc");
+ if (soc) {
+ void *serial = NULL;
+
+ setprop(soc, "bus-frequency", &bd.bi_busfreq,
+ sizeof(bd.bi_busfreq));
+
+ while ((serial = find_node_by_devtype(serial, "serial"))) {
+ if (get_parent(serial) != soc)
+ continue;
+
+ setprop(serial, "clock-frequency", &bd.bi_busfreq,
+ sizeof(bd.bi_busfreq));
+ }
+ }
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+ unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+ memcpy(&bd, (bd_t *)r3, sizeof(bd));
+ loader_info.initrd_addr = r4;
+ loader_info.initrd_size = r4 ? r5 : 0;
+ loader_info.cmdline = (char *)r6;
+ loader_info.cmdline_len = r7 - r6;
+
+ simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+ ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ serial_console_init();
+ platform_ops.fixups = platform_fixups;
+}
diff --git a/arch/powerpc/boot/cuboot-85xx.c b/arch/powerpc/boot/cuboot-85xx.c
new file mode 100644
index 000000000000..f88ba00ac122
--- /dev/null
+++ b/arch/powerpc/boot/cuboot-85xx.c
@@ -0,0 +1,69 @@
+/*
+ * Old U-boot compatibility for 85xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+
+#define TARGET_85xx
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+extern char _dtb_start[], _dtb_end[];
+
+static void platform_fixups(void)
+{
+ void *soc;
+
+ dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+ dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr,
+ bd.bi_enet2addr);
+ dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 8, bd.bi_busfreq);
+
+ /* Unfortunately, the specific model number is encoded in the
+ * soc node name in existing dts files -- once that is fixed,
+ * this can do a simple path lookup.
+ */
+ soc = find_node_by_devtype(NULL, "soc");
+ if (soc) {
+ void *serial = NULL;
+
+ setprop(soc, "bus-frequency", &bd.bi_busfreq,
+ sizeof(bd.bi_busfreq));
+
+ while ((serial = find_node_by_devtype(serial, "serial"))) {
+ if (get_parent(serial) != soc)
+ continue;
+
+ setprop(serial, "clock-frequency", &bd.bi_busfreq,
+ sizeof(bd.bi_busfreq));
+ }
+ }
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+ unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+ memcpy(&bd, (bd_t *)r3, sizeof(bd));
+ loader_info.initrd_addr = r4;
+ loader_info.initrd_size = r4 ? r5 : 0;
+ loader_info.cmdline = (char *)r6;
+ loader_info.cmdline_len = r7 - r6;
+
+ simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+ ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ serial_console_init();
+ platform_ops.fixups = platform_fixups;
+}
diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c
new file mode 100644
index 000000000000..c9951550ed2c
--- /dev/null
+++ b/arch/powerpc/boot/devtree.c
@@ -0,0 +1,307 @@
+/*
+ * devtree.c - convenience functions for device tree manipulation
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * Authors: David Gibson <david@gibson.dropbear.id.au>
+ * Scott Wood <scottwood@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+
+void dt_fixup_memory(u64 start, u64 size)
+{
+ void *root, *memory;
+ int naddr, nsize, i;
+ u32 memreg[4];
+
+ root = finddevice("/");
+ if (getprop(root, "#address-cells", &naddr, sizeof(naddr)) < 0)
+ naddr = 2;
+ if (naddr < 1 || naddr > 2)
+ fatal("Can't cope with #address-cells == %d in /\n\r", naddr);
+
+ if (getprop(root, "#size-cells", &nsize, sizeof(nsize)) < 0)
+ nsize = 1;
+ if (nsize < 1 || nsize > 2)
+ fatal("Can't cope with #size-cells == %d in /\n\r", nsize);
+
+ i = 0;
+ if (naddr == 2)
+ memreg[i++] = start >> 32;
+ memreg[i++] = start & 0xffffffff;
+ if (nsize == 2)
+ memreg[i++] = size >> 32;
+ memreg[i++] = size & 0xffffffff;
+
+ memory = finddevice("/memory");
+ if (! memory) {
+ memory = create_node(NULL, "memory");
+ setprop_str(memory, "device_type", "memory");
+ }
+
+ printf("Memory <- <0x%x", memreg[0]);
+ for (i = 1; i < (naddr + nsize); i++)
+ printf(" 0x%x", memreg[i]);
+ printf("> (%ldMB)\n\r", (unsigned long)(size >> 20));
+
+ setprop(memory, "reg", memreg, (naddr + nsize)*sizeof(u32));
+}
+
+#define MHZ(x) ((x + 500000) / 1000000)
+
+void dt_fixup_cpu_clocks(u32 cpu, u32 tb, u32 bus)
+{
+ void *devp = NULL;
+
+ printf("CPU clock-frequency <- 0x%x (%dMHz)\n\r", cpu, MHZ(cpu));
+ printf("CPU timebase-frequency <- 0x%x (%dMHz)\n\r", tb, MHZ(tb));
+ if (bus > 0)
+ printf("CPU bus-frequency <- 0x%x (%dMHz)\n\r", bus, MHZ(bus));
+
+ while ((devp = find_node_by_devtype(devp, "cpu"))) {
+ setprop_val(devp, "clock-frequency", cpu);
+ setprop_val(devp, "timebase-frequency", tb);
+ if (bus > 0)
+ setprop_val(devp, "bus-frequency", bus);
+ }
+}
+
+void dt_fixup_clock(const char *path, u32 freq)
+{
+ void *devp = finddevice(path);
+
+ if (devp) {
+ printf("%s: clock-frequency <- %x (%dMHz)\n\r", path, freq, MHZ(freq));
+ setprop_val(devp, "clock-frequency", freq);
+ }
+}
+
+void __dt_fixup_mac_addresses(u32 startindex, ...)
+{
+ va_list ap;
+ u32 index = startindex;
+ void *devp;
+ const u8 *addr;
+
+ va_start(ap, startindex);
+ while ((addr = va_arg(ap, const u8 *))) {
+ devp = find_node_by_prop_value(NULL, "linux,network-index",
+ (void*)&index, sizeof(index));
+
+ printf("ENET%d: local-mac-address <-"
+ " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index,
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+ if (devp)
+ setprop(devp, "local-mac-address", addr, 6);
+
+ index++;
+ }
+ va_end(ap);
+}
+
+#define MAX_ADDR_CELLS 4
+#define MAX_RANGES 8
+
+static void get_reg_format(void *node, u32 *naddr, u32 *nsize)
+{
+ if (getprop(node, "#address-cells", naddr, 4) != 4)
+ *naddr = 2;
+ if (getprop(node, "#size-cells", nsize, 4) != 4)
+ *nsize = 1;
+}
+
+static void copy_val(u32 *dest, u32 *src, int naddr)
+{
+ int pad = MAX_ADDR_CELLS - naddr;
+
+ memset(dest, 0, pad * 4);
+ memcpy(dest + pad, src, naddr * 4);
+}
+
+static int sub_reg(u32 *reg, u32 *sub)
+{
+ int i, borrow = 0;
+
+ for (i = MAX_ADDR_CELLS - 1; i >= 0; i--) {
+ int prev_borrow = borrow;
+ borrow = reg[i] < sub[i] + prev_borrow;
+ reg[i] -= sub[i] + prev_borrow;
+ }
+
+ return !borrow;
+}
+
+static int add_reg(u32 *reg, u32 *add, int naddr)
+{
+ int i, carry = 0;
+
+ for (i = MAX_ADDR_CELLS - 1; i >= MAX_ADDR_CELLS - naddr; i--) {
+ u64 tmp = (u64)reg[i] + add[i] + carry;
+ carry = tmp >> 32;
+ reg[i] = (u32)tmp;
+ }
+
+ return !carry;
+}
+
+/* It is assumed that if the first byte of reg fits in a
+ * range, then the whole reg block fits.
+ */
+static int compare_reg(u32 *reg, u32 *range, u32 *rangesize)
+{
+ int i;
+ u32 end;
+
+ for (i = 0; i < MAX_ADDR_CELLS; i++) {
+ if (reg[i] < range[i])
+ return 0;
+ if (reg[i] > range[i])
+ break;
+ }
+
+ for (i = 0; i < MAX_ADDR_CELLS; i++) {
+ end = range[i] + rangesize[i];
+
+ if (reg[i] < end)
+ break;
+ if (reg[i] > end)
+ return 0;
+ }
+
+ return reg[i] != end;
+}
+
+/* reg must be MAX_ADDR_CELLS */
+static int find_range(u32 *reg, u32 *ranges, int nregaddr,
+ int naddr, int nsize, int buflen)
+{
+ int nrange = nregaddr + naddr + nsize;
+ int i;
+
+ for (i = 0; i + nrange <= buflen; i += nrange) {
+ u32 range_addr[MAX_ADDR_CELLS];
+ u32 range_size[MAX_ADDR_CELLS];
+
+ copy_val(range_addr, ranges + i, naddr);
+ copy_val(range_size, ranges + i + nregaddr + naddr, nsize);
+
+ if (compare_reg(reg, range_addr, range_size))
+ return i;
+ }
+
+ return -1;
+}
+
+/* Currently only generic buses without special encodings are supported.
+ * In particular, PCI is not supported. Also, only the beginning of the
+ * reg block is tracked; size is ignored except in ranges.
+ */
+static u32 dt_xlate_buf[MAX_ADDR_CELLS * MAX_RANGES * 3];
+
+static int dt_xlate(void *node, int res, int reglen, unsigned long *addr,
+ unsigned long *size)
+{
+ u32 last_addr[MAX_ADDR_CELLS];
+ u32 this_addr[MAX_ADDR_CELLS];
+ void *parent;
+ u64 ret_addr, ret_size;
+ u32 naddr, nsize, prev_naddr;
+ int buflen, offset;
+
+ parent = get_parent(node);
+ if (!parent)
+ return 0;
+
+ get_reg_format(parent, &naddr, &nsize);
+
+ if (nsize > 2)
+ return 0;
+
+ offset = (naddr + nsize) * res;
+
+ if (reglen < offset + naddr + nsize ||
+ sizeof(dt_xlate_buf) < offset + naddr + nsize)
+ return 0;
+
+ copy_val(last_addr, dt_xlate_buf + offset, naddr);
+
+ ret_size = dt_xlate_buf[offset + naddr];
+ if (nsize == 2) {
+ ret_size <<= 32;
+ ret_size |= dt_xlate_buf[offset + naddr + 1];
+ }
+
+ while ((node = get_parent(node))) {
+ prev_naddr = naddr;
+
+ get_reg_format(node, &naddr, &nsize);
+
+ buflen = getprop(node, "ranges", dt_xlate_buf,
+ sizeof(dt_xlate_buf));
+ if (buflen < 0)
+ continue;
+ if (buflen > sizeof(dt_xlate_buf))
+ return 0;
+
+ offset = find_range(last_addr, dt_xlate_buf, prev_naddr,
+ naddr, nsize, buflen / 4);
+
+ if (offset < 0)
+ return 0;
+
+ copy_val(this_addr, dt_xlate_buf + offset, prev_naddr);
+
+ if (!sub_reg(last_addr, this_addr))
+ return 0;
+
+ copy_val(this_addr, dt_xlate_buf + offset + prev_naddr, naddr);
+
+ if (!add_reg(last_addr, this_addr, naddr))
+ return 0;
+ }
+
+ if (naddr > 2)
+ return 0;
+
+ ret_addr = ((u64)last_addr[2] << 32) | last_addr[3];
+
+ if (sizeof(void *) == 4 &&
+ (ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL ||
+ ret_addr + ret_size > 0x100000000ULL))
+ return 0;
+
+ *addr = ret_addr;
+ if (size)
+ *size = ret_size;
+
+ return 1;
+}
+
+int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size)
+{
+ int reglen;
+
+ reglen = getprop(node, "reg", dt_xlate_buf, sizeof(dt_xlate_buf)) / 4;
+ return dt_xlate(node, res, reglen, addr, size);
+}
+
+int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr)
+{
+
+ if (buflen > sizeof(dt_xlate_buf))
+ return 0;
+
+ memcpy(dt_xlate_buf, buf, buflen);
+ return dt_xlate(node, 0, buflen / 4, xlated_addr, NULL);
+}
diff --git a/arch/powerpc/boot/dts/kuroboxHD.dts b/arch/powerpc/boot/dts/kuroboxHD.dts
index b89791802e86..157dc98d3988 100644
--- a/arch/powerpc/boot/dts/kuroboxHD.dts
+++ b/arch/powerpc/boot/dts/kuroboxHD.dts
@@ -29,7 +29,6 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts"
cpus {
linux,phandle = <2000>;
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
@@ -126,17 +125,17 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts"
interrupt-parent = <4400>;
interrupt-map-mask = <f800 0 0 7>;
interrupt-map = <
- /* IDSEL 0x11 - IRQ0 ETH */
+ /* IDSEL 11 - IRQ0 ETH */
5800 0 0 1 4400 0 1
5800 0 0 2 4400 1 1
5800 0 0 3 4400 2 1
5800 0 0 4 4400 3 1
- /* IDSEL 0x12 - IRQ1 IDE0 */
+ /* IDSEL 12 - IRQ1 IDE0 */
6000 0 0 1 4400 1 1
6000 0 0 2 4400 2 1
6000 0 0 3 4400 3 1
6000 0 0 4 4400 0 1
- /* IDSEL 0x14 - IRQ3 USB2.0 */
+ /* IDSEL 14 - IRQ3 USB2.0 */
7000 0 0 1 4400 3 1
7000 0 0 2 4400 3 1
7000 0 0 3 4400 3 1
diff --git a/arch/powerpc/boot/dts/kuroboxHG.dts b/arch/powerpc/boot/dts/kuroboxHG.dts
index 753102752d8b..919eb29097db 100644
--- a/arch/powerpc/boot/dts/kuroboxHG.dts
+++ b/arch/powerpc/boot/dts/kuroboxHG.dts
@@ -29,7 +29,6 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts"
cpus {
linux,phandle = <2000>;
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
@@ -126,17 +125,17 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts"
interrupt-parent = <4400>;
interrupt-map-mask = <f800 0 0 7>;
interrupt-map = <
- /* IDSEL 0x11 - IRQ0 ETH */
+ /* IDSEL 11 - IRQ0 ETH */
5800 0 0 1 4400 0 1
5800 0 0 2 4400 1 1
5800 0 0 3 4400 2 1
5800 0 0 4 4400 3 1
- /* IDSEL 0x12 - IRQ1 IDE0 */
+ /* IDSEL 12 - IRQ1 IDE0 */
6000 0 0 1 4400 1 1
6000 0 0 2 4400 2 1
6000 0 0 3 4400 3 1
6000 0 0 4 4400 0 1
- /* IDSEL 0x14 - IRQ3 USB2.0 */
+ /* IDSEL 14 - IRQ3 USB2.0 */
7000 0 0 1 4400 3 1
7000 0 0 2 4400 3 1
7000 0 0 3 4400 3 1
diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts
index c03103c63285..ba54c6b40a09 100644
--- a/arch/powerpc/boot/dts/lite5200.dts
+++ b/arch/powerpc/boot/dts/lite5200.dts
@@ -24,7 +24,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts
index 3875ca9a9a62..2e003081b0d3 100644
--- a/arch/powerpc/boot/dts/lite5200b.dts
+++ b/arch/powerpc/boot/dts/lite5200b.dts
@@ -24,7 +24,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc7448hpc2.dts b/arch/powerpc/boot/dts/mpc7448hpc2.dts
index 41d0720c5900..6fa3754f293a 100644
--- a/arch/powerpc/boot/dts/mpc7448hpc2.dts
+++ b/arch/powerpc/boot/dts/mpc7448hpc2.dts
@@ -19,7 +19,6 @@
linux,phandle = <100>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells =<0>;
linux,phandle = <200>;
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 260b2e447779..423eedcf634f 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -17,7 +17,6 @@
linux,phandle = <100>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
linux,phandle = <200>;
diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts
index 6d721900d00e..a1533cc07d09 100644
--- a/arch/powerpc/boot/dts/mpc8313erdb.dts
+++ b/arch/powerpc/boot/dts/mpc8313erdb.dts
@@ -16,7 +16,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts
index 06b310698a02..c798491f4cd0 100644
--- a/arch/powerpc/boot/dts/mpc832x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc832x_mds.dts
@@ -16,7 +16,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
new file mode 100644
index 000000000000..b55bced1593d
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts
@@ -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>;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
index 61b550bf1645..db0d00303275 100644
--- a/arch/powerpc/boot/dts/mpc8349emitx.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -15,7 +15,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
index b2e1a5ec3779..f636528a3c72 100644
--- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
@@ -15,7 +15,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts
index e4b43c24bc0b..07bcc5194d2b 100644
--- a/arch/powerpc/boot/dts/mpc834x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc834x_mds.dts
@@ -16,7 +16,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index 4fe45c021848..7f578eb57082 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -21,7 +21,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts
index 3c0917fa791c..f261d647ac85 100644
--- a/arch/powerpc/boot/dts/mpc8540ads.dts
+++ b/arch/powerpc/boot/dts/mpc8540ads.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts
index 2a1ae760ab3a..5fdcb69554f2 100644
--- a/arch/powerpc/boot/dts/mpc8541cds.dts
+++ b/arch/powerpc/boot/dts/mpc8541cds.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts
new file mode 100644
index 000000000000..6b084605bb4b
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8544ds.dts
@@ -0,0 +1,136 @@
+/*
+ * MPC8544 DS Device Tree Source
+ *
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/ {
+ model = "MPC8544DS";
+ compatible = "MPC8544DS", "MPC85xxDS";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #cpus = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,8544@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>; // 32 bytes
+ i-cache-line-size = <20>; // 32 bytes
+ d-cache-size = <8000>; // L1, 32K
+ i-cache-size = <8000>; // L1, 32K
+ timebase-frequency = <0>;
+ bus-frequency = <0>;
+ clock-frequency = <0>;
+ 32-bit;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <00000000 00000000>; // Filled by U-Boot
+ };
+
+ soc8544@e0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = <0 e0000000 00100000>;
+ reg = <e0000000 00100000>; // CCSRBAR 1M
+ bus-frequency = <0>; // Filled out by uboot.
+
+ i2c@3000 {
+ device_type = "i2c";
+ compatible = "fsl-i2c";
+ reg = <3000 100>;
+ interrupts = <1b 2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+ mdio@24520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "mdio";
+ compatible = "gianfar";
+ reg = <24520 20>;
+ phy0: ethernet-phy@0 {
+ interrupt-parent = <&mpic>;
+ interrupts = <3a 1>;
+ reg = <0>;
+ device_type = "ethernet-phy";
+ };
+ phy1: ethernet-phy@1 {
+ interrupt-parent = <&mpic>;
+ interrupts = <3a 1>;
+ reg = <1>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ ethernet@24000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "network";
+ model = "TSEC";
+ compatible = "gianfar";
+ reg = <24000 1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <d 2 e 2 12 2>;
+ interrupt-parent = <&mpic>;
+ phy-handle = <&phy0>;
+ };
+
+ ethernet@26000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "network";
+ model = "TSEC";
+ compatible = "gianfar";
+ reg = <26000 1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <f 2 10 2 11 2>;
+ interrupt-parent = <&mpic>;
+ phy-handle = <&phy1>;
+ };
+
+ serial@4500 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4500 100>;
+ clock-frequency = <0>;
+ interrupts = <1a 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ serial@4600 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4600 100>;
+ clock-frequency = <0>;
+ interrupts = <1a 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ mpic: pic@40000 {
+ clock-frequency = <0>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <40000 40000>;
+ built-in;
+ compatible = "chrp,open-pic";
+ device_type = "open-pic";
+ big-endian;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
index 7eb5d81d5eec..b2b2200d0425 100644
--- a/arch/powerpc/boot/dts/mpc8548cds.dts
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts
index 5f9c102a0ab4..68a4795720dc 100644
--- a/arch/powerpc/boot/dts/mpc8555cds.dts
+++ b/arch/powerpc/boot/dts/mpc8555cds.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
index 10502638b0e9..1f2afe9291d2 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts
index bf49d8c997b9..7361b36749cb 100644
--- a/arch/powerpc/boot/dts/mpc8568mds.dts
+++ b/arch/powerpc/boot/dts/mpc8568mds.dts
@@ -21,7 +21,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
index 8a4995a85ba0..260b264c869e 100644
--- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
+++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <2>;
#address-cells = <1>;
#size-cells = <0>;
@@ -300,6 +299,30 @@
};
};
+
+ pci@9000 {
+ compatible = "86xx";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <9000 1000>;
+ bus-range = <0 ff>;
+ ranges = <02000000 0 a0000000 a0000000 0 20000000
+ 01000000 0 00000000 e3000000 0 00100000>;
+ clock-frequency = <1fca055>;
+ interrupt-parent = <&mpic>;
+ interrupts = <19 2>;
+ interrupt-map-mask = <f800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0 0 1 &mpic 44 1
+ 0000 0 0 2 &mpic 45 1
+ 0000 0 0 3 &mpic 46 1
+ 0000 0 0 4 &mpic 47 1
+ >;
+ };
+
mpic: pic@40000 {
clock-frequency = <0>;
interrupt-controller;
diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts
index 2b56b5df451a..c0d06fd12927 100644
--- a/arch/powerpc/boot/dts/mpc866ads.dts
+++ b/arch/powerpc/boot/dts/mpc866ads.dts
@@ -18,7 +18,6 @@
linux,phandle = <100>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
linux,phandle = <200>;
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index faecd08c54da..110bf6170603 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -18,7 +18,6 @@
linux,phandle = <100>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
linux,phandle = <200>;
diff --git a/arch/powerpc/boot/elf.h b/arch/powerpc/boot/elf.h
index d4828fcf1cb9..1941bc50d4c5 100644
--- a/arch/powerpc/boot/elf.h
+++ b/arch/powerpc/boot/elf.h
@@ -146,4 +146,12 @@ typedef struct elf64_phdr {
#define ELFOSABI_NONE 0
#define ELFOSABI_LINUX 3
+struct elf_info {
+ unsigned long loadsize;
+ unsigned long memsize;
+ unsigned long elfoffset;
+};
+int parse_elf64(void *hdr, struct elf_info *info);
+int parse_elf32(void *hdr, struct elf_info *info);
+
#endif /* _PPC_BOOT_ELF_H_ */
diff --git a/arch/powerpc/boot/elf_util.c b/arch/powerpc/boot/elf_util.c
new file mode 100644
index 000000000000..7454aa4cc20c
--- /dev/null
+++ b/arch/powerpc/boot/elf_util.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * Updates for PPC64 by Todd Inglett, Dave Engebretsen & Peter Bergner.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+
+int parse_elf64(void *hdr, struct elf_info *info)
+{
+ Elf64_Ehdr *elf64 = hdr;
+ Elf64_Phdr *elf64ph;
+ unsigned int i;
+
+ if (!(elf64->e_ident[EI_MAG0] == ELFMAG0 &&
+ elf64->e_ident[EI_MAG1] == ELFMAG1 &&
+ elf64->e_ident[EI_MAG2] == ELFMAG2 &&
+ elf64->e_ident[EI_MAG3] == ELFMAG3 &&
+ elf64->e_ident[EI_CLASS] == ELFCLASS64 &&
+ elf64->e_ident[EI_DATA] == ELFDATA2MSB &&
+ elf64->e_type == ET_EXEC &&
+ elf64->e_machine == EM_PPC64))
+ return 0;
+
+ elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
+ (unsigned long)elf64->e_phoff);
+ for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
+ if (elf64ph->p_type == PT_LOAD)
+ break;
+ if (i >= (unsigned int)elf64->e_phnum)
+ return 0;
+
+ info->loadsize = (unsigned long)elf64ph->p_filesz;
+ info->memsize = (unsigned long)elf64ph->p_memsz;
+ info->elfoffset = (unsigned long)elf64ph->p_offset;
+
+ return 1;
+}
+
+int parse_elf32(void *hdr, struct elf_info *info)
+{
+ Elf32_Ehdr *elf32 = hdr;
+ Elf32_Phdr *elf32ph;
+ unsigned int i;
+
+ if (!(elf32->e_ident[EI_MAG0] == ELFMAG0 &&
+ elf32->e_ident[EI_MAG1] == ELFMAG1 &&
+ elf32->e_ident[EI_MAG2] == ELFMAG2 &&
+ elf32->e_ident[EI_MAG3] == ELFMAG3 &&
+ elf32->e_ident[EI_CLASS] == ELFCLASS32 &&
+ elf32->e_ident[EI_DATA] == ELFDATA2MSB &&
+ elf32->e_type == ET_EXEC &&
+ elf32->e_machine == EM_PPC))
+ return 0;
+
+ elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
+ for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
+ if (elf32ph->p_type == PT_LOAD)
+ break;
+ if (i >= elf32->e_phnum)
+ return 0;
+
+ info->loadsize = elf32ph->p_filesz;
+ info->memsize = elf32ph->p_memsz;
+ info->elfoffset = elf32ph->p_offset;
+ return 1;
+}
diff --git a/arch/powerpc/boot/flatdevtree.c b/arch/powerpc/boot/flatdevtree.c
index c76c194715b2..d00fbd92a458 100644
--- a/arch/powerpc/boot/flatdevtree.c
+++ b/arch/powerpc/boot/flatdevtree.c
@@ -29,12 +29,20 @@
#define _ALIGN(x, al) (((x) + (al) - 1) & ~((al) - 1))
+static char *ft_root_node(struct ft_cxt *cxt)
+{
+ return cxt->rgn[FT_STRUCT].start;
+}
+
/* Routines for keeping node ptrs returned by ft_find_device current */
/* First entry not used b/c it would return 0 and be taken as NULL/error */
-static void *ft_node_add(struct ft_cxt *cxt, char *node)
+static void *ft_get_phandle(struct ft_cxt *cxt, char *node)
{
unsigned int i;
+ if (!node)
+ return NULL;
+
for (i = 1; i < cxt->nodes_used; i++) /* already there? */
if (cxt->node_tbl[i] == node)
return (void *)i;
@@ -238,7 +246,7 @@ static int ft_shuffle(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
if (rgn == FT_STRUCT)
ft_node_update_before(cxt, p, -nextra);
}
- *p -= nextra;
+ *pp -= nextra;
cxt->rgn[rgn].start -= nextra;
cxt->rgn[rgn].size += nextra;
return 1;
@@ -253,8 +261,14 @@ static int ft_make_space(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
char *str, *next;
enum ft_rgn_id r;
- if (!cxt->isordered && !ft_reorder(cxt, nextra))
- return 0;
+ if (!cxt->isordered) {
+ unsigned long rgn_off = *pp - cxt->rgn[rgn].start;
+
+ if (!ft_reorder(cxt, nextra))
+ return 0;
+
+ *pp = cxt->rgn[rgn].start + rgn_off;
+ }
if (ft_shuffle(cxt, pp, rgn, nextra))
return 1;
@@ -415,7 +429,7 @@ int ft_prop(struct ft_cxt *cxt, const char *name, const void *data,
{
int off, len;
- off = lookup_string(cxt, name);
+ off = map_string(cxt, name);
if (off == NO_STRING)
return -1;
@@ -590,7 +604,7 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size)
void ft_begin_tree(struct ft_cxt *cxt)
{
- cxt->p = cxt->rgn[FT_STRUCT].start;
+ cxt->p = ft_root_node(cxt);
}
void ft_end_tree(struct ft_cxt *cxt)
@@ -636,8 +650,21 @@ void *ft_find_device(struct ft_cxt *cxt, const char *srch_path)
/* require absolute path */
if (srch_path[0] != '/')
return NULL;
- node = ft_find_descendent(cxt, cxt->rgn[FT_STRUCT].start, srch_path);
- return ft_node_add(cxt, node);
+ node = ft_find_descendent(cxt, ft_root_node(cxt), srch_path);
+ return ft_get_phandle(cxt, node);
+}
+
+void *ft_find_device_rel(struct ft_cxt *cxt, const void *top,
+ const char *srch_path)
+{
+ char *node;
+
+ node = ft_node_ph2node(cxt, top);
+ if (node == NULL)
+ return NULL;
+
+ node = ft_find_descendent(cxt, node, srch_path);
+ return ft_get_phandle(cxt, node);
}
void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
@@ -701,23 +728,18 @@ void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
return NULL;
}
-void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
+void *__ft_get_parent(struct ft_cxt *cxt, void *node)
{
- void *node;
int d;
struct ft_atom atom;
char *p;
- node = ft_node_ph2node(cxt, phandle);
- if (node == NULL)
- return NULL;
-
for (d = 0; cxt->genealogy[d] != NULL; ++d)
if (cxt->genealogy[d] == node)
- return cxt->genealogy[d > 0 ? d - 1 : 0];
+ return d > 0 ? cxt->genealogy[d - 1] : NULL;
/* have to do it the hard way... */
- p = cxt->rgn[FT_STRUCT].start;
+ p = ft_root_node(cxt);
d = 0;
while ((p = ft_next(cxt, p, &atom)) != NULL) {
switch (atom.tag) {
@@ -726,7 +748,7 @@ void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
if (node == atom.data) {
/* found it */
cxt->genealogy[d + 1] = NULL;
- return d > 0 ? cxt->genealogy[d - 1] : node;
+ return d > 0 ? cxt->genealogy[d - 1] : NULL;
}
++d;
break;
@@ -738,41 +760,131 @@ void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
return NULL;
}
-int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
- void *buf, const unsigned int buflen)
+void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
{
- struct ft_atom atom;
- void *node;
- char *p;
- int depth;
- unsigned int size;
-
- node = ft_node_ph2node(cxt, phandle);
+ void *node = ft_node_ph2node(cxt, phandle);
if (node == NULL)
- return -1;
+ return NULL;
- depth = 0;
- p = (char *)node;
+ node = __ft_get_parent(cxt, node);
+ return ft_get_phandle(cxt, node);
+}
- while ((p = ft_next(cxt, p, &atom)) != NULL) {
+static const void *__ft_get_prop(struct ft_cxt *cxt, void *node,
+ const char *propname, unsigned int *len)
+{
+ struct ft_atom atom;
+ int depth = 0;
+
+ while ((node = ft_next(cxt, node, &atom)) != NULL) {
switch (atom.tag) {
case OF_DT_BEGIN_NODE:
++depth;
break;
+
case OF_DT_PROP:
- if ((depth != 1) || strcmp(atom.name, propname))
+ if (depth != 1 || strcmp(atom.name, propname))
break;
- size = min(atom.size, buflen);
- memcpy(buf, atom.data, size);
- return atom.size;
+
+ if (len)
+ *len = atom.size;
+
+ return atom.data;
+
case OF_DT_END_NODE:
if (--depth <= 0)
- return -1;
+ return NULL;
}
}
+
+ return NULL;
+}
+
+int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
+ void *buf, const unsigned int buflen)
+{
+ const void *data;
+ unsigned int size;
+
+ void *node = ft_node_ph2node(cxt, phandle);
+ if (!node)
+ return -1;
+
+ data = __ft_get_prop(cxt, node, propname, &size);
+ if (data) {
+ unsigned int clipped_size = min(size, buflen);
+ memcpy(buf, data, clipped_size);
+ return size;
+ }
+
return -1;
}
+void *__ft_find_node_by_prop_value(struct ft_cxt *cxt, void *prev,
+ const char *propname, const char *propval,
+ unsigned int proplen)
+{
+ struct ft_atom atom;
+ char *p = ft_root_node(cxt);
+ char *next;
+ int past_prev = prev ? 0 : 1;
+ int depth = -1;
+
+ while ((next = ft_next(cxt, p, &atom)) != NULL) {
+ const void *data;
+ unsigned int size;
+
+ switch (atom.tag) {
+ case OF_DT_BEGIN_NODE:
+ depth++;
+
+ if (prev == p) {
+ past_prev = 1;
+ break;
+ }
+
+ if (!past_prev || depth < 1)
+ break;
+
+ data = __ft_get_prop(cxt, p, propname, &size);
+ if (!data || size != proplen)
+ break;
+ if (memcmp(data, propval, size))
+ break;
+
+ return p;
+
+ case OF_DT_END_NODE:
+ if (depth-- == 0)
+ return NULL;
+
+ break;
+ }
+
+ p = next;
+ }
+
+ return NULL;
+}
+
+void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
+ const char *propname, const char *propval,
+ int proplen)
+{
+ void *node = NULL;
+
+ if (prev) {
+ node = ft_node_ph2node(cxt, prev);
+
+ if (!node)
+ return NULL;
+ }
+
+ node = __ft_find_node_by_prop_value(cxt, node, propname,
+ propval, proplen);
+ return ft_get_phandle(cxt, node);
+}
+
int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
const void *buf, const unsigned int buflen)
{
@@ -849,19 +961,26 @@ int ft_del_prop(struct ft_cxt *cxt, const void *phandle, const char *propname)
return -1;
}
-void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path)
+void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name)
{
struct ft_atom atom;
char *p, *next;
int depth = 0;
- p = cxt->rgn[FT_STRUCT].start;
+ if (parent) {
+ p = ft_node_ph2node(cxt, parent);
+ if (!p)
+ return NULL;
+ } else {
+ p = ft_root_node(cxt);
+ }
+
while ((next = ft_next(cxt, p, &atom)) != NULL) {
switch (atom.tag) {
case OF_DT_BEGIN_NODE:
++depth;
- if (depth == 1 && strcmp(atom.name, path) == 0)
- /* duplicate node path, return error */
+ if (depth == 1 && strcmp(atom.name, name) == 0)
+ /* duplicate node name, return error */
return NULL;
break;
case OF_DT_END_NODE:
@@ -870,7 +989,7 @@ void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path)
break;
/* end of node, insert here */
cxt->p = p;
- ft_begin_node(cxt, path);
+ ft_begin_node(cxt, name);
ft_end_node(cxt);
return p;
}
diff --git a/arch/powerpc/boot/flatdevtree.h b/arch/powerpc/boot/flatdevtree.h
index b9cd9f61f351..cb26325d72db 100644
--- a/arch/powerpc/boot/flatdevtree.h
+++ b/arch/powerpc/boot/flatdevtree.h
@@ -97,10 +97,17 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size);
void ft_dump_blob(const void *bphp);
void ft_merge_blob(struct ft_cxt *cxt, void *blob);
void *ft_find_device(struct ft_cxt *cxt, const char *srch_path);
+void *ft_find_device_rel(struct ft_cxt *cxt, const void *top,
+ const char *srch_path);
void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path);
int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
void *buf, const unsigned int buflen);
int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
const void *buf, const unsigned int buflen);
+void *ft_get_parent(struct ft_cxt *cxt, const void *phandle);
+void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
+ const char *propname, const char *propval,
+ int proplen);
+void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name);
#endif /* FLATDEVTREE_H */
diff --git a/arch/powerpc/boot/flatdevtree_misc.c b/arch/powerpc/boot/flatdevtree_misc.c
index 04da38fa477f..4341e6558c1a 100644
--- a/arch/powerpc/boot/flatdevtree_misc.c
+++ b/arch/powerpc/boot/flatdevtree_misc.c
@@ -16,24 +16,43 @@
static struct ft_cxt cxt;
-static void *ft_finddevice(const char *name)
+static void *fdtm_finddevice(const char *name)
{
return ft_find_device(&cxt, name);
}
-static int ft_getprop(const void *phandle, const char *propname, void *buf,
- const int buflen)
+static int fdtm_getprop(const void *phandle, const char *propname,
+ void *buf, const int buflen)
{
return ft_get_prop(&cxt, phandle, propname, buf, buflen);
}
-static int ft_setprop(const void *phandle, const char *propname,
- const void *buf, const int buflen)
+static int fdtm_setprop(const void *phandle, const char *propname,
+ const void *buf, const int buflen)
{
return ft_set_prop(&cxt, phandle, propname, buf, buflen);
}
-static unsigned long ft_finalize(void)
+static void *fdtm_get_parent(const void *phandle)
+{
+ return ft_get_parent(&cxt, phandle);
+}
+
+static void *fdtm_create_node(const void *phandle, const char *name)
+{
+ return ft_create_node(&cxt, phandle, name);
+}
+
+static void *fdtm_find_node_by_prop_value(const void *prev,
+ const char *propname,
+ const char *propval,
+ int proplen)
+{
+ return ft_find_node_by_prop_value(&cxt, prev, propname,
+ propval, proplen);
+}
+
+static unsigned long fdtm_finalize(void)
{
ft_end_tree(&cxt);
return (unsigned long)cxt.bph;
@@ -41,10 +60,13 @@ static unsigned long ft_finalize(void)
int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device)
{
- dt_ops.finddevice = ft_finddevice;
- dt_ops.getprop = ft_getprop;
- dt_ops.setprop = ft_setprop;
- dt_ops.finalize = ft_finalize;
+ dt_ops.finddevice = fdtm_finddevice;
+ dt_ops.getprop = fdtm_getprop;
+ dt_ops.setprop = fdtm_setprop;
+ dt_ops.get_parent = fdtm_get_parent;
+ dt_ops.create_node = fdtm_create_node;
+ dt_ops.find_node_by_prop_value = fdtm_find_node_by_prop_value;
+ dt_ops.finalize = fdtm_finalize;
return ft_open(&cxt, dt_blob, max_size, max_find_device,
platform_ops.realloc);
diff --git a/arch/powerpc/boot/gunzip_util.c b/arch/powerpc/boot/gunzip_util.c
new file mode 100644
index 000000000000..df8ab07e9ff4
--- /dev/null
+++ b/arch/powerpc/boot/gunzip_util.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Based on earlier work, Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+#include "gunzip_util.h"
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+/**
+ * gunzip_start - prepare to decompress gzip data
+ * @state: decompressor state structure to be initialized
+ * @src: buffer containing gzip compressed or uncompressed data
+ * @srclen: size in bytes of the buffer at src
+ *
+ * If the buffer at @src contains a gzip header, this function
+ * initializes zlib to decompress the data, storing the decompression
+ * state in @state. The other functions in this file can then be used
+ * to decompress data from the gzipped stream.
+ *
+ * If the buffer at @src does not contain a gzip header, it is assumed
+ * to contain uncompressed data. The buffer information is recorded
+ * in @state and the other functions in this file will simply copy
+ * data from the uncompressed data stream at @src.
+ *
+ * Any errors, such as bad compressed data, cause an error to be
+ * printed an the platform's exit() function to be called.
+ */
+void gunzip_start(struct gunzip_state *state, void *src, int srclen)
+{
+ char *hdr = src;
+ int hdrlen = 0;
+
+ memset(state, 0, sizeof(*state));
+
+ /* Check for gzip magic number */
+ if ((hdr[0] == 0x1f) && (hdr[1] == 0x8b)) {
+ /* gzip data, initialize zlib parameters */
+ int r, flags;
+
+ state->s.workspace = state->scratch;
+ if (zlib_inflate_workspacesize() > sizeof(state->scratch))
+ fatal("insufficient scratch space for gunzip\n\r");
+
+ /* skip header */
+ hdrlen = 10;
+ flags = hdr[3];
+ if (hdr[2] != Z_DEFLATED || (flags & RESERVED) != 0)
+ fatal("bad gzipped data\n\r");
+ if ((flags & EXTRA_FIELD) != 0)
+ hdrlen = 12 + hdr[10] + (hdr[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (hdr[hdrlen++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (hdr[hdrlen++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ hdrlen += 2;
+ if (hdrlen >= srclen)
+ fatal("gunzip_start: ran out of data in header\n\r");
+
+ r = zlib_inflateInit2(&state->s, -MAX_WBITS);
+ if (r != Z_OK)
+ fatal("inflateInit2 returned %d\n\r", r);
+ }
+
+ state->s.next_in = src + hdrlen;
+ state->s.avail_in = srclen - hdrlen;
+}
+
+/**
+ * gunzip_partial - extract bytes from a gzip data stream
+ * @state: gzip state structure previously initialized by gunzip_start()
+ * @dst: buffer to store extracted data
+ * @dstlen: maximum number of bytes to extract
+ *
+ * This function extracts at most @dstlen bytes from the data stream
+ * previously associated with @state by gunzip_start(), decompressing
+ * if necessary. Exactly @dstlen bytes are extracted unless the data
+ * stream doesn't contain enough bytes, in which case the entire
+ * remainder of the stream is decompressed.
+ *
+ * Returns the actual number of bytes extracted. If any errors occur,
+ * such as a corrupted compressed stream, an error is printed an the
+ * platform's exit() function is called.
+ */
+int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen)
+{
+ int len;
+
+ if (state->s.workspace) {
+ /* gunzipping */
+ int r;
+
+ state->s.next_out = dst;
+ state->s.avail_out = dstlen;
+ r = zlib_inflate(&state->s, Z_FULL_FLUSH);
+ if (r != Z_OK && r != Z_STREAM_END)
+ fatal("inflate returned %d msg: %s\n\r", r, state->s.msg);
+ len = state->s.next_out - (unsigned char *)dst;
+ } else {
+ /* uncompressed image */
+ len = min(state->s.avail_in, (unsigned)dstlen);
+ memcpy(dst, state->s.next_in, len);
+ state->s.next_in += len;
+ state->s.avail_in -= len;
+ }
+ return len;
+}
+
+/**
+ * gunzip_exactly - extract a fixed number of bytes from a gzip data stream
+ * @state: gzip state structure previously initialized by gunzip_start()
+ * @dst: buffer to store extracted data
+ * @dstlen: number of bytes to extract
+ *
+ * This function extracts exactly @dstlen bytes from the data stream
+ * previously associated with @state by gunzip_start(), decompressing
+ * if necessary.
+ *
+ * If there are less @dstlen bytes available in the data stream, or if
+ * any other errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+void gunzip_exactly(struct gunzip_state *state, void *dst, int dstlen)
+{
+ int len;
+
+ len = gunzip_partial(state, dst, dstlen);
+ if (len < dstlen)
+ fatal("\n\rgunzip_exactly: ran out of data!"
+ " Wanted %d, got %d.\n\r", dstlen, len);
+}
+
+/**
+ * gunzip_discard - discard bytes from a gzip data stream
+ * @state: gzip state structure previously initialized by gunzip_start()
+ * @len: number of bytes to discard
+ *
+ * This function extracts, then discards exactly @len bytes from the
+ * data stream previously associated with @state by gunzip_start().
+ * Subsequent gunzip_partial(), gunzip_exactly() or gunzip_finish()
+ * calls will extract the data following the discarded bytes in the
+ * data stream.
+ *
+ * If there are less @len bytes available in the data stream, or if
+ * any other errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+void gunzip_discard(struct gunzip_state *state, int len)
+{
+ static char discard_buf[128];
+
+ while (len > sizeof(discard_buf)) {
+ gunzip_exactly(state, discard_buf, sizeof(discard_buf));
+ len -= sizeof(discard_buf);
+ }
+
+ if (len > 0)
+ gunzip_exactly(state, discard_buf, len);
+}
+
+/**
+ * gunzip_finish - extract all remaining bytes from a gzip data stream
+ * @state: gzip state structure previously initialized by gunzip_start()
+ * @dst: buffer to store extracted data
+ * @dstlen: maximum number of bytes to extract
+ *
+ * This function extracts all remaining data, or at most @dstlen
+ * bytes, from the stream previously associated with @state by
+ * gunzip_start(). zlib is then shut down, so it is an error to use
+ * any of the functions in this file on @state until it is
+ * re-initialized with another call to gunzip_start().
+ *
+ * If any errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen)
+{
+ int len;
+
+ if (state->s.workspace) {
+ len = gunzip_partial(state, dst, dstlen);
+ zlib_inflateEnd(&state->s);
+ } else {
+ /* uncompressed image */
+ len = min(state->s.avail_in, (unsigned)dstlen);
+ memcpy(dst, state->s.next_in, len);
+ }
+
+ return len;
+}
diff --git a/arch/powerpc/boot/gunzip_util.h b/arch/powerpc/boot/gunzip_util.h
new file mode 100644
index 000000000000..b3dfa6e87b3a
--- /dev/null
+++ b/arch/powerpc/boot/gunzip_util.h
@@ -0,0 +1,45 @@
+/*
+ * Decompression convenience functions
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef _PPC_BOOT_GUNZIP_UTIL_H_
+#define _PPC_BOOT_GUNZIP_UTIL_H_
+
+#include "zlib.h"
+
+/*
+ * These functions are designed to make life easy for decompressing
+ * kernel images, initrd images or any other gzip compressed image,
+ * particularly if its useful to decompress part of the image (e.g. to
+ * examine headers) before decompressing the remainder.
+ *
+ * To use:
+ * - declare a gunzip_state structure
+ * - use gunzip_start() to initialize the state, associating it
+ * with a stream of compressed data
+ * - use gunzip_partial(), gunzip_exactly() and gunzip_discard()
+ * in any combination to extract pieces of data from the stream
+ * - Finally use gunzip_finish() to extract the tail of the
+ * compressed stream and wind up zlib
+ */
+
+/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
+#define GUNZIP_SCRATCH_SIZE 46912
+
+struct gunzip_state {
+ z_stream s;
+ char scratch[46912];
+};
+
+void gunzip_start(struct gunzip_state *state, void *src, int srclen);
+int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen);
+void gunzip_exactly(struct gunzip_state *state, void *dst, int len);
+void gunzip_discard(struct gunzip_state *state, int len);
+int gunzip_finish(struct gunzip_state *state, void *dst, int len);
+
+#endif /* _PPC_BOOT_GUNZIP_UTIL_H_ */
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index 6f6b50d238b6..56b56a8d4b23 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -14,11 +14,10 @@
#include "page.h"
#include "string.h"
#include "stdio.h"
-#include "zlib.h"
#include "ops.h"
+#include "gunzip_util.h"
#include "flatdevtree.h"
-
-extern void flush_cache(void *, unsigned long);
+#include "reg.h"
extern char _start[];
extern char __bss_start[];
@@ -30,304 +29,173 @@ extern char _initrd_end[];
extern char _dtb_start[];
extern char _dtb_end[];
+static struct gunzip_state gzstate;
+
struct addr_range {
- unsigned long addr;
+ void *addr;
unsigned long size;
- unsigned long memsize;
};
-static struct addr_range vmlinux;
-static struct addr_range vmlinuz;
-static struct addr_range initrd;
-
-static unsigned long elfoffset;
-static int is_64bit;
-
-/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
-static char scratch[46912];
-static char elfheader[256];
typedef void (*kernel_entry_t)(unsigned long, unsigned long, void *);
#undef DEBUG
-#define HEAD_CRC 2
-#define EXTRA_FIELD 4
-#define ORIG_NAME 8
-#define COMMENT 0x10
-#define RESERVED 0xe0
-
-static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+static struct addr_range prep_kernel(void)
{
- z_stream s;
- int r, i, flags;
-
- /* skip header */
- i = 10;
- flags = src[3];
- if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
- printf("bad gzipped data\n\r");
- exit();
- }
- if ((flags & EXTRA_FIELD) != 0)
- i = 12 + src[10] + (src[11] << 8);
- if ((flags & ORIG_NAME) != 0)
- while (src[i++] != 0)
- ;
- if ((flags & COMMENT) != 0)
- while (src[i++] != 0)
- ;
- if ((flags & HEAD_CRC) != 0)
- i += 2;
- if (i >= *lenp) {
- printf("gunzip: ran out of data in header\n\r");
- exit();
- }
+ char elfheader[256];
+ void *vmlinuz_addr = _vmlinux_start;
+ unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
+ void *addr = 0;
+ struct elf_info ei;
+ int len;
- if (zlib_inflate_workspacesize() > sizeof(scratch)) {
- printf("gunzip needs more mem\n");
- exit();
- }
- memset(&s, 0, sizeof(s));
- s.workspace = scratch;
- r = zlib_inflateInit2(&s, -MAX_WBITS);
- if (r != Z_OK) {
- printf("inflateInit2 returned %d\n\r", r);
- exit();
- }
- s.next_in = src + i;
- s.avail_in = *lenp - i;
- s.next_out = dst;
- s.avail_out = dstlen;
- r = zlib_inflate(&s, Z_FULL_FLUSH);
- if (r != Z_OK && r != Z_STREAM_END) {
- printf("inflate returned %d msg: %s\n\r", r, s.msg);
- exit();
+ /* gunzip the ELF header of the kernel */
+ gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
+ gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
+
+ if (!parse_elf64(elfheader, &ei) && !parse_elf32(elfheader, &ei))
+ fatal("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
+
+ if (platform_ops.image_hdr)
+ platform_ops.image_hdr(elfheader);
+
+ /* We need to alloc the memsize: gzip will expand the kernel
+ * text/data, then possible rubbish we don't care about. But
+ * the kernel bss must be claimed (it will be zero'd by the
+ * kernel itself)
+ */
+ printf("Allocating 0x%lx bytes for kernel ...\n\r", ei.memsize);
+
+ if (platform_ops.vmlinux_alloc) {
+ addr = platform_ops.vmlinux_alloc(ei.memsize);
+ } else {
+ if ((unsigned long)_start < ei.memsize)
+ fatal("Insufficient memory for kernel at address 0!"
+ " (_start=%p)\n\r", _start);
}
- *lenp = s.next_out - (unsigned char *) dst;
- zlib_inflateEnd(&s);
-}
-static int is_elf64(void *hdr)
-{
- Elf64_Ehdr *elf64 = hdr;
- Elf64_Phdr *elf64ph;
- unsigned int i;
-
- if (!(elf64->e_ident[EI_MAG0] == ELFMAG0 &&
- elf64->e_ident[EI_MAG1] == ELFMAG1 &&
- elf64->e_ident[EI_MAG2] == ELFMAG2 &&
- elf64->e_ident[EI_MAG3] == ELFMAG3 &&
- elf64->e_ident[EI_CLASS] == ELFCLASS64 &&
- elf64->e_ident[EI_DATA] == ELFDATA2MSB &&
- elf64->e_type == ET_EXEC &&
- elf64->e_machine == EM_PPC64))
- return 0;
-
- elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
- (unsigned long)elf64->e_phoff);
- for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
- if (elf64ph->p_type == PT_LOAD)
- break;
- if (i >= (unsigned int)elf64->e_phnum)
- return 0;
-
- elfoffset = (unsigned long)elf64ph->p_offset;
- vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
- vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
-
- is_64bit = 1;
- return 1;
-}
+ /* Finally, gunzip the kernel */
+ printf("gunzipping (0x%p <- 0x%p:0x%p)...", addr,
+ vmlinuz_addr, vmlinuz_addr+vmlinuz_size);
+ /* discard up to the actual load data */
+ gunzip_discard(&gzstate, ei.elfoffset - sizeof(elfheader));
+ len = gunzip_finish(&gzstate, addr, ei.loadsize);
+ if (len != ei.loadsize)
+ fatal("ran out of data! only got 0x%x of 0x%lx bytes.\n\r",
+ len, ei.loadsize);
+ printf("done 0x%x bytes\n\r", len);
-static int is_elf32(void *hdr)
-{
- Elf32_Ehdr *elf32 = hdr;
- Elf32_Phdr *elf32ph;
- unsigned int i;
-
- if (!(elf32->e_ident[EI_MAG0] == ELFMAG0 &&
- elf32->e_ident[EI_MAG1] == ELFMAG1 &&
- elf32->e_ident[EI_MAG2] == ELFMAG2 &&
- elf32->e_ident[EI_MAG3] == ELFMAG3 &&
- elf32->e_ident[EI_CLASS] == ELFCLASS32 &&
- elf32->e_ident[EI_DATA] == ELFDATA2MSB &&
- elf32->e_type == ET_EXEC &&
- elf32->e_machine == EM_PPC))
- return 0;
-
- elf32 = (Elf32_Ehdr *)elfheader;
- elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
- for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
- if (elf32ph->p_type == PT_LOAD)
- break;
- if (i >= elf32->e_phnum)
- return 0;
-
- elfoffset = elf32ph->p_offset;
- vmlinux.size = elf32ph->p_filesz + elf32ph->p_offset;
- vmlinux.memsize = elf32ph->p_memsz + elf32ph->p_offset;
- return 1;
+ flush_cache(addr, ei.loadsize);
+
+ return (struct addr_range){addr, ei.memsize};
}
-static void prep_kernel(unsigned long a1, unsigned long a2)
+static struct addr_range prep_initrd(struct addr_range vmlinux, void *chosen,
+ unsigned long initrd_addr,
+ unsigned long initrd_size)
{
- int len;
-
- vmlinuz.addr = (unsigned long)_vmlinux_start;
- vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
-
- /* gunzip the ELF header of the kernel */
- if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
- len = vmlinuz.size;
- gunzip(elfheader, sizeof(elfheader),
- (unsigned char *)vmlinuz.addr, &len);
- } else
- memcpy(elfheader, (const void *)vmlinuz.addr,
- sizeof(elfheader));
-
- if (!is_elf64(elfheader) && !is_elf32(elfheader)) {
- printf("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
- exit();
+ /* If we have an image attached to us, it overrides anything
+ * supplied by the loader. */
+ if (_initrd_end > _initrd_start) {
+ printf("Attached initrd image at 0x%p-0x%p\n\r",
+ _initrd_start, _initrd_end);
+ initrd_addr = (unsigned long)_initrd_start;
+ initrd_size = _initrd_end - _initrd_start;
+ } else if (initrd_size > 0) {
+ printf("Using loader supplied ramdisk at 0x%lx-0x%lx\n\r",
+ initrd_addr, initrd_addr + initrd_size);
}
- if (platform_ops.image_hdr)
- platform_ops.image_hdr(elfheader);
- /* We need to alloc the memsize plus the file offset since gzip
- * will expand the header (file offset), then the kernel, then
- * possible rubbish we don't care about. But the kernel bss must
- * be claimed (it will be zero'd by the kernel itself)
- */
- printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize);
- vmlinux.addr = (unsigned long)malloc(vmlinux.memsize);
- if (vmlinux.addr == 0) {
- printf("Can't allocate memory for kernel image !\n\r");
- exit();
- }
+ /* If there's no initrd at all, we're done */
+ if (! initrd_size)
+ return (struct addr_range){0, 0};
/*
- * Now find the initrd
- *
- * First see if we have an image attached to us. If so
- * allocate memory for it and copy it there.
+ * If the initrd is too low it will be clobbered when the
+ * kernel relocates to its final location. In this case,
+ * allocate a safer place and move it.
*/
- initrd.size = (unsigned long)(_initrd_end - _initrd_start);
- initrd.memsize = initrd.size;
- if (initrd.size > 0) {
+ if (initrd_addr < vmlinux.size) {
+ void *old_addr = (void *)initrd_addr;
+
printf("Allocating 0x%lx bytes for initrd ...\n\r",
- initrd.size);
- initrd.addr = (unsigned long)malloc((u32)initrd.size);
- if (initrd.addr == 0) {
- printf("Can't allocate memory for initial "
- "ramdisk !\n\r");
- exit();
- }
- printf("initial ramdisk moving 0x%lx <- 0x%lx "
- "(0x%lx bytes)\n\r", initrd.addr,
- (unsigned long)_initrd_start, initrd.size);
- memmove((void *)initrd.addr, (void *)_initrd_start,
- initrd.size);
- printf("initrd head: 0x%lx\n\r",
- *((unsigned long *)initrd.addr));
- } else if (a2 != 0) {
- /* Otherwise, see if yaboot or another loader gave us an initrd */
- initrd.addr = a1;
- initrd.memsize = initrd.size = a2;
- printf("Using loader supplied initrd at 0x%lx (0x%lx bytes)\n\r",
- initrd.addr, initrd.size);
+ initrd_size);
+ initrd_addr = (unsigned long)malloc(initrd_size);
+ if (! initrd_addr)
+ fatal("Can't allocate memory for initial "
+ "ramdisk !\n\r");
+ printf("Relocating initrd 0x%lx <- 0x%p (0x%lx bytes)\n\r",
+ initrd_addr, old_addr, initrd_size);
+ memmove((void *)initrd_addr, old_addr, initrd_size);
}
- /* Eventually gunzip the kernel */
- if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
- printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
- vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
- len = vmlinuz.size;
- gunzip((void *)vmlinux.addr, vmlinux.memsize,
- (unsigned char *)vmlinuz.addr, &len);
- printf("done 0x%lx bytes\n\r", len);
- } else {
- memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,
- vmlinuz.size);
- }
+ printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd_addr));
- /* Skip over the ELF header */
-#ifdef DEBUG
- printf("... skipping 0x%lx bytes of ELF header\n\r",
- elfoffset);
-#endif
- vmlinux.addr += elfoffset;
+ /* Tell the kernel initrd address via device tree */
+ setprop_val(chosen, "linux,initrd-start", (u32)(initrd_addr));
+ setprop_val(chosen, "linux,initrd-end", (u32)(initrd_addr+initrd_size));
- flush_cache((void *)vmlinux.addr, vmlinux.size);
+ return (struct addr_range){(void *)initrd_addr, initrd_size};
}
/* A buffer that may be edited by tools operating on a zImage binary so as to
* edit the command line passed to vmlinux (by setting /chosen/bootargs).
* The buffer is put in it's own section so that tools may locate it easier.
*/
-static char builtin_cmdline[COMMAND_LINE_SIZE]
+static char cmdline[COMMAND_LINE_SIZE]
__attribute__((__section__("__builtin_cmdline")));
-static void get_cmdline(char *buf, int size)
+static void prep_cmdline(void *chosen)
{
- void *devp;
- int len = strlen(builtin_cmdline);
-
- buf[0] = '\0';
-
- if (len > 0) { /* builtin_cmdline overrides dt's /chosen/bootargs */
- len = min(len, size-1);
- strncpy(buf, builtin_cmdline, len);
- buf[len] = '\0';
- }
- else if ((devp = finddevice("/chosen")))
- getprop(devp, "bootargs", buf, size);
-}
+ if (cmdline[0] == '\0')
+ getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
-static void set_cmdline(char *buf)
-{
- void *devp;
+ printf("\n\rLinux/PowerPC load: %s", cmdline);
+ /* If possible, edit the command line */
+ if (console_ops.edit_cmdline)
+ console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
+ printf("\n\r");
- if ((devp = finddevice("/chosen")))
- setprop(devp, "bootargs", buf, strlen(buf) + 1);
+ /* Put the command line back into the devtree for the kernel */
+ setprop_str(chosen, "bootargs", cmdline);
}
struct platform_ops platform_ops;
struct dt_ops dt_ops;
struct console_ops console_ops;
+struct loader_info loader_info;
-void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
+void start(void)
{
+ struct addr_range vmlinux, initrd;
kernel_entry_t kentry;
- char cmdline[COMMAND_LINE_SIZE];
unsigned long ft_addr = 0;
+ void *chosen;
- memset(__bss_start, 0, _end - __bss_start);
- memset(&platform_ops, 0, sizeof(platform_ops));
- memset(&dt_ops, 0, sizeof(dt_ops));
- memset(&console_ops, 0, sizeof(console_ops));
+ /* Do this first, because malloc() could clobber the loader's
+ * command line. Only use the loader command line if a
+ * built-in command line wasn't set by an external tool */
+ if ((loader_info.cmdline_len > 0) && (cmdline[0] == '\0'))
+ memmove(cmdline, loader_info.cmdline,
+ min(loader_info.cmdline_len, COMMAND_LINE_SIZE-1));
- if (platform_init(promptr, _dtb_start, _dtb_end))
- exit();
if (console_ops.open && (console_ops.open() < 0))
exit();
if (platform_ops.fixups)
platform_ops.fixups();
printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r",
- _start, sp);
+ _start, get_sp());
- prep_kernel(a1, a2);
+ /* Ensure that the device tree has a /chosen node */
+ chosen = finddevice("/chosen");
+ if (!chosen)
+ chosen = create_node(NULL, "chosen");
- /* If cmdline came from zimage wrapper or if we can edit the one
- * in the dt, print it out and edit it, if possible.
- */
- if ((strlen(builtin_cmdline) > 0) || console_ops.edit_cmdline) {
- get_cmdline(cmdline, COMMAND_LINE_SIZE);
- printf("\n\rLinux/PowerPC load: %s", cmdline);
- if (console_ops.edit_cmdline)
- console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
- printf("\n\r");
- set_cmdline(cmdline);
- }
+ vmlinux = prep_kernel();
+ initrd = prep_initrd(vmlinux, chosen,
+ loader_info.initrd_addr, loader_info.initrd_size);
+ prep_cmdline(chosen);
printf("Finalizing device tree...");
if (dt_ops.finalize)
@@ -335,7 +203,7 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
if (ft_addr)
printf(" flat tree at 0x%lx\n\r", ft_addr);
else
- printf(" using OF tree (promptr=%p)\n\r", promptr);
+ printf(" using OF tree (promptr=%p)\n\r", loader_info.promptr);
if (console_ops.close)
console_ops.close();
@@ -344,10 +212,9 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
if (ft_addr)
kentry(ft_addr, 0, NULL);
else
- /* XXX initrd addr/size should be passed in properties */
- kentry(initrd.addr, initrd.size, promptr);
+ kentry((unsigned long)initrd.addr, initrd.size,
+ loader_info.promptr);
- /* console closed so printf below may not work */
- printf("Error: Linux kernel returned to zImage boot wrapper!\n\r");
- exit();
+ /* console closed so printf in fatal below may not work */
+ fatal("Error: Linux kernel returned to zImage boot wrapper!\n\r");
}
diff --git a/arch/powerpc/boot/ns16550.c b/arch/powerpc/boot/ns16550.c
index 1ffe72e35cdc..f8f1b2f31412 100644
--- a/arch/powerpc/boot/ns16550.c
+++ b/arch/powerpc/boot/ns16550.c
@@ -55,10 +55,15 @@ static u8 ns16550_tstc(void)
int ns16550_console_init(void *devp, struct serial_console_data *scdp)
{
int n;
+ unsigned long reg_phys;
n = getprop(devp, "virtual-reg", &reg_base, sizeof(reg_base));
- if (n != sizeof(reg_base))
- return -1;
+ if (n != sizeof(reg_base)) {
+ if (!dt_xlate_reg(devp, 0, &reg_phys, NULL))
+ return -1;
+
+ reg_base = (void *)reg_phys;
+ }
n = getprop(devp, "reg-shift", &reg_shift, sizeof(reg_shift));
if (n != sizeof(reg_shift))
diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c
index 0182f384f3e6..d16ee3e3f868 100644
--- a/arch/powerpc/boot/of.c
+++ b/arch/powerpc/boot/of.c
@@ -173,7 +173,7 @@ static void *claim(unsigned long virt, unsigned long size, unsigned long align)
return (void *) virt;
}
-static void *of_try_claim(u32 size)
+static void *of_try_claim(unsigned long size)
{
unsigned long addr = 0;
@@ -208,6 +208,16 @@ static void of_image_hdr(const void *hdr)
}
}
+static void *of_vmlinux_alloc(unsigned long size)
+{
+ void *p = malloc(size);
+
+ if (!p)
+ fatal("Can't allocate memory for kernel image!\n\r");
+
+ return p;
+}
+
static void of_exit(void)
{
call_prom("exit", 0, 0);
@@ -256,11 +266,12 @@ static void of_console_write(char *buf, int len)
call_prom("write", 3, 1, of_stdout_handle, buf, len);
}
-int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end)
+void platform_init(unsigned long a1, unsigned long a2, void *promptr)
{
platform_ops.image_hdr = of_image_hdr;
platform_ops.malloc = of_try_claim;
platform_ops.exit = of_exit;
+ platform_ops.vmlinux_alloc = of_vmlinux_alloc;
dt_ops.finddevice = of_finddevice;
dt_ops.getprop = of_getprop;
@@ -270,5 +281,9 @@ int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end)
console_ops.write = of_console_write;
prom = (int (*)(void *))promptr;
- return 0;
+ loader_info.promptr = promptr;
+ if (a1 && a2 && a2 != 0xdeadbeef) {
+ loader_info.initrd_addr = a1;
+ loader_info.initrd_size = a2;
+ }
}
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
index 8abb6516bb7c..73bd47a3a079 100644
--- a/arch/powerpc/boot/ops.h
+++ b/arch/powerpc/boot/ops.h
@@ -11,7 +11,9 @@
#ifndef _PPC_BOOT_OPS_H_
#define _PPC_BOOT_OPS_H_
+#include <stddef.h>
#include "types.h"
+#include "string.h"
#define COMMAND_LINE_SIZE 512
#define MAX_PATH_LEN 256
@@ -21,10 +23,11 @@
struct platform_ops {
void (*fixups)(void);
void (*image_hdr)(const void *);
- void * (*malloc)(u32 size);
+ void * (*malloc)(unsigned long size);
void (*free)(void *ptr);
void * (*realloc)(void *ptr, unsigned long size);
void (*exit)(void);
+ void * (*vmlinux_alloc)(unsigned long size);
};
extern struct platform_ops platform_ops;
@@ -35,6 +38,12 @@ struct dt_ops {
const int buflen);
int (*setprop)(const void *phandle, const char *name,
const void *buf, const int buflen);
+ void *(*get_parent)(const void *phandle);
+ /* The node must not already exist. */
+ void *(*create_node)(const void *parent, const char *name);
+ void *(*find_node_by_prop_value)(const void *prev,
+ const char *propname,
+ const char *propval, int proplen);
unsigned long (*finalize)(void);
};
extern struct dt_ops dt_ops;
@@ -58,13 +67,23 @@ struct serial_console_data {
void (*close)(void);
};
-int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end);
+struct loader_info {
+ void *promptr;
+ unsigned long initrd_addr, initrd_size;
+ char *cmdline;
+ int cmdline_len;
+};
+extern struct loader_info loader_info;
+
+void start(void);
int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device);
int serial_console_init(void);
int ns16550_console_init(void *devp, struct serial_console_data *scdp);
-void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
- u32 max_allocs);
-
+void *simple_alloc_init(char *base, unsigned long heap_size,
+ unsigned long granularity, unsigned long max_allocs);
+extern void flush_cache(void *, unsigned long);
+int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
+int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
static inline void *finddevice(const char *name)
{
@@ -76,12 +95,76 @@ static inline int getprop(void *devp, const char *name, void *buf, int buflen)
return (dt_ops.getprop) ? dt_ops.getprop(devp, name, buf, buflen) : -1;
}
-static inline int setprop(void *devp, const char *name, void *buf, int buflen)
+static inline int setprop(void *devp, const char *name,
+ const void *buf, int buflen)
{
return (dt_ops.setprop) ? dt_ops.setprop(devp, name, buf, buflen) : -1;
}
+#define setprop_val(devp, name, val) \
+ do { \
+ typeof(val) x = (val); \
+ setprop((devp), (name), &x, sizeof(x)); \
+ } while (0)
+
+static inline int setprop_str(void *devp, const char *name, const char *buf)
+{
+ if (dt_ops.setprop)
+ return dt_ops.setprop(devp, name, buf, strlen(buf) + 1);
+
+ return -1;
+}
+
+static inline void *get_parent(const char *devp)
+{
+ return dt_ops.get_parent ? dt_ops.get_parent(devp) : NULL;
+}
+
+static inline void *create_node(const void *parent, const char *name)
+{
+ return dt_ops.create_node ? dt_ops.create_node(parent, name) : NULL;
+}
+
-static inline void *malloc(u32 size)
+static inline void *find_node_by_prop_value(const void *prev,
+ const char *propname,
+ const char *propval, int proplen)
+{
+ if (dt_ops.find_node_by_prop_value)
+ return dt_ops.find_node_by_prop_value(prev, propname,
+ propval, proplen);
+
+ return NULL;
+}
+
+static inline void *find_node_by_prop_value_str(const void *prev,
+ const char *propname,
+ const char *propval)
+{
+ return find_node_by_prop_value(prev, propname, propval,
+ strlen(propval) + 1);
+}
+
+static inline void *find_node_by_devtype(const void *prev,
+ const char *type)
+{
+ return find_node_by_prop_value_str(prev, "device_type", type);
+}
+
+void dt_fixup_memory(u64 start, u64 size);
+void dt_fixup_cpu_clocks(u32 cpufreq, u32 tbfreq, u32 busfreq);
+void dt_fixup_clock(const char *path, u32 freq);
+void __dt_fixup_mac_addresses(u32 startindex, ...);
+#define dt_fixup_mac_addresses(...) \
+ __dt_fixup_mac_addresses(0, __VA_ARGS__, NULL)
+
+
+static inline void *find_node_by_linuxphandle(const u32 linuxphandle)
+{
+ return find_node_by_prop_value(NULL, "linux,phandle",
+ (char *)&linuxphandle, sizeof(u32));
+}
+
+static inline void *malloc(unsigned long size)
{
return (platform_ops.malloc) ? platform_ops.malloc(size) : NULL;
}
@@ -98,5 +181,11 @@ static inline void exit(void)
platform_ops.exit();
for(;;);
}
+#define fatal(args...) { printf(args); exit(); }
+
+
+#define BSS_STACK(size) \
+ static char _bss_stack[size]; \
+ void *_platform_stack_top = _bss_stack + sizeof(_bss_stack);
#endif /* _PPC_BOOT_OPS_H_ */
diff --git a/arch/powerpc/boot/ppcboot.h b/arch/powerpc/boot/ppcboot.h
new file mode 100644
index 000000000000..5290ff2c2b2b
--- /dev/null
+++ b/arch/powerpc/boot/ppcboot.h
@@ -0,0 +1,108 @@
+/*
+ * This interface is used for compatibility with old U-boots *ONLY*.
+ * Please do not imitate or extend this.
+ */
+
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __PPCBOOT_H__
+#define __PPCBOOT_H__
+
+/*
+ * Board information passed to kernel from PPCBoot
+ *
+ * include/asm-ppc/ppcboot.h
+ */
+
+#include "types.h"
+
+typedef struct bd_info {
+ unsigned long bi_memstart; /* start of DRAM memory */
+ unsigned long bi_memsize; /* size of DRAM memory in bytes */
+ unsigned long bi_flashstart; /* start of FLASH memory */
+ unsigned long bi_flashsize; /* size of FLASH memory */
+ unsigned long bi_flashoffset; /* reserved area for startup monitor */
+ unsigned long bi_sramstart; /* start of SRAM memory */
+ unsigned long bi_sramsize; /* size of SRAM memory */
+#if defined(TARGET_8xx) || defined(TARGET_CPM2) || defined(TARGET_85xx) ||\
+ defined(TARGET_83xx)
+ unsigned long bi_immr_base; /* base of IMMR register */
+#endif
+#if defined(TARGET_PPC_MPC52xx)
+ unsigned long bi_mbar_base; /* base of internal registers */
+#endif
+ unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */
+ unsigned long bi_ip_addr; /* IP Address */
+ unsigned char bi_enetaddr[6]; /* Ethernet address */
+ unsigned short bi_ethspeed; /* Ethernet speed in Mbps */
+ unsigned long bi_intfreq; /* Internal Freq, in MHz */
+ unsigned long bi_busfreq; /* Bus Freq, in MHz */
+#if defined(TARGET_CPM2)
+ unsigned long bi_cpmfreq; /* CPM_CLK Freq, in MHz */
+ unsigned long bi_brgfreq; /* BRG_CLK Freq, in MHz */
+ unsigned long bi_sccfreq; /* SCC_CLK Freq, in MHz */
+ unsigned long bi_vco; /* VCO Out from PLL, in MHz */
+#endif
+#if defined(TARGET_PPC_MPC52xx)
+ unsigned long bi_ipbfreq; /* IPB Bus Freq, in MHz */
+ unsigned long bi_pcifreq; /* PCI Bus Freq, in MHz */
+#endif
+ unsigned long bi_baudrate; /* Console Baudrate */
+#if defined(TARGET_4xx)
+ unsigned char bi_s_version[4]; /* Version of this structure */
+ unsigned char bi_r_version[32]; /* Version of the ROM (IBM) */
+ unsigned int bi_procfreq; /* CPU (Internal) Freq, in Hz */
+ unsigned int bi_plb_busfreq; /* PLB Bus speed, in Hz */
+ unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
+ unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */
+#endif
+#if defined(TARGET_HYMOD)
+ hymod_conf_t bi_hymod_conf; /* hymod configuration information */
+#endif
+#if defined(TARGET_EVB64260) || defined(TARGET_405EP) || defined(TARGET_44x) || \
+ defined(TARGET_85xx) || defined(TARGET_83xx)
+ /* second onboard ethernet port */
+ unsigned char bi_enet1addr[6];
+#define HAVE_ENET1ADDR
+#endif
+#if defined(TARGET_EVB64260) || defined(TARGET_440GX) || defined(TARGET_85xx)
+ /* third onboard ethernet ports */
+ unsigned char bi_enet2addr[6];
+#define HAVE_ENET2ADDR
+#endif
+#if defined(TARGET_440GX)
+ /* fourth onboard ethernet ports */
+ unsigned char bi_enet3addr[6];
+#define HAVE_ENET3ADDR
+#endif
+#if defined(TARGET_4xx)
+ unsigned int bi_opbfreq; /* OB clock in Hz */
+ int bi_iic_fast[2]; /* Use fast i2c mode */
+#endif
+#if defined(TARGET_440GX)
+ int bi_phynum[4]; /* phy mapping */
+ int bi_phymode[4]; /* phy mode */
+#endif
+} bd_t;
+
+#define bi_tbfreq bi_intfreq
+
+#endif /* __PPCBOOT_H__ */
diff --git a/arch/powerpc/boot/reg.h b/arch/powerpc/boot/reg.h
new file mode 100644
index 000000000000..d3cd9ee98afb
--- /dev/null
+++ b/arch/powerpc/boot/reg.h
@@ -0,0 +1,22 @@
+#ifndef _PPC_BOOT_REG_H
+#define _PPC_BOOT_REG_H
+/*
+ * Copyright 2007 Davud Gibson, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+static inline u32 mfpvr(void)
+{
+ u32 pvr;
+ asm volatile ("mfpvr %0" : "=r"(pvr));
+ return pvr;
+}
+
+register void *__stack_pointer asm("r1");
+#define get_sp() (__stack_pointer)
+
+#endif /* _PPC_BOOT_REG_H */
diff --git a/arch/powerpc/boot/simple_alloc.c b/arch/powerpc/boot/simple_alloc.c
index cfe3a7505ba0..65ec135d0157 100644
--- a/arch/powerpc/boot/simple_alloc.c
+++ b/arch/powerpc/boot/simple_alloc.c
@@ -19,24 +19,24 @@
#define ENTRY_IN_USE 0x02
static struct alloc_info {
- u32 flags;
- u32 base;
- u32 size;
+ unsigned long flags;
+ unsigned long base;
+ unsigned long size;
} *alloc_tbl;
-static u32 tbl_entries;
-static u32 alloc_min;
-static u32 next_base;
-static u32 space_left;
+static unsigned long tbl_entries;
+static unsigned long alloc_min;
+static unsigned long next_base;
+static unsigned long space_left;
/*
* First time an entry is used, its base and size are set.
* An entry can be freed and re-malloc'd but its base & size don't change.
* Should be smart enough for needs of bootwrapper.
*/
-static void *simple_malloc(u32 size)
+static void *simple_malloc(unsigned long size)
{
- u32 i;
+ unsigned long i;
struct alloc_info *p = alloc_tbl;
if (size == 0)
@@ -67,13 +67,14 @@ err_out:
static struct alloc_info *simple_find_entry(void *ptr)
{
- u32 i;
+ unsigned long i;
struct alloc_info *p = alloc_tbl;
for (i=0; i<tbl_entries; i++,p++) {
if (!(p->flags & ENTRY_BEEN_USED))
break;
- if ((p->flags & ENTRY_IN_USE) && (p->base == (u32)ptr))
+ if ((p->flags & ENTRY_IN_USE) &&
+ (p->base == (unsigned long)ptr))
return p;
}
return NULL;
@@ -122,10 +123,10 @@ static void *simple_realloc(void *ptr, unsigned long size)
* Returns addr of first byte after heap so caller can see if it took
* too much space. If so, change args & try again.
*/
-void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
- u32 max_allocs)
+void *simple_alloc_init(char *base, unsigned long heap_size,
+ unsigned long granularity, unsigned long max_allocs)
{
- u32 heap_base, tbl_size;
+ unsigned long heap_base, tbl_size;
heap_size = _ALIGN_UP(heap_size, granularity);
alloc_min = granularity;
@@ -136,7 +137,7 @@ void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
alloc_tbl = (struct alloc_info *)_ALIGN_UP((unsigned long)base, 8);
memset(alloc_tbl, 0, tbl_size);
- heap_base = _ALIGN_UP((u32)alloc_tbl + tbl_size, alloc_min);
+ heap_base = _ALIGN_UP((unsigned long)alloc_tbl + tbl_size, alloc_min);
next_base = heap_base;
space_left = heap_size;
diff --git a/arch/powerpc/boot/stdio.h b/arch/powerpc/boot/stdio.h
index 73b8a91bfb34..adffc58412d4 100644
--- a/arch/powerpc/boot/stdio.h
+++ b/arch/powerpc/boot/stdio.h
@@ -7,11 +7,12 @@
#define EINVAL 22 /* Invalid argument */
#define ENOSPC 28 /* No space left on device */
-extern int printf(const char *fmt, ...);
+extern int printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
#define fprintf(fmt, args...) printf(args)
-extern int sprintf(char *buf, const char *fmt, ...);
+extern int sprintf(char *buf, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
extern int vsprintf(char *buf, const char *fmt, va_list args);
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 024e4d425c59..5cedd901201f 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -29,6 +29,7 @@ initrd=
dtb=
dts=
cacheit=
+gzip=.gz
# cross-compilation prefix
CROSS=
@@ -42,7 +43,7 @@ tmpdir=.
usage() {
echo 'Usage: wrapper [-o output] [-p platform] [-i initrd]' >&2
echo ' [-d devtree] [-s tree.dts] [-c] [-C cross-prefix]' >&2
- echo ' [-D datadir] [-W workingdir] [vmlinux]' >&2
+ echo ' [-D datadir] [-W workingdir] [--no-gzip] [vmlinux]' >&2
exit 1
}
@@ -91,6 +92,9 @@ while [ "$#" -gt 0 ]; do
[ "$#" -gt 0 ] || usage
tmpdir="$1"
;;
+ --no-gzip)
+ gzip=
+ ;;
-?)
usage
;;
@@ -137,31 +141,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
diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S
index a360905e5428..fe87a90ce7f1 100644
--- a/arch/powerpc/boot/zImage.coff.lds.S
+++ b/arch/powerpc/boot/zImage.coff.lds.S
@@ -1,5 +1,6 @@
OUTPUT_ARCH(powerpc:common)
-ENTRY(_start)
+ENTRY(_zimage_start_opd)
+EXTERN(_zimage_start_opd)
SECTIONS
{
. = (5*1024*1024);
diff --git a/arch/powerpc/boot/zImage.lds.S b/arch/powerpc/boot/zImage.lds.S
index 4be3c6414b04..f6e380fdb388 100644
--- a/arch/powerpc/boot/zImage.lds.S
+++ b/arch/powerpc/boot/zImage.lds.S
@@ -1,5 +1,6 @@
OUTPUT_ARCH(powerpc:common)
ENTRY(_zimage_start)
+EXTERN(_zimage_start)
SECTIONS
{
. = (4*1024*1024);
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index cf7e316ad4f6..6061e5f7696e 100644
--- a/arch/powerpc/configs/cell_defconfig
+++ b/arch/powerpc/configs/cell_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Fri Mar 9 23:34:53 2007
+# Linux kernel version: 2.6.21-rc6
+# Mon Apr 23 20:46:48 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -139,11 +139,31 @@ CONFIG_PPC_MULTIPLATFORM=y
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_MAPLE is not set
# CONFIG_PPC_PASEMI is not set
+CONFIG_PPC_CELLEB=y
+CONFIG_PPC_PS3=y
+
+#
+# PS3 Platform Options
+#
+# CONFIG_PS3_ADVANCED is not set
+CONFIG_PS3_HTAB_SIZE=20
+# CONFIG_PS3_DYNAMIC_DMA is not set
+CONFIG_PS3_USE_LPAR_ADDR=y
+CONFIG_PS3_VUART=y
+CONFIG_PS3_PS3AV=y
+CONFIG_PS3_SYS_MANAGER=y
CONFIG_PPC_CELL=y
CONFIG_PPC_CELL_NATIVE=y
CONFIG_PPC_IBM_CELL_BLADE=y
-CONFIG_PPC_PS3=y
-CONFIG_PPC_CELLEB=y
+
+#
+# Cell Broadband Engine options
+#
+CONFIG_SPU_FS=m
+CONFIG_SPU_BASE=y
+CONFIG_CBE_RAS=y
+CONFIG_CBE_THERM=m
+CONFIG_CBE_CPUFREQ=m
CONFIG_PPC_NATIVE=y
CONFIG_UDBG_RTAS_CONSOLE=y
CONFIG_PPC_UDBG_BEAT=y
@@ -175,26 +195,6 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_MPIC=y
#
-# Cell Broadband Engine options
-#
-CONFIG_SPU_FS=m
-CONFIG_SPU_BASE=y
-CONFIG_CBE_RAS=y
-CONFIG_CBE_THERM=m
-CONFIG_CBE_CPUFREQ=m
-
-#
-# PS3 Platform Options
-#
-# CONFIG_PS3_ADVANCED is not set
-CONFIG_PS3_HTAB_SIZE=20
-# CONFIG_PS3_DYNAMIC_DMA is not set
-CONFIG_PS3_USE_LPAR_ADDR=y
-CONFIG_PS3_VUART=y
-CONFIG_PS3_PS3AV=y
-CONFIG_PS3_SYS_MANAGER=y
-
-#
# Kernel options
#
# CONFIG_HZ_100 is not set
@@ -534,7 +534,6 @@ CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
CONFIG_BLK_DEV_AEC62XX=y
# CONFIG_BLK_DEV_ALI15X3 is not set
@@ -561,11 +560,10 @@ CONFIG_BLK_DEV_SIIMAGE=y
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_BLK_DEV_TC86C001 is not set
-CONFIG_BLK_DEV_IDE_CELLEB=y
+CONFIG_BLK_DEV_CELLEB=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set
#
@@ -937,7 +935,7 @@ CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_HVC_DRIVER=y
CONFIG_HVC_RTAS=y
-# CONFIG_HVC_BEAT is not set
+CONFIG_HVC_BEAT=y
#
# IPMI
@@ -1482,6 +1480,8 @@ CONFIG_NLS_ISO8859_15=m
# Distributed Lock Manager
#
# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
#
# Library routines
@@ -1540,6 +1540,7 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_FAULT_INJECTION is not set
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_DEBUGGER=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 7724847f702a..3ccf19d8da38 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -143,7 +143,7 @@ CONFIG_PPC_NATIVE=y
CONFIG_U3_DART=y
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
# CONFIG_PPC_MPC106 is not set
CONFIG_PPC_970_NAP=y
# CONFIG_PPC_INDIRECT_IO is not set
diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig
index de97f2f0ae96..15366f0e489f 100644
--- a/arch/powerpc/configs/maple_defconfig
+++ b/arch/powerpc/configs/maple_defconfig
@@ -146,7 +146,7 @@ CONFIG_PPC_RTAS=y
CONFIG_RTAS_PROC=y
# CONFIG_RTAS_FLASH is not set
# CONFIG_MMIO_NVRAM is not set
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
# CONFIG_PPC_MPC106 is not set
CONFIG_PPC_970_NAP=y
# CONFIG_PPC_INDIRECT_IO is not set
diff --git a/arch/powerpc/configs/mpc832x_rdb_defconfig b/arch/powerpc/configs/mpc832x_rdb_defconfig
new file mode 100644
index 000000000000..56fc0a824458
--- /dev/null
+++ b/arch/powerpc/configs/mpc832x_rdb_defconfig
@@ -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
index 000000000000..b563513cc96c
--- /dev/null
+++ b/arch/powerpc/configs/mpc8544_ds_defconfig
@@ -0,0 +1,1077 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3
+# Mon Mar 19 17:18:49 2007
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_85xx=y
+CONFIG_E500=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+# CONFIG_SPE is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_IPC_NS=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_MPC85xx_CDS is not set
+# CONFIG_MPC85xx_MDS is not set
+CONFIG_MPC8544_DS=y
+CONFIG_MPC85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+CONFIG_MPIC=y
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="root=/dev/sda3 rw console=ttyS0,115200"
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_ARPD=y
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_FIB_RULES=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_PATA_PLATFORM is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+CONFIG_VITESSE_PHY=y
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_NVRAM=y
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+# CONFIG_DVB_CORE_ATTACH is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+
+#
+# DVB-T (terrestrial) frontends
+#
+
+#
+# DVB-C (cable) frontends
+#
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+
+#
+# Tuners/PLL support
+#
+
+#
+# Miscellaneous devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_CRAMFS=y
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index a8da0aea3b87..126b9f87df25 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -152,7 +152,7 @@ CONFIG_RTAS_ERROR_LOGGING=y
CONFIG_RTAS_PROC=y
CONFIG_RTAS_FLASH=m
CONFIG_MMIO_NVRAM=y
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
CONFIG_IBMVIO=y
# CONFIG_IBMEBUS is not set
# CONFIG_PPC_MPC106 is not set
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 8120d428ebfd..e0fa80eca366 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -25,8 +25,8 @@ obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o
procfs-$(CONFIG_PPC64) := proc_ppc64.o
obj-$(CONFIG_PROC_FS) += $(procfs-y)
-rtaspci-$(CONFIG_PPC64) := rtas_pci.o
-obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y)
+rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI) := rtas_pci.o
+obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y-y)
obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
obj-$(CONFIG_RTAS_PROC) += rtas-proc.o
obj-$(CONFIG_LPARCFG) += lparcfg.o
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index 4734b5de599d..5c9ff7f5c44e 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -241,7 +241,7 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr)
if (user_mode(regs) && !access_ok(VERIFY_WRITE, p, size))
return -EFAULT;
for (i = 0; i < size / sizeof(long); ++i)
- if (__put_user(0, p+i))
+ if (__put_user_inatomic(0, p+i))
return -EFAULT;
return 1;
}
@@ -288,7 +288,8 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
} else {
unsigned long pc = regs->nip ^ (swiz & 4);
- if (__get_user(instr, (unsigned int __user *)pc))
+ if (__get_user_inatomic(instr,
+ (unsigned int __user *)pc))
return -EFAULT;
if (swiz == 0 && (flags & SW))
instr = cpu_to_le32(instr);
@@ -324,27 +325,31 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
((nb0 + 3) / 4) * sizeof(unsigned long));
for (i = 0; i < nb; ++i, ++p)
- if (__get_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p)))
+ if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
+ SWIZ_PTR(p)))
return -EFAULT;
if (nb0 > 0) {
rptr = &regs->gpr[0];
addr += nb;
for (i = 0; i < nb0; ++i, ++p)
- if (__get_user(REG_BYTE(rptr, i ^ bswiz),
- SWIZ_PTR(p)))
+ if (__get_user_inatomic(REG_BYTE(rptr,
+ i ^ bswiz),
+ SWIZ_PTR(p)))
return -EFAULT;
}
} else {
for (i = 0; i < nb; ++i, ++p)
- if (__put_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p)))
+ if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
+ SWIZ_PTR(p)))
return -EFAULT;
if (nb0 > 0) {
rptr = &regs->gpr[0];
addr += nb;
for (i = 0; i < nb0; ++i, ++p)
- if (__put_user(REG_BYTE(rptr, i ^ bswiz),
- SWIZ_PTR(p)))
+ if (__put_user_inatomic(REG_BYTE(rptr,
+ i ^ bswiz),
+ SWIZ_PTR(p)))
return -EFAULT;
}
}
@@ -398,7 +403,8 @@ int fix_alignment(struct pt_regs *regs)
if (cpu_has_feature(CPU_FTR_PPC_LE) && (regs->msr & MSR_LE))
pc ^= 4;
- if (unlikely(__get_user(instr, (unsigned int __user *)pc)))
+ if (unlikely(__get_user_inatomic(instr,
+ (unsigned int __user *)pc)))
return -EFAULT;
if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE))
instr = cpu_to_le32(instr);
@@ -474,16 +480,16 @@ int fix_alignment(struct pt_regs *regs)
p = (unsigned long) addr;
switch (nb) {
case 8:
- ret |= __get_user(data.v[0], SWIZ_PTR(p++));
- ret |= __get_user(data.v[1], SWIZ_PTR(p++));
- ret |= __get_user(data.v[2], SWIZ_PTR(p++));
- ret |= __get_user(data.v[3], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[0], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[1], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[2], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[3], SWIZ_PTR(p++));
case 4:
- ret |= __get_user(data.v[4], SWIZ_PTR(p++));
- ret |= __get_user(data.v[5], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[4], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[5], SWIZ_PTR(p++));
case 2:
- ret |= __get_user(data.v[6], SWIZ_PTR(p++));
- ret |= __get_user(data.v[7], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[6], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[7], SWIZ_PTR(p++));
if (unlikely(ret))
return -EFAULT;
}
@@ -551,16 +557,16 @@ int fix_alignment(struct pt_regs *regs)
p = (unsigned long) addr;
switch (nb) {
case 8:
- ret |= __put_user(data.v[0], SWIZ_PTR(p++));
- ret |= __put_user(data.v[1], SWIZ_PTR(p++));
- ret |= __put_user(data.v[2], SWIZ_PTR(p++));
- ret |= __put_user(data.v[3], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[0], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[1], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[2], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[3], SWIZ_PTR(p++));
case 4:
- ret |= __put_user(data.v[4], SWIZ_PTR(p++));
- ret |= __put_user(data.v[5], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[4], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[5], SWIZ_PTR(p++));
case 2:
- ret |= __put_user(data.v[6], SWIZ_PTR(p++));
- ret |= __put_user(data.v[7], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[6], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[7], SWIZ_PTR(p++));
}
if (unlikely(ret))
return -EFAULT;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 030d300cd71c..0c5150c69175 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -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));
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c
index 3678997339d6..e7b684689e04 100644
--- a/arch/powerpc/kernel/btext.c
+++ b/arch/powerpc/kernel/btext.c
@@ -161,33 +161,33 @@ int btext_initialize(struct device_node *np)
unsigned long address = 0;
const u32 *prop;
- prop = get_property(np, "linux,bootx-width", NULL);
+ prop = of_get_property(np, "linux,bootx-width", NULL);
if (prop == NULL)
- prop = get_property(np, "width", NULL);
+ prop = of_get_property(np, "width", NULL);
if (prop == NULL)
return -EINVAL;
width = *prop;
- prop = get_property(np, "linux,bootx-height", NULL);
+ prop = of_get_property(np, "linux,bootx-height", NULL);
if (prop == NULL)
- prop = get_property(np, "height", NULL);
+ prop = of_get_property(np, "height", NULL);
if (prop == NULL)
return -EINVAL;
height = *prop;
- prop = get_property(np, "linux,bootx-depth", NULL);
+ prop = of_get_property(np, "linux,bootx-depth", NULL);
if (prop == NULL)
- prop = get_property(np, "depth", NULL);
+ prop = of_get_property(np, "depth", NULL);
if (prop == NULL)
return -EINVAL;
depth = *prop;
pitch = width * ((depth + 7) / 8);
- prop = get_property(np, "linux,bootx-linebytes", NULL);
+ prop = of_get_property(np, "linux,bootx-linebytes", NULL);
if (prop == NULL)
- prop = get_property(np, "linebytes", NULL);
+ prop = of_get_property(np, "linebytes", NULL);
if (prop && *prop != 0xffffffffu)
pitch = *prop;
if (pitch == 1)
pitch = 0x1000;
- prop = get_property(np, "address", NULL);
+ prop = of_get_property(np, "address", NULL);
if (prop)
address = *prop;
@@ -219,7 +219,7 @@ int __init btext_find_display(int allow_nonstdout)
struct device_node *np = NULL;
int rc = -ENODEV;
- name = get_property(of_chosen, "linux,stdout-path", NULL);
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (name != NULL) {
np = of_find_node_by_path(name);
if (np != NULL) {
@@ -236,7 +236,7 @@ int __init btext_find_display(int allow_nonstdout)
return rc;
for (np = NULL; (np = of_find_node_by_type(np, "display"));) {
- if (get_property(np, "linux,opened", NULL)) {
+ if (of_get_property(np, "linux,opened", NULL)) {
printk("trying %s ...\n", np->full_name);
rc = btext_initialize(np);
printk("result: %d\n", rc);
diff --git a/arch/powerpc/kernel/cpu_setup_pa6t.S b/arch/powerpc/kernel/cpu_setup_pa6t.S
index 4047be25c4d2..d62cb9cae4e9 100644
--- a/arch/powerpc/kernel/cpu_setup_pa6t.S
+++ b/arch/powerpc/kernel/cpu_setup_pa6t.S
@@ -34,7 +34,7 @@ _GLOBAL(__setup_cpu_pa6t)
beqlr
mfspr r0,SPRN_HID5
- ori r0,r0,0x30
+ ori r0,r0,0x38
mtspr SPRN_HID5,r0
mfspr r0,SPRN_LPCR
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index e4006dc087ca..9cb24d20f0f9 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -389,6 +389,8 @@ static struct cpu_spec cpu_specs[] = {
.pmc_type = PPC_PMC_PA6T,
.cpu_setup = __setup_cpu_pa6t,
.cpu_restore = __restore_cpu_pa6t,
+ .oprofile_cpu_type = "ppc64/pa6t",
+ .oprofile_type = PPC_OPROFILE_PA6T,
.platform = "pa6t",
},
{ /* default match */
@@ -558,6 +560,18 @@ static struct cpu_spec cpu_specs[] = {
.cpu_setup = __setup_cpu_750cx,
.platform = "ppc750",
},
+ { /* 750CL */
+ .pvr_mask = 0xfffff0f0,
+ .pvr_value = 0x00087010,
+ .cpu_name = "750CL",
+ .cpu_features = CPU_FTRS_750CL,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .num_pmcs = 4,
+ .cpu_setup = __setup_cpu_750,
+ .platform = "ppc750",
+ },
{ /* 745/755 */
.pvr_mask = 0xfffff000,
.pvr_value = 0x00083000,
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index c03e829fee3c..c29d1652a421 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -191,7 +191,6 @@ stack_ovf:
0:
_GLOBAL(DoSyscall)
- stw r0,THREAD+LAST_SYSCALL(r2)
stw r3,ORIG_GPR3(r1)
li r12,0
stw r12,RESULT(r1)
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 97cedcd6c9b4..1111fcec7673 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -278,8 +278,12 @@ exception_marker:
beq- 1f; \
ld r1,PACAKSAVE(r13); /* kernel stack to use */ \
1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \
- bge- cr1,bad_stack; /* abort if it is */ \
- std r9,_CCR(r1); /* save CR in stackframe */ \
+ bge- cr1,2f; /* abort if it is */ \
+ b 3f; \
+2: li r1,(n); /* will be reloaded later */ \
+ sth r1,PACA_TRAP_SAVE(r13); \
+ b bad_stack; \
+3: std r9,_CCR(r1); /* save CR in stackframe */ \
std r11,_NIP(r1); /* save SRR0 in stackframe */ \
std r12,_MSR(r1); /* save SRR1 in stackframe */ \
std r10,0(r1); /* make stack chain pointer */ \
@@ -940,6 +944,8 @@ bad_stack:
SAVE_2GPRS(7,r1)
SAVE_10GPRS(12,r1)
SAVE_10GPRS(22,r1)
+ lhz r12,PACA_TRAP_SAVE(r13)
+ std r12,_TRAP(r1)
addi r11,r1,INT_FRAME_SIZE
std r11,0(r1)
li r12,0
@@ -1555,7 +1561,6 @@ _GLOBAL(generic_secondary_smp_init)
/* turn on 64-bit mode */
bl .enable_64b_mode
- isync
/* Set up a paca value for this processor. Since we have the
* physical cpu id in r24, we need to search the pacas to find
@@ -1735,10 +1740,6 @@ _STATIC(__boot_from_prom)
/* We never return */
trap
-/*
- * At this point, r3 contains the physical address we are running at,
- * returned by prom_init()
- */
_STATIC(__after_prom_start)
/*
@@ -1851,7 +1852,6 @@ __secondary_start_pmac_0:
_GLOBAL(pmac_secondary_start)
/* turn on 64-bit mode */
bl .enable_64b_mode
- isync
/* Copy some CPU settings from CPU 0 */
bl .__restore_cpu_ppc970
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 82bd2f10770f..9a8c9af43b22 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -2,36 +2,37 @@
* IBM PowerPC IBM eBus Infrastructure Support.
*
* Copyright (c) 2005 IBM Corporation
+ * Joachim Fenkes <fenkes@de.ibm.com>
* Heiko J Schick <schickhj@de.ibm.com>
- *
+ *
* All rights reserved.
*
- * This source code is distributed under a dual license of GPL v2.0 and OpenIB
- * BSD.
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
*
* OpenIB BSD License
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
*
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
*
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
* and/or other materials
- * provided with the distribution.
+ * provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
@@ -43,19 +44,19 @@
#include <asm/ibmebus.h>
#include <asm/abs_addr.h>
-static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */
- .name = ibmebus_bus_device.ofdev.dev.bus_id,
- .ofdev.dev.bus_id = "ibmebus",
- .ofdev.dev.bus = &ibmebus_bus_type,
+static struct device ibmebus_bus_device = { /* fake "parent" device */
+ .bus_id = "ibmebus",
};
+struct bus_type ibmebus_bus_type;
+
static void *ibmebus_alloc_coherent(struct device *dev,
size_t size,
dma_addr_t *dma_handle,
gfp_t flag)
{
void *mem;
-
+
mem = kmalloc(size, flag);
*dma_handle = (dma_addr_t)mem;
@@ -63,7 +64,7 @@ static void *ibmebus_alloc_coherent(struct device *dev,
}
static void ibmebus_free_coherent(struct device *dev,
- size_t size, void *vaddr,
+ size_t size, void *vaddr,
dma_addr_t dma_handle)
{
kfree(vaddr);
@@ -79,7 +80,7 @@ static dma_addr_t ibmebus_map_single(struct device *dev,
static void ibmebus_unmap_single(struct device *dev,
dma_addr_t dma_addr,
- size_t size,
+ size_t size,
enum dma_data_direction direction)
{
return;
@@ -90,13 +91,13 @@ static int ibmebus_map_sg(struct device *dev,
int nents, enum dma_data_direction direction)
{
int i;
-
+
for (i = 0; i < nents; i++) {
- sg[i].dma_address = (dma_addr_t)page_address(sg[i].page)
+ sg[i].dma_address = (dma_addr_t)page_address(sg[i].page)
+ sg[i].offset;
sg[i].dma_length = sg[i].length;
}
-
+
return nents;
}
@@ -128,15 +129,15 @@ static int ibmebus_bus_probe(struct device *dev)
struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
const struct of_device_id *id;
int error = -ENODEV;
-
+
if (!ibmebusdrv->probe)
return error;
-
+
id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev);
if (id) {
error = ibmebusdrv->probe(ibmebusdev, id);
}
-
+
return error;
}
@@ -144,11 +145,11 @@ static int ibmebus_bus_remove(struct device *dev)
{
struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev);
struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
-
+
if (ibmebusdrv->remove) {
return ibmebusdrv->remove(ibmebusdev);
}
-
+
return 0;
}
@@ -158,21 +159,12 @@ static void __devinit ibmebus_dev_release(struct device *dev)
kfree(to_ibmebus_dev(dev));
}
-static ssize_t ibmebusdev_show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name);
-}
-static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name,
- NULL);
-
-static struct ibmebus_dev* __devinit ibmebus_register_device_common(
+static int __devinit ibmebus_register_device_common(
struct ibmebus_dev *dev, const char *name)
{
int err = 0;
- dev->name = name;
- dev->ofdev.dev.parent = &ibmebus_bus_device.ofdev.dev;
+ dev->ofdev.dev.parent = &ibmebus_bus_device;
dev->ofdev.dev.bus = &ibmebus_bus_type;
dev->ofdev.dev.release = ibmebus_dev_release;
@@ -181,17 +173,15 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_common(
dev->ofdev.dev.archdata.numa_node = of_node_to_nid(dev->ofdev.node);
/* An ibmebusdev is based on a of_device. We have to change the
- * bus type to use our own DMA mapping operations.
- */
+ * bus type to use our own DMA mapping operations.
+ */
if ((err = of_device_register(&dev->ofdev)) != 0) {
printk(KERN_ERR "%s: failed to register device (%d).\n",
__FUNCTION__, err);
- return NULL;
+ return -ENODEV;
}
-
- device_create_file(&dev->ofdev.dev, &dev_attr_name);
-
- return dev;
+
+ return 0;
}
static struct ibmebus_dev* __devinit ibmebus_register_device_node(
@@ -201,35 +191,35 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
const char *loc_code;
int length;
- loc_code = get_property(dn, "ibm,loc-code", NULL);
+ loc_code = of_get_property(dn, "ibm,loc-code", NULL);
if (!loc_code) {
printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n",
__FUNCTION__, dn->name ? dn->name : "<unknown>");
- return NULL;
+ return ERR_PTR(-EINVAL);
}
-
+
if (strlen(loc_code) == 0) {
printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n",
__FUNCTION__);
- return NULL;
+ return ERR_PTR(-EINVAL);
}
dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL);
if (!dev) {
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
dev->ofdev.node = of_node_get(dn);
-
+
length = strlen(loc_code);
- memcpy(dev->ofdev.dev.bus_id, loc_code
- + (length - min(length, BUS_ID_SIZE - 1)),
+ memcpy(dev->ofdev.dev.bus_id, loc_code
+ + (length - min(length, BUS_ID_SIZE - 1)),
min(length, BUS_ID_SIZE - 1));
/* Register with generic device framework. */
- if (ibmebus_register_device_common(dev, dn->name) == NULL) {
+ if (ibmebus_register_device_common(dev, dn->name) != 0) {
kfree(dev);
- return NULL;
+ return ERR_PTR(-ENODEV);
}
return dev;
@@ -238,17 +228,16 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
static void ibmebus_probe_of_nodes(char* name)
{
struct device_node *dn = NULL;
-
+
while ((dn = of_find_node_by_name(dn, name))) {
- if (ibmebus_register_device_node(dn) == NULL) {
+ if (IS_ERR(ibmebus_register_device_node(dn))) {
of_node_put(dn);
-
return;
}
}
-
+
of_node_put(dn);
-
+
return;
}
@@ -262,17 +251,21 @@ static void ibmebus_add_devices_by_id(struct of_device_id *idt)
return;
}
-static int ibmebus_match_helper(struct device *dev, void *data)
+static int ibmebus_match_name(struct device *dev, void *data)
{
- if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0)
+ const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+ const char *name;
+
+ name = of_get_property(ebus_dev->ofdev.node, "name", NULL);
+
+ if (name && (strcmp(data, name) == 0))
return 1;
-
+
return 0;
}
static int ibmebus_unregister_device(struct device *dev)
{
- device_remove_file(dev, &dev_attr_name);
of_device_unregister(to_of_device(dev));
return 0;
@@ -281,17 +274,16 @@ static int ibmebus_unregister_device(struct device *dev)
static void ibmebus_remove_devices_by_id(struct of_device_id *idt)
{
struct device *dev;
-
+
while (strlen(idt->name) > 0) {
- while ((dev = bus_find_device(&ibmebus_bus_type, NULL,
+ while ((dev = bus_find_device(&ibmebus_bus_type, NULL,
(void*)idt->name,
- ibmebus_match_helper))) {
+ ibmebus_match_name))) {
ibmebus_unregister_device(dev);
}
idt++;
-
}
-
+
return;
}
@@ -307,30 +299,33 @@ int ibmebus_register_driver(struct ibmebus_driver *drv)
if ((err = driver_register(&drv->driver) != 0))
return err;
+ /* remove all supported devices first, in case someone
+ * probed them manually before registering the driver */
+ ibmebus_remove_devices_by_id(drv->id_table);
ibmebus_add_devices_by_id(drv->id_table);
-
+
return 0;
}
EXPORT_SYMBOL(ibmebus_register_driver);
void ibmebus_unregister_driver(struct ibmebus_driver *drv)
-{
+{
driver_unregister(&drv->driver);
ibmebus_remove_devices_by_id(drv->id_table);
}
EXPORT_SYMBOL(ibmebus_unregister_driver);
int ibmebus_request_irq(struct ibmebus_dev *dev,
- u32 ist,
+ u32 ist,
irq_handler_t handler,
unsigned long irq_flags, const char * devname,
void *dev_id)
{
unsigned int irq = irq_create_mapping(NULL, ist);
-
+
if (irq == NO_IRQ)
return -EINVAL;
-
+
return request_irq(irq, handler,
irq_flags, devname, dev_id);
}
@@ -339,56 +334,163 @@ EXPORT_SYMBOL(ibmebus_request_irq);
void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id)
{
unsigned int irq = irq_find_mapping(NULL, ist);
-
+
free_irq(irq, dev_id);
}
EXPORT_SYMBOL(ibmebus_free_irq);
static int ibmebus_bus_match(struct device *dev, struct device_driver *drv)
-{
+{
const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
struct ibmebus_driver *ebus_drv = to_ibmebus_driver(drv);
const struct of_device_id *ids = ebus_drv->id_table;
const struct of_device_id *found_id;
-
+
if (!ids)
return 0;
-
+
found_id = of_match_device(ids, &ebus_dev->ofdev);
if (found_id)
return 1;
-
+
return 0;
}
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+ const char *name = of_get_property(ebus_dev->ofdev.node, "name", NULL);
+ return sprintf(buf, "%s\n", name);
+}
+
+static struct device_attribute ibmebus_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_NULL
+};
+
+static int ibmebus_match_path(struct device *dev, void *data)
+{
+ int rc;
+ struct device_node *dn =
+ of_node_get(to_ibmebus_dev(dev)->ofdev.node);
+
+ rc = (dn->full_name && (strcasecmp((char*)data, dn->full_name) == 0));
+
+ of_node_put(dn);
+ return rc;
+}
+
+static char *ibmebus_chomp(const char *in, size_t count)
+{
+ char *out = (char*)kmalloc(count + 1, GFP_KERNEL);
+ if (!out)
+ return NULL;
+
+ memcpy(out, in, count);
+ out[count] = '\0';
+ if (out[count - 1] == '\n')
+ out[count - 1] = '\0';
+
+ return out;
+}
+
+static ssize_t ibmebus_store_probe(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ struct device_node *dn = NULL;
+ struct ibmebus_dev *dev;
+ char *path;
+ ssize_t rc;
+
+ path = ibmebus_chomp(buf, count);
+ if (!path)
+ return -ENOMEM;
+
+ if (bus_find_device(&ibmebus_bus_type, NULL, path,
+ ibmebus_match_path)) {
+ printk(KERN_WARNING "%s: %s has already been probed\n",
+ __FUNCTION__, path);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if ((dn = of_find_node_by_path(path))) {
+ dev = ibmebus_register_device_node(dn);
+ of_node_put(dn);
+ rc = IS_ERR(dev) ? PTR_ERR(dev) : count;
+ } else {
+ printk(KERN_WARNING "%s: no such device node: %s\n",
+ __FUNCTION__, path);
+ rc = -ENODEV;
+ }
+
+out:
+ kfree(path);
+ return rc;
+}
+
+static ssize_t ibmebus_store_remove(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ struct device *dev;
+ char *path;
+
+ path = ibmebus_chomp(buf, count);
+ if (!path)
+ return -ENOMEM;
+
+ if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
+ ibmebus_match_path))) {
+ ibmebus_unregister_device(dev);
+
+ kfree(path);
+ return count;
+ } else {
+ printk(KERN_WARNING "%s: %s not on the bus\n",
+ __FUNCTION__, path);
+
+ kfree(path);
+ return -ENODEV;
+ }
+}
+
+static struct bus_attribute ibmebus_bus_attrs[] = {
+ __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe),
+ __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove),
+ __ATTR_NULL
+};
+
struct bus_type ibmebus_bus_type = {
- .name = "ibmebus",
- .match = ibmebus_bus_match,
+ .name = "ibmebus",
+ .match = ibmebus_bus_match,
+ .dev_attrs = ibmebus_dev_attrs,
+ .bus_attrs = ibmebus_bus_attrs
};
EXPORT_SYMBOL(ibmebus_bus_type);
static int __init ibmebus_bus_init(void)
{
int err;
-
+
printk(KERN_INFO "IBM eBus Device Driver\n");
-
+
err = bus_register(&ibmebus_bus_type);
if (err) {
printk(KERN_ERR ":%s: failed to register IBM eBus.\n",
__FUNCTION__);
return err;
}
-
- err = device_register(&ibmebus_bus_device.ofdev.dev);
+
+ err = device_register(&ibmebus_bus_device);
if (err) {
- printk(KERN_WARNING "%s: device_register returned %i\n",
+ printk(KERN_WARNING "%s: device_register returned %i\n",
__FUNCTION__, err);
bus_unregister(&ibmebus_bus_type);
return err;
}
-
+
return 0;
}
__initcall(ibmebus_bus_init);
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 95edad4faf26..c08ceca6277d 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -47,6 +47,8 @@ static int novmerge = 0;
static int novmerge = 1;
#endif
+static int protect4gb = 1;
+
static inline unsigned long iommu_num_pages(unsigned long vaddr,
unsigned long slen)
{
@@ -58,6 +60,16 @@ static inline unsigned long iommu_num_pages(unsigned long vaddr,
return npages;
}
+static int __init setup_protect4gb(char *str)
+{
+ if (strcmp(str, "on") == 0)
+ protect4gb = 1;
+ else if (strcmp(str, "off") == 0)
+ protect4gb = 0;
+
+ return 1;
+}
+
static int __init setup_iommu(char *str)
{
if (!strcmp(str, "novmerge"))
@@ -67,6 +79,7 @@ static int __init setup_iommu(char *str)
return 1;
}
+__setup("protect4gb=", setup_protect4gb);
__setup("iommu=", setup_iommu);
static unsigned long iommu_range_alloc(struct iommu_table *tbl,
@@ -429,6 +442,9 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
{
unsigned long sz;
+ unsigned long start_index, end_index;
+ unsigned long entries_per_4g;
+ unsigned long index;
static int welcomed = 0;
struct page *page;
@@ -450,7 +466,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
#ifdef CONFIG_CRASH_DUMP
if (ppc_md.tce_get) {
- unsigned long index, tceval;
+ unsigned long tceval;
unsigned long tcecount = 0;
/*
@@ -480,6 +496,23 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
#endif
+ /*
+ * DMA cannot cross 4 GB boundary. Mark last entry of each 4
+ * GB chunk as reserved.
+ */
+ if (protect4gb) {
+ entries_per_4g = 0x100000000l >> IOMMU_PAGE_SHIFT;
+
+ /* Mark the last bit before a 4GB boundary as used */
+ start_index = tbl->it_offset | (entries_per_4g - 1);
+ start_index -= tbl->it_offset;
+
+ end_index = tbl->it_size;
+
+ for (index = start_index; index < end_index - 1; index += entries_per_4g)
+ __set_bit(index, tbl->it_map);
+ }
+
if (!welcomed) {
printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
novmerge ? "disabled" : "enabled");
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 100930826850..6c83fe229e60 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -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];
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index dd2886f97e98..ef647e7a9dc3 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -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;
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index 325f490a10cc..63dd2c3ad95e 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -44,12 +44,12 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
int index;
/* get clock freq. if present */
- clk = get_property(np, "clock-frequency", NULL);
+ clk = of_get_property(np, "clock-frequency", NULL);
if (clk && *clk)
clock = *clk;
/* get default speed if present */
- spd = get_property(np, "current-speed", NULL);
+ spd = of_get_property(np, "current-speed", NULL);
/* If we have a location index, then try to use it */
if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)
@@ -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;
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 89486b631284..c492cee90e0f 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -130,30 +130,31 @@ static int iseries_lparcfg_data(struct seq_file *m, void *v)
/*
* Methods used to fetch LPAR data when running on a pSeries platform.
*/
-/* find a better place for this function... */
static void log_plpar_hcall_return(unsigned long rc, char *tag)
{
- if (rc == 0) /* success, return */
+ switch(rc) {
+ case 0:
return;
-/* check for null tag ? */
- if (rc == H_HARDWARE)
- printk(KERN_INFO
- "plpar-hcall (%s) failed with hardware fault\n", tag);
- else if (rc == H_FUNCTION)
- printk(KERN_INFO
- "plpar-hcall (%s) failed; function not allowed\n", tag);
- else if (rc == H_AUTHORITY)
- printk(KERN_INFO
- "plpar-hcall (%s) failed; not authorized to this"
- " function\n", tag);
- else if (rc == H_PARAMETER)
- printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n",
- tag);
- else
- printk(KERN_INFO
- "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n",
- tag, rc);
-
+ case H_HARDWARE:
+ printk(KERN_INFO "plpar-hcall (%s) "
+ "Hardware fault\n", tag);
+ return;
+ case H_FUNCTION:
+ printk(KERN_INFO "plpar-hcall (%s) "
+ "Function not allowed\n", tag);
+ return;
+ case H_AUTHORITY:
+ printk(KERN_INFO "plpar-hcall (%s) "
+ "Not authorized to this function\n", tag);
+ return;
+ case H_PARAMETER:
+ printk(KERN_INFO "plpar-hcall (%s) "
+ "Bad parameter(s)\n",tag);
+ return;
+ default:
+ printk(KERN_INFO "plpar-hcall (%s) "
+ "Unexpected rc(0x%lx)\n", tag, rc);
+ }
}
/*
@@ -321,15 +322,16 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
struct device_node *rtas_node;
const int *lrdrp = NULL;
- rtas_node = find_path_device("/rtas");
+ rtas_node = of_find_node_by_path("/rtas");
if (rtas_node)
- lrdrp = get_property(rtas_node, "ibm,lrdr-capacity", NULL);
+ lrdrp = of_get_property(rtas_node, "ibm,lrdr-capacity", NULL);
if (lrdrp == NULL) {
partition_potential_processors = vdso_data->processorCount;
} else {
partition_potential_processors = *(lrdrp + 4);
}
+ of_node_put(rtas_node);
partition_active_processors = lparcfg_count_active_processors();
@@ -537,25 +539,27 @@ static int lparcfg_data(struct seq_file *m, void *v)
seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
- rootdn = find_path_device("/");
+ rootdn = of_find_node_by_path("/");
if (rootdn) {
- tmp = get_property(rootdn, "model", NULL);
+ tmp = of_get_property(rootdn, "model", NULL);
if (tmp) {
model = tmp;
/* Skip "IBM," - see platforms/iseries/dt.c */
if (firmware_has_feature(FW_FEATURE_ISERIES))
model += 4;
}
- tmp = get_property(rootdn, "system-id", NULL);
+ tmp = of_get_property(rootdn, "system-id", NULL);
if (tmp) {
system_id = tmp;
/* Skip "IBM," - see platforms/iseries/dt.c */
if (firmware_has_feature(FW_FEATURE_ISERIES))
system_id += 4;
}
- lp_index_ptr = get_property(rootdn, "ibm,partition-no", NULL);
+ lp_index_ptr = of_get_property(rootdn, "ibm,partition-no",
+ NULL);
if (lp_index_ptr)
lp_index = *lp_index_ptr;
+ of_node_put(rootdn);
}
seq_printf(m, "serial_number=%s\n", system_id);
seq_printf(m, "system_type=%s\n", model);
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index a24b09c27718..704375bda73a 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -72,8 +72,8 @@ int default_machine_kexec_prepare(struct kimage *image)
/* We also should not overwrite the tce tables */
for (node = of_find_node_by_type(NULL, "pci"); node != NULL;
node = of_find_node_by_type(node, "pci")) {
- basep = get_property(node, "linux,tce-base", NULL);
- sizep = get_property(node, "linux,tce-size", NULL);
+ basep = of_get_property(node, "linux,tce-base", NULL);
+ sizep = of_get_property(node, "linux,tce-size", NULL);
if (basep == NULL || sizep == NULL)
continue;
@@ -294,19 +294,19 @@ static unsigned long htab_base, kernel_end;
static struct property htab_base_prop = {
.name = "linux,htab-base",
.length = sizeof(unsigned long),
- .value = (unsigned char *)&htab_base,
+ .value = &htab_base,
};
static struct property htab_size_prop = {
.name = "linux,htab-size",
.length = sizeof(unsigned long),
- .value = (unsigned char *)&htab_size_bytes,
+ .value = &htab_size_bytes,
};
static struct property kernel_end_prop = {
.name = "linux,kernel-end",
.length = sizeof(unsigned long),
- .value = (unsigned char *)&kernel_end,
+ .value = &kernel_end,
};
static void __init export_htab_values(void)
@@ -335,7 +335,7 @@ static void __init export_htab_values(void)
static struct property crashk_base_prop = {
.name = "linux,crashkernel-base",
.length = sizeof(unsigned long),
- .value = (unsigned char *)&crashk_res.start,
+ .value = &crashk_res.start,
};
static unsigned long crashk_size;
@@ -343,7 +343,7 @@ static unsigned long crashk_size;
static struct property crashk_size_prop = {
.name = "linux,crashkernel-size",
.length = sizeof(unsigned long),
- .value = (unsigned char *)&crashk_size,
+ .value = &crashk_size,
};
static void __init export_crashk_values(void)
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 412bea3cf813..98decf8ebff4 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -734,10 +734,6 @@ _GLOBAL(abs)
sub r3,r3,r4
blr
-_GLOBAL(_get_SP)
- mr r3,r1 /* Close enough */
- blr
-
/*
* Create a kernel thread
* kernel_thread(fn, arg, flags)
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index e921514e655b..0c8ea7659d92 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -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);
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index 9e7a4d249f03..908ed7926db4 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -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) {
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index d8ef2e100505..f022862de344 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -637,7 +637,7 @@ make_one_node_map(struct device_node* node, u8 pci_bus)
if (pci_bus >= pci_bus_count)
return;
- bus_range = get_property(node, "bus-range", &len);
+ bus_range = of_get_property(node, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, "
"assuming it starts at 0\n", node->full_name);
@@ -649,17 +649,20 @@ make_one_node_map(struct device_node* node, u8 pci_bus)
struct pci_dev* dev;
const unsigned int *class_code, *reg;
- class_code = get_property(node, "class-code", NULL);
+ class_code = of_get_property(node, "class-code", NULL);
if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
continue;
- reg = get_property(node, "reg", NULL);
+ reg = of_get_property(node, "reg", NULL);
if (!reg)
continue;
- dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff));
- if (!dev || !dev->subordinate)
+ dev = pci_get_bus_and_slot(pci_bus, ((reg[0] >> 8) & 0xff));
+ if (!dev || !dev->subordinate) {
+ pci_dev_put(dev);
continue;
+ }
make_one_node_map(node, dev->subordinate->number);
+ pci_dev_put(dev);
}
}
@@ -669,6 +672,7 @@ pcibios_make_OF_bus_map(void)
int i;
struct pci_controller* hose;
struct property *map_prop;
+ struct device_node *dn;
pci_to_OF_bus_map = kmalloc(pci_bus_count, GFP_KERNEL);
if (!pci_to_OF_bus_map) {
@@ -690,12 +694,13 @@ pcibios_make_OF_bus_map(void)
continue;
make_one_node_map(node, hose->first_busno);
}
- map_prop = of_find_property(find_path_device("/"),
- "pci-OF-bus-map", NULL);
+ dn = of_find_node_by_path("/");
+ map_prop = of_find_property(dn, "pci-OF-bus-map", NULL);
if (map_prop) {
BUG_ON(pci_bus_count > map_prop->length);
memcpy(map_prop->value, pci_to_OF_bus_map, pci_bus_count);
}
+ of_node_put(dn);
#ifdef DEBUG
printk("PCI->OF bus map:\n");
for (i=0; i<pci_bus_count; i++) {
@@ -724,7 +729,7 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
* a fake root for all functions of a multi-function device,
* we go down them as well.
*/
- class_code = get_property(node, "class-code", NULL);
+ class_code = of_get_property(node, "class-code", NULL);
if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
strcmp(node->name, "multifunc-device"))
@@ -744,7 +749,7 @@ static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
unsigned int psize;
while ((np = of_get_next_child(parent, np)) != NULL) {
- reg = get_property(np, "reg", &psize);
+ reg = of_get_property(np, "reg", &psize);
if (reg == NULL || psize < 4)
continue;
if (((reg[0] >> 8) & 0xff) == devfn)
@@ -859,7 +864,7 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child,
find_OF_pci_device_filter, (void *)node))
return -ENODEV;
- reg = get_property(node, "reg", NULL);
+ reg = of_get_property(node, "reg", NULL);
if (!reg)
return -ENODEV;
*bus = (reg[0] >> 16) & 0xff;
@@ -895,14 +900,14 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
int rlen = 0, orig_rlen;
int memno = 0;
struct resource *res;
- int np, na = prom_n_addr_cells(dev);
+ int np, na = of_n_addr_cells(dev);
np = na + 5;
/* First we try to merge ranges to fix a problem with some pmacs
* that can have more than 3 ranges, fortunately using contiguous
* addresses -- BenH
*/
- dt_ranges = get_property(dev, "ranges", &rlen);
+ dt_ranges = of_get_property(dev, "ranges", &rlen);
if (!dt_ranges)
return;
/* Sanity check, though hopefully that never happens */
@@ -1006,14 +1011,19 @@ void __init
pci_create_OF_bus_map(void)
{
struct property* of_prop;
-
+ struct device_node *dn;
+
of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256);
- if (of_prop && find_path_device("/")) {
+ if (!of_prop)
+ return;
+ dn = of_find_node_by_path("/");
+ if (dn) {
memset(of_prop, -1, sizeof(struct property) + 256);
of_prop->name = "pci-OF-bus-map";
of_prop->length = 256;
- of_prop->value = (unsigned char *)&of_prop[1];
- prom_add_property(find_path_device("/"), of_prop);
+ of_prop->value = &of_prop[1];
+ prom_add_property(dn, of_prop);
+ of_node_put(dn);
}
}
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 7e97d71a5f8f..60d7d4baa227 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -61,8 +61,7 @@ void iSeries_pcibios_init(void);
LIST_HEAD(hose_list);
-struct dma_mapping_ops *pci_dma_ops;
-EXPORT_SYMBOL(pci_dma_ops);
+static struct dma_mapping_ops *pci_dma_ops;
int global_phb_number; /* Global phb counter */
@@ -70,6 +69,17 @@ int global_phb_number; /* Global phb counter */
struct pci_dev *ppc64_isabridge_dev = NULL;
EXPORT_SYMBOL_GPL(ppc64_isabridge_dev);
+void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
+{
+ pci_dma_ops = dma_ops;
+}
+
+struct dma_mapping_ops *get_pci_dma_ops(void)
+{
+ return pci_dma_ops;
+}
+EXPORT_SYMBOL(get_pci_dma_ops);
+
static void fixup_broken_pcnet32(struct pci_dev* dev)
{
if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
@@ -258,7 +268,7 @@ static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
const u32 *prop;
int len;
- prop = get_property(np, name, &len);
+ prop = of_get_property(np, name, &len);
if (prop && len >= 4)
return *prop;
return def;
@@ -291,7 +301,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
u32 i;
int proplen;
- addrs = get_property(node, "assigned-addresses", &proplen);
+ addrs = of_get_property(node, "assigned-addresses", &proplen);
if (!addrs)
return;
DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs);
@@ -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;
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index 68df018dae0e..d7d36df9c053 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -40,7 +40,8 @@
static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
{
struct pci_controller *phb = data;
- const int *type = get_property(dn, "ibm,pci-config-space-type", NULL);
+ const int *type =
+ of_get_property(dn, "ibm,pci-config-space-type", NULL);
const u32 *regs;
struct pci_dn *pdn;
@@ -54,14 +55,14 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
dn->data = pdn;
pdn->node = dn;
pdn->phb = phb;
- regs = get_property(dn, "reg", NULL);
+ regs = of_get_property(dn, "reg", NULL);
if (regs) {
/* First register entry is addr (00BBSS00) */
pdn->busno = (regs[0] >> 16) & 0xff;
pdn->devfn = (regs[0] >> 8) & 0xff;
}
if (firmware_has_feature(FW_FEATURE_ISERIES)) {
- const u32 *busp = get_property(dn, "linux,subbus", NULL);
+ const u32 *busp = of_get_property(dn, "linux,subbus", NULL);
if (busp)
pdn->bussubno = *busp;
}
@@ -100,7 +101,7 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
u32 class;
nextdn = NULL;
- classp = get_property(dn, "class-code", NULL);
+ classp = of_get_property(dn, "class-code", NULL);
class = classp ? *classp : 0;
if (pre && ((ret = pre(dn, data)) != NULL))
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 2f8e9c02c92a..ff252aaead12 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -20,7 +20,6 @@
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/ide.h>
#include <asm/atomic.h>
#include <asm/checksum.h>
#include <asm/pgtable.h>
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index e53b2988d1bf..e509aae2feb3 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -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
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 8d52b23348bd..caef555f2dc0 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -390,18 +390,19 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
if (allnextpp) {
pp->name = "name";
pp->length = sz;
- pp->value = (unsigned char *)(pp + 1);
+ pp->value = pp + 1;
*prev_pp = pp;
prev_pp = &pp->next;
memcpy(pp->value, ps, sz - 1);
((char *)pp->value)[sz - 1] = 0;
- DBG("fixed up name for %s -> %s\n", pathp, pp->value);
+ DBG("fixed up name for %s -> %s\n", pathp,
+ (char *)pp->value);
}
}
if (allnextpp) {
*prev_pp = NULL;
- np->name = get_property(np, "name", NULL);
- np->type = get_property(np, "device_type", NULL);
+ np->name = of_get_property(np, "name", NULL);
+ np->type = of_get_property(np, "device_type", NULL);
if (!np->name)
np->name = "<NULL>";
@@ -719,6 +720,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
const char *uname, int depth, void *data)
{
unsigned long *lprop;
+ u32 *prop;
unsigned long l;
char *p;
@@ -760,6 +762,22 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
crashk_res.end = crashk_res.start + *lprop - 1;
#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+ DBG("Looking for initrd properties... ");
+ prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
+ if (prop) {
+ initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
+ prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
+ if (prop) {
+ initrd_end = (unsigned long)__va(of_read_ulong(prop, l/4));
+ initrd_below_start_ok = 1;
+ } else {
+ initrd_start = 0;
+ }
+ }
+ DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
/* Retreive command line */
p = of_get_flat_dt_prop(node, "bootargs", &l);
if (p != NULL && l > 0)
@@ -926,6 +944,12 @@ static void __init early_reserve_mem(void)
self_size = initial_boot_params->totalsize;
lmb_reserve(self_base, self_size);
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* then reserve the initrd, if any */
+ if (initrd_start && (initrd_end > initrd_start))
+ lmb_reserve(__pa(initrd_start), initrd_end - initrd_start);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
#ifdef CONFIG_PPC32
/*
* Handle the case where we might be booting from an old kexec
@@ -954,9 +978,6 @@ static void __init early_reserve_mem(void)
size = *(reserve_map++);
if (size == 0)
break;
- /* skip if the reservation is for the blob */
- if (base == self_base && size == self_size)
- continue;
DBG("reserving: %llx -> %llx\n", base, size);
lmb_reserve(base, size);
}
@@ -1021,102 +1042,46 @@ void __init early_init_devtree(void *params)
#undef printk
-int
-prom_n_addr_cells(struct device_node* np)
+int of_n_addr_cells(struct device_node* np)
{
const int *ip;
do {
if (np->parent)
np = np->parent;
- ip = get_property(np, "#address-cells", NULL);
+ ip = of_get_property(np, "#address-cells", NULL);
if (ip != NULL)
return *ip;
} while (np->parent);
/* No #address-cells property for the root node, default to 1 */
return 1;
}
-EXPORT_SYMBOL(prom_n_addr_cells);
+EXPORT_SYMBOL(of_n_addr_cells);
-int
-prom_n_size_cells(struct device_node* np)
+int of_n_size_cells(struct device_node* np)
{
const int* ip;
do {
if (np->parent)
np = np->parent;
- ip = get_property(np, "#size-cells", NULL);
+ ip = of_get_property(np, "#size-cells", NULL);
if (ip != NULL)
return *ip;
} while (np->parent);
/* No #size-cells property for the root node, default to 1 */
return 1;
}
-EXPORT_SYMBOL(prom_n_size_cells);
-
-/**
- * Construct and return a list of the device_nodes with a given name.
- */
-struct device_node *find_devices(const char *name)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- if (np->name != 0 && strcasecmp(np->name, name) == 0) {
- *prevp = np;
- prevp = &np->next;
- }
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_devices);
-
-/**
- * Construct and return a list of the device_nodes with a given type.
- */
-struct device_node *find_type_devices(const char *type)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- if (np->type != 0 && strcasecmp(np->type, type) == 0) {
- *prevp = np;
- prevp = &np->next;
- }
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_type_devices);
-
-/**
- * Returns all nodes linked together
- */
-struct device_node *find_all_nodes(void)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- *prevp = np;
- prevp = &np->next;
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_all_nodes);
+EXPORT_SYMBOL(of_n_size_cells);
/** Checks if the given "compat" string matches one of the strings in
* the device's "compatible" property
*/
-int device_is_compatible(const struct device_node *device, const char *compat)
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
{
const char* cp;
int cplen, l;
- cp = get_property(device, "compatible", &cplen);
+ cp = of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
@@ -1129,7 +1094,7 @@ int device_is_compatible(const struct device_node *device, const char *compat)
return 0;
}
-EXPORT_SYMBOL(device_is_compatible);
+EXPORT_SYMBOL(of_device_is_compatible);
/**
@@ -1143,51 +1108,13 @@ int machine_is_compatible(const char *compat)
root = of_find_node_by_path("/");
if (root) {
- rc = device_is_compatible(root, compat);
+ rc = of_device_is_compatible(root, compat);
of_node_put(root);
}
return rc;
}
EXPORT_SYMBOL(machine_is_compatible);
-/**
- * Construct and return a list of the device_nodes with a given type
- * and compatible property.
- */
-struct device_node *find_compatible_devices(const char *type,
- const char *compat)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- if (type != NULL
- && !(np->type != 0 && strcasecmp(np->type, type) == 0))
- continue;
- if (device_is_compatible(np, compat)) {
- *prevp = np;
- prevp = &np->next;
- }
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_compatible_devices);
-
-/**
- * Find the device_node with a given full_name.
- */
-struct device_node *find_path_device(const char *path)
-{
- struct device_node *np;
-
- for (np = allnodes; np != 0; np = np->allnext)
- if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
- return np;
- return NULL;
-}
-EXPORT_SYMBOL(find_path_device);
-
/*******
*
* New implementation of the OF "find" APIs, return a refcounted
@@ -1280,7 +1207,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
if (type != NULL
&& !(np->type != 0 && strcasecmp(np->type, type) == 0))
continue;
- if (device_is_compatible(np, compatible) && of_node_get(np))
+ if (of_device_is_compatible(np, compatible) && of_node_get(np))
break;
}
of_node_put(from);
@@ -1527,8 +1454,8 @@ static int of_finish_dynamic_node(struct device_node *node)
int err = 0;
const phandle *ibm_phandle;
- node->name = get_property(node, "name", NULL);
- node->type = get_property(node, "device_type", NULL);
+ node->name = of_get_property(node, "name", NULL);
+ node->type = of_get_property(node, "device_type", NULL);
if (!parent) {
err = -ENODEV;
@@ -1542,7 +1469,7 @@ static int of_finish_dynamic_node(struct device_node *node)
return -ENODEV;
/* fix up new node's linux_phandle field */
- if ((ibm_phandle = get_property(node, "ibm,phandle", NULL)))
+ if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL)))
node->linux_phandle = *ibm_phandle;
out:
@@ -1605,13 +1532,13 @@ EXPORT_SYMBOL(of_find_property);
* Find a property with a given name for a given node
* and return the value.
*/
-const void *get_property(const struct device_node *np, const char *name,
+const void *of_get_property(const struct device_node *np, const char *name,
int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
}
-EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(of_get_property);
/*
* Add a property to a node
@@ -1742,10 +1669,10 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
/* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
* fallback to "reg" property and assume no threads
*/
- intserv = get_property(np, "ibm,ppc-interrupt-server#s",
+ intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
&plen);
if (intserv == NULL) {
- const u32 *reg = get_property(np, "reg", NULL);
+ const u32 *reg = of_get_property(np, "reg", NULL);
if (reg == NULL)
continue;
if (*reg == hardid) {
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 4fb5938ce6d3..e27d9d1b6e67 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -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()
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index 91b443c9a488..aa40a5307294 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -68,9 +68,9 @@ static void of_bus_default_count_cells(struct device_node *dev,
int *addrc, int *sizec)
{
if (addrc)
- *addrc = prom_n_addr_cells(dev);
+ *addrc = of_n_addr_cells(dev);
if (sizec)
- *sizec = prom_n_size_cells(dev);
+ *sizec = of_n_size_cells(dev);
}
static u64 of_bus_default_map(u32 *addr, const u32 *range,
@@ -196,7 +196,7 @@ const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
return NULL;
/* Get "reg" or "assigned-addresses" property */
- prop = get_property(dev, bus->addresses, &psize);
+ prop = of_get_property(dev, bus->addresses, &psize);
if (prop == NULL)
return NULL;
psize /= 4;
@@ -438,7 +438,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
* to translate addresses that aren't supposed to be translated in
* the first place. --BenH.
*/
- ranges = get_property(parent, "ranges", &rlen);
+ ranges = of_get_property(parent, "ranges", &rlen);
if (ranges == NULL || rlen == 0) {
offset = of_read_number(addr, na);
memset(addr, 0, pna * 4);
@@ -578,7 +578,7 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
return NULL;
/* Get "reg" or "assigned-addresses" property */
- prop = get_property(dev, bus->addresses, &psize);
+ prop = of_get_property(dev, bus->addresses, &psize);
if (prop == NULL)
return NULL;
psize /= 4;
@@ -650,17 +650,17 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
/* busno is always one cell */
*busno = *(dma_window++);
- prop = get_property(dn, "ibm,#dma-address-cells", NULL);
+ prop = of_get_property(dn, "ibm,#dma-address-cells", NULL);
if (!prop)
- prop = get_property(dn, "#address-cells", NULL);
+ prop = of_get_property(dn, "#address-cells", NULL);
- cells = prop ? *(u32 *)prop : prom_n_addr_cells(dn);
+ cells = prop ? *(u32 *)prop : of_n_addr_cells(dn);
*phys = of_read_number(dma_window, cells);
dma_window += cells;
- prop = get_property(dn, "ibm,#dma-size-cells", NULL);
- cells = prop ? *(u32 *)prop : prom_n_size_cells(dn);
+ prop = of_get_property(dn, "ibm,#dma-size-cells", NULL);
+ cells = prop ? *(u32 *)prop : of_n_size_cells(dn);
*size = of_read_number(dma_window, cells);
}
@@ -680,7 +680,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child)
return NULL;
do {
- parp = get_property(child, "interrupt-parent", NULL);
+ parp = of_get_property(child, "interrupt-parent", NULL);
if (parp == NULL)
p = of_get_parent(child);
else {
@@ -691,7 +691,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child)
}
of_node_put(child);
child = p;
- } while (p && get_property(p, "#interrupt-cells", NULL) == NULL);
+ } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
return p;
}
@@ -716,7 +716,7 @@ void of_irq_map_init(unsigned int flags)
struct device_node *np;
for(np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
- if (get_property(np, "interrupt-controller", NULL)
+ if (of_get_property(np, "interrupt-controller", NULL)
== NULL)
continue;
/* Skip /chosen/interrupt-controller */
@@ -755,7 +755,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
* is none, we are nice and just walk up the tree
*/
do {
- tmp = get_property(ipar, "#interrupt-cells", NULL);
+ tmp = of_get_property(ipar, "#interrupt-cells", NULL);
if (tmp != NULL) {
intsize = *tmp;
break;
@@ -779,7 +779,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
*/
old = of_node_get(ipar);
do {
- tmp = get_property(old, "#address-cells", NULL);
+ tmp = of_get_property(old, "#address-cells", NULL);
tnode = of_get_parent(old);
of_node_put(old);
old = tnode;
@@ -795,7 +795,8 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
/* Now check if cursor is an interrupt-controller and if it is
* then we are done
*/
- if (get_property(ipar, "interrupt-controller", NULL) != NULL) {
+ if (of_get_property(ipar, "interrupt-controller", NULL) !=
+ NULL) {
DBG(" -> got it !\n");
memcpy(out_irq->specifier, intspec,
intsize * sizeof(u32));
@@ -806,7 +807,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
}
/* Now look for an interrupt-map */
- imap = get_property(ipar, "interrupt-map", &imaplen);
+ imap = of_get_property(ipar, "interrupt-map", &imaplen);
/* No interrupt map, check for an interrupt parent */
if (imap == NULL) {
DBG(" -> no map, getting parent\n");
@@ -816,7 +817,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
imaplen /= sizeof(u32);
/* Look for a mask */
- imask = get_property(ipar, "interrupt-map-mask", NULL);
+ imask = of_get_property(ipar, "interrupt-map-mask", NULL);
/* If we were passed no "reg" property and we attempt to parse
* an interrupt-map, then #address-cells must be 0.
@@ -863,15 +864,13 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
/* Get #interrupt-cells and #address-cells of new
* parent
*/
- tmp = get_property(newpar, "#interrupt-cells",
- NULL);
+ tmp = of_get_property(newpar, "#interrupt-cells", NULL);
if (tmp == NULL) {
DBG(" -> parent lacks #interrupt-cells !\n");
goto fail;
}
newintsize = *tmp;
- tmp = get_property(newpar, "#address-cells",
- NULL);
+ tmp = of_get_property(newpar, "#address-cells", NULL);
newaddrsize = (tmp == NULL) ? 0 : *tmp;
DBG(" -> newintsize=%d, newaddrsize=%d\n",
@@ -928,7 +927,7 @@ static int of_irq_map_oldworld(struct device_node *device, int index,
* everything together on these)
*/
while (device) {
- ints = get_property(device, "AAPL,interrupts", &intlen);
+ ints = of_get_property(device, "AAPL,interrupts", &intlen);
if (ints != NULL)
break;
device = device->parent;
@@ -970,13 +969,13 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq
return of_irq_map_oldworld(device, index, out_irq);
/* Get the interrupts property */
- intspec = get_property(device, "interrupts", &intlen);
+ intspec = of_get_property(device, "interrupts", &intlen);
if (intspec == NULL)
return -EINVAL;
intlen /= sizeof(u32);
/* Get the reg property (if any) */
- addr = get_property(device, "reg", NULL);
+ addr = of_get_property(device, "reg", NULL);
/* Look for the interrupt parent. */
p = of_irq_find_parent(device);
@@ -984,7 +983,7 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq
return -EINVAL;
/* Get size of interrupt specifier */
- tmp = get_property(p, "#interrupt-cells", NULL);
+ tmp = of_get_property(p, "#interrupt-cells", NULL);
if (tmp == NULL) {
of_node_put(p);
return -EINVAL;
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
index 6cbf2ae5d7aa..190b7ed1dbfb 100644
--- a/arch/powerpc/kernel/rtas-proc.c
+++ b/arch/powerpc/kernel/rtas-proc.c
@@ -450,7 +450,7 @@ static int ppc_rtas_sensors_show(struct seq_file *m, void *v)
int llen, offs;
sprintf (rstr, SENSOR_PREFIX"%04d", p->token);
- loc = get_property(rtas_node, rstr, &llen);
+ loc = of_get_property(rtas_node, rstr, &llen);
/* A sensor may have multiple instances */
for (j = 0, offs = 0; j <= p->quant; j++) {
@@ -477,7 +477,7 @@ static int ppc_rtas_find_all_sensors(void)
const unsigned int *utmp;
int len, i;
- utmp = get_property(rtas_node, "rtas-sensors", &len);
+ utmp = of_get_property(rtas_node, "rtas-sensors", &len);
if (utmp == NULL) {
printk (KERN_ERR "error: could not get rtas-sensors\n");
return 1;
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 9d0735a54564..214780798289 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -192,18 +192,19 @@ void rtas_progress(char *s, unsigned short hex)
if (display_width == 0) {
display_width = 0x10;
- if ((root = find_path_device("/rtas"))) {
- if ((p = get_property(root,
+ if ((root = of_find_node_by_path("/rtas"))) {
+ if ((p = of_get_property(root,
"ibm,display-line-length", NULL)))
display_width = *p;
- if ((p = get_property(root,
+ if ((p = of_get_property(root,
"ibm,form-feed", NULL)))
form_feed = *p;
- if ((p = get_property(root,
+ if ((p = of_get_property(root,
"ibm,display-number-of-lines", NULL)))
display_lines = *p;
- row_width = get_property(root,
+ row_width = of_get_property(root,
"ibm,display-truncation-length", NULL);
+ of_node_put(root);
}
display_character = rtas_token("display-character");
set_indicator = rtas_token("set-indicator");
@@ -298,7 +299,7 @@ int rtas_token(const char *service)
const int *tokp;
if (rtas.dev == NULL)
return RTAS_UNKNOWN_SERVICE;
- tokp = get_property(rtas.dev, service, NULL);
+ tokp = of_get_property(rtas.dev, service, NULL);
return tokp ? *tokp : RTAS_UNKNOWN_SERVICE;
}
EXPORT_SYMBOL(rtas_token);
@@ -832,12 +833,12 @@ void __init rtas_initialize(void)
if (rtas.dev) {
const u32 *basep, *entryp, *sizep;
- basep = get_property(rtas.dev, "linux,rtas-base", NULL);
- sizep = get_property(rtas.dev, "rtas-size", NULL);
+ basep = of_get_property(rtas.dev, "linux,rtas-base", NULL);
+ sizep = of_get_property(rtas.dev, "rtas-size", NULL);
if (basep != NULL && sizep != NULL) {
rtas.base = *basep;
rtas.size = *sizep;
- entryp = get_property(rtas.dev,
+ entryp = of_get_property(rtas.dev,
"linux,rtas-entry", NULL);
if (entryp == NULL) /* Ugh */
rtas.entry = rtas.base;
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index ace9f4c86e67..f2286822be09 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -60,7 +60,7 @@ static int of_device_available(struct device_node * dn)
{
const char *status;
- status = get_property(dn, "status", NULL);
+ status = of_get_property(dn, "status", NULL);
if (!status)
return 1;
@@ -177,7 +177,7 @@ struct pci_ops rtas_pci_ops = {
int is_python(struct device_node *dev)
{
- const char *model = get_property(dev, "model", NULL);
+ const char *model = of_get_property(dev, "model", NULL);
if (model && strstr(model, "Python"))
return 1;
@@ -247,7 +247,7 @@ static int phb_set_bus_ranges(struct device_node *dev,
const int *bus_range;
unsigned int len;
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
return 1;
}
@@ -274,7 +274,7 @@ int __devinit rtas_setup_phb(struct pci_controller *phb)
return 0;
}
-unsigned long __init find_and_init_phbs(void)
+void __init find_and_init_phbs(void)
{
struct device_node *node;
struct pci_controller *phb;
@@ -309,18 +309,16 @@ unsigned long __init find_and_init_phbs(void)
if (of_chosen) {
const int *prop;
- prop = get_property(of_chosen,
+ prop = of_get_property(of_chosen,
"linux,pci-probe-only", NULL);
if (prop)
pci_probe_only = *prop;
- prop = get_property(of_chosen,
+ prop = of_get_property(of_chosen,
"linux,pci-assign-all-buses", NULL);
if (prop)
pci_assign_all_buses = *prop;
}
-
- return 0;
}
/* RPA-specific bits for removing PHBs */
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 89cfaf49d3de..370803722e47 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -21,7 +21,6 @@
#include <linux/delay.h>
#include <linux/initrd.h>
#include <linux/platform_device.h>
-#include <linux/ide.h>
#include <linux/seq_file.h>
#include <linux/ioport.h>
#include <linux/console.h>
@@ -304,26 +303,8 @@ struct seq_operations cpuinfo_op = {
void __init check_for_initrd(void)
{
#ifdef CONFIG_BLK_DEV_INITRD
- const unsigned int *prop;
- int len;
-
- DBG(" -> check_for_initrd()\n");
-
- if (of_chosen) {
- prop = get_property(of_chosen, "linux,initrd-start", &len);
- if (prop != NULL) {
- initrd_start = (unsigned long)
- __va(of_read_ulong(prop, len / 4));
- prop = get_property(of_chosen,
- "linux,initrd-end", &len);
- if (prop != NULL) {
- initrd_end = (unsigned long)
- __va(of_read_ulong(prop, len / 4));
- initrd_below_start_ok = 1;
- } else
- initrd_start = 0;
- }
- }
+ DBG(" -> check_for_initrd() initrd_start=0x%lx initrd_end=0x%lx\n",
+ initrd_start, initrd_end);
/* If we were passed an initrd, set the ROOT_DEV properly if the values
* look sensible. If not, clear initrd reference.
@@ -371,11 +352,12 @@ void __init smp_setup_cpu_maps(void)
const int *intserv;
int j, len = sizeof(u32), nthreads = 1;
- intserv = get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+ intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s",
+ &len);
if (intserv)
nthreads = len / sizeof(int);
else {
- intserv = get_property(dn, "reg", NULL);
+ intserv = of_get_property(dn, "reg", NULL);
if (!intserv)
intserv = &cpu; /* assume logical == phys */
}
@@ -398,10 +380,10 @@ void __init smp_setup_cpu_maps(void)
int num_addr_cell, num_size_cell, maxcpus;
const unsigned int *ireg;
- num_addr_cell = prom_n_addr_cells(dn);
- num_size_cell = prom_n_size_cells(dn);
+ num_addr_cell = of_n_addr_cells(dn);
+ num_size_cell = of_n_size_cells(dn);
- ireg = get_property(dn, "ibm,lrdr-capacity", NULL);
+ ireg = of_get_property(dn, "ibm,lrdr-capacity", NULL);
if (!ireg)
goto out;
@@ -496,11 +478,39 @@ void probe_machine(void)
printk(KERN_INFO "Using %s machine description\n", ppc_md.name);
}
+/* Match a class of boards, not a specific device configuration. */
int check_legacy_ioport(unsigned long base_port)
{
- if (ppc_md.check_legacy_ioport == NULL)
- return 0;
- return ppc_md.check_legacy_ioport(base_port);
+ struct device_node *parent, *np = NULL;
+ int ret = -ENODEV;
+
+ switch(base_port) {
+ case I8042_DATA_REG:
+ np = of_find_node_by_type(NULL, "8042");
+ break;
+ case FDC_BASE: /* FDC1 */
+ np = of_find_node_by_type(NULL, "fdc");
+ break;
+#ifdef CONFIG_PPC_PREP
+ case _PIDXR:
+ case _PNPWRP:
+ case PNPBIOS_BASE:
+ /* implement me */
+#endif
+ default:
+ /* ipmi is supposed to fail here */
+ break;
+ }
+ if (!np)
+ return ret;
+ parent = of_get_parent(np);
+ if (parent) {
+ if (strcmp(parent->type, "isa") == 0)
+ ret = 0;
+ of_node_put(parent);
+ }
+ of_node_put(np);
+ return ret;
}
EXPORT_SYMBOL(check_legacy_ioport);
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 44a6a3c47feb..35f8f443c14f 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -92,7 +92,8 @@ unsigned long __init early_init(unsigned long dt_ptr)
/* First zero the BSS -- use memset_io, some platforms don't have
* caches on yet */
- memset_io((void __iomem *)PTRRELOC(&__bss_start), 0, _end - __bss_start);
+ memset_io((void __iomem *)PTRRELOC(&__bss_start), 0,
+ __bss_stop - __bss_start);
/*
* Identify the CPU type and fix up code sections
@@ -195,18 +196,22 @@ EXPORT_SYMBOL(nvram_sync);
#endif /* CONFIG_NVRAM */
-static struct cpu cpu_devices[NR_CPUS];
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
int __init ppc_init(void)
{
- int i;
+ int cpu;
/* clear the progress line */
- if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff);
+ if (ppc_md.progress)
+ ppc_md.progress(" ", 0xffff);
/* register CPU devices */
- for_each_possible_cpu(i)
- register_cpu(&cpu_devices[i], i);
+ for_each_possible_cpu(cpu) {
+ struct cpu *c = &per_cpu(cpu_devices, cpu);
+ c->hotpluggable = 1;
+ register_cpu(c, cpu);
+ }
/* call platform init */
if (ppc_md.init != NULL) {
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 3733de30e84d..22083ce3cc30 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -20,7 +20,6 @@
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/initrd.h>
-#include <linux/ide.h>
#include <linux/seq_file.h>
#include <linux/ioport.h>
#include <linux/console.h>
@@ -110,7 +109,7 @@ static void check_smt_enabled(void)
dn = of_find_node_by_path("/options");
if (dn) {
- smt_option = get_property(dn, "ibm,smt-enabled", NULL);
+ smt_option = of_get_property(dn, "ibm,smt-enabled", NULL);
if (smt_option) {
if (!strcmp(smt_option, "on"))
@@ -305,10 +304,10 @@ static void __init initialize_cache_info(void)
size = 0;
lsize = cur_cpu_spec->dcache_bsize;
- sizep = get_property(np, "d-cache-size", NULL);
+ sizep = of_get_property(np, "d-cache-size", NULL);
if (sizep != NULL)
size = *sizep;
- lsizep = get_property(np, dc, NULL);
+ lsizep = of_get_property(np, dc, NULL);
if (lsizep != NULL)
lsize = *lsizep;
if (sizep == 0 || lsizep == 0)
@@ -322,10 +321,10 @@ static void __init initialize_cache_info(void)
size = 0;
lsize = cur_cpu_spec->icache_bsize;
- sizep = get_property(np, "i-cache-size", NULL);
+ sizep = of_get_property(np, "i-cache-size", NULL);
if (sizep != NULL)
size = *sizep;
- lsizep = get_property(np, ic, NULL);
+ lsizep = of_get_property(np, ic, NULL);
if (lsizep != NULL)
lsize = *lsizep;
if (sizep == 0 || lsizep == 0)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 924d692bc8f9..d8e503b2e1af 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -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();
}
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index 673e8d9df7f5..047246ad4f65 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -53,10 +53,6 @@
#include <asm/ppc-pci.h>
#include <asm/syscalls.h>
-/* readdir & getdents */
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
-#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
-
struct old_linux_dirent32 {
u32 d_ino;
u32 d_offset;
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index d57818aea081..933e214c33e8 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -66,16 +66,17 @@ static int __init smt_setup(void)
if (!cpu_has_feature(CPU_FTR_SMT))
return -ENODEV;
- options = find_path_device("/options");
+ options = of_find_node_by_path("/options");
if (!options)
return -ENODEV;
- val = get_property(options, "ibm,smt-snooze-delay", NULL);
+ val = of_get_property(options, "ibm,smt-snooze-delay", NULL);
if (!smt_snooze_cmdline && val) {
for_each_possible_cpu(cpu)
per_cpu(smt_snooze_delay, cpu) = *val;
}
+ of_node_put(options);
return 0;
}
__initcall(smt_setup);
@@ -189,12 +190,12 @@ SYSFS_PMCSETUP(purr, SPRN_PURR);
SYSFS_PMCSETUP(spurr, SPRN_SPURR);
SYSFS_PMCSETUP(dscr, SPRN_DSCR);
-SYSFS_PMCSETUP(pa6t_pmc0, PA6T_SPRN_PMC0);
-SYSFS_PMCSETUP(pa6t_pmc1, PA6T_SPRN_PMC1);
-SYSFS_PMCSETUP(pa6t_pmc2, PA6T_SPRN_PMC2);
-SYSFS_PMCSETUP(pa6t_pmc3, PA6T_SPRN_PMC3);
-SYSFS_PMCSETUP(pa6t_pmc4, PA6T_SPRN_PMC4);
-SYSFS_PMCSETUP(pa6t_pmc5, PA6T_SPRN_PMC5);
+SYSFS_PMCSETUP(pa6t_pmc0, SPRN_PA6T_PMC0);
+SYSFS_PMCSETUP(pa6t_pmc1, SPRN_PA6T_PMC1);
+SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2);
+SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3);
+SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4);
+SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5);
static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index f6f0c6b07c4c..7cedef8f5f70 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -834,7 +834,7 @@ static int __init get_freq(char *name, int cells, unsigned long *val)
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu) {
- fp = get_property(cpu, name, NULL);
+ fp = of_get_property(cpu, name, NULL);
if (fp) {
found = 1;
*val = of_read_ulong(fp, cells);
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 17724fb2067f..f7862224fe85 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -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;
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 2968ffeafdb6..9eaefac5053f 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -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);
diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S
index a6b54cb97c49..25ec5378afa4 100644
--- a/arch/powerpc/lib/copyuser_64.S
+++ b/arch/powerpc/lib/copyuser_64.S
@@ -24,7 +24,7 @@ _GLOBAL(__copy_tofrom_user)
dcbt 0,r4
beq .Lcopy_page_4K
andi. r6,r6,7
- mtcrf 0x01,r5
+ PPC_MTOCRF 0x01,r5
blt cr1,.Lshort_copy
bne .Ldst_unaligned
.Ldst_aligned:
@@ -135,7 +135,7 @@ _GLOBAL(__copy_tofrom_user)
b .Ldo_tail
.Ldst_unaligned:
- mtcrf 0x01,r6 /* put #bytes to 8B bdry into cr7 */
+ PPC_MTOCRF 0x01,r6 /* put #bytes to 8B bdry into cr7 */
subf r5,r6,r5
li r7,0
cmpldi r1,r5,16
@@ -150,7 +150,7 @@ _GLOBAL(__copy_tofrom_user)
2: bf cr7*4+1,3f
37: lwzx r0,r7,r4
83: stwx r0,r7,r3
-3: mtcrf 0x01,r5
+3: PPC_MTOCRF 0x01,r5
add r4,r6,r4
add r3,r6,r3
b .Ldst_aligned
diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c
index 80b482ca30df..79d0fa3a470d 100644
--- a/arch/powerpc/lib/locks.c
+++ b/arch/powerpc/lib/locks.c
@@ -43,9 +43,11 @@ void __spin_yield(raw_spinlock_t *lock)
if (firmware_has_feature(FW_FEATURE_ISERIES))
HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
((u64)holder_cpu << 32) | yield_count);
+#ifdef CONFIG_PPC_SPLPAR
else
plpar_hcall_norets(H_CONFER,
get_hard_smp_processor_id(holder_cpu), yield_count);
+#endif
}
/*
@@ -72,9 +74,11 @@ void __rw_yield(raw_rwlock_t *rw)
if (firmware_has_feature(FW_FEATURE_ISERIES))
HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
((u64)holder_cpu << 32) | yield_count);
+#ifdef CONFIG_PPC_SPLPAR
else
plpar_hcall_norets(H_CONFER,
get_hard_smp_processor_id(holder_cpu), yield_count);
+#endif
}
#endif
diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S
index 68df20283ff5..11ce045e21fd 100644
--- a/arch/powerpc/lib/mem_64.S
+++ b/arch/powerpc/lib/mem_64.S
@@ -19,7 +19,7 @@ _GLOBAL(memset)
rlwimi r4,r4,16,0,15
cmplw cr1,r5,r0 /* do we get that far? */
rldimi r4,r4,32,0
- mtcrf 1,r0
+ PPC_MTOCRF 1,r0
mr r6,r3
blt cr1,8f
beq+ 3f /* if already 8-byte aligned */
@@ -49,7 +49,7 @@ _GLOBAL(memset)
bdnz 4b
5: srwi. r0,r5,3
clrlwi r5,r5,29
- mtcrf 1,r0
+ PPC_MTOCRF 1,r0
beq 8f
bf 29,6f
std r4,0(r6)
@@ -65,7 +65,7 @@ _GLOBAL(memset)
std r4,0(r6)
addi r6,r6,8
8: cmpwi r5,0
- mtcrf 1,r5
+ PPC_MTOCRF 1,r5
beqlr+
bf 29,9f
stw r4,0(r6)
diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S
index 7173ba98f427..3f131129d1c1 100644
--- a/arch/powerpc/lib/memcpy_64.S
+++ b/arch/powerpc/lib/memcpy_64.S
@@ -12,7 +12,7 @@
.align 7
_GLOBAL(memcpy)
std r3,48(r1) /* save destination pointer for return value */
- mtcrf 0x01,r5
+ PPC_MTOCRF 0x01,r5
cmpldi cr1,r5,16
neg r6,r3 # LS 3 bits = # bytes to 8-byte dest bdry
andi. r6,r6,7
@@ -128,7 +128,7 @@ _GLOBAL(memcpy)
b .Ldo_tail
.Ldst_unaligned:
- mtcrf 0x01,r6 # put #bytes to 8B bdry into cr7
+ PPC_MTOCRF 0x01,r6 # put #bytes to 8B bdry into cr7
subf r5,r6,r5
li r7,0
cmpldi r1,r5,16
@@ -143,7 +143,7 @@ _GLOBAL(memcpy)
2: bf cr7*4+1,3f
lwzx r0,r7,r4
stwx r0,r7,r3
-3: mtcrf 0x01,r5
+3: PPC_MTOCRF 0x01,r5
add r4,r6,r4
add r3,r6,r3
b .Ldst_aligned
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 7e8ded051b5b..4aae0c387645 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -54,7 +54,7 @@ static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs)
*/
int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
{
- unsigned int opcode, rd;
+ unsigned int opcode, rs, rb, rd, spr;
unsigned long int imm;
opcode = instr >> 26;
@@ -152,6 +152,49 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
regs->nip &= 0xffffffffUL;
return 1;
#endif
+ case 0x26: /* mfcr */
+ regs->gpr[rd] = regs->ccr;
+ regs->gpr[rd] &= 0xffffffffUL;
+ goto mtspr_out;
+ case 0x2a6: /* mfspr */
+ spr = (instr >> 11) & 0x3ff;
+ switch (spr) {
+ case 0x20: /* mfxer */
+ regs->gpr[rd] = regs->xer;
+ regs->gpr[rd] &= 0xffffffffUL;
+ goto mtspr_out;
+ case 0x100: /* mflr */
+ regs->gpr[rd] = regs->link;
+ goto mtspr_out;
+ case 0x120: /* mfctr */
+ regs->gpr[rd] = regs->ctr;
+ goto mtspr_out;
+ }
+ break;
+ case 0x378: /* orx */
+ rs = (instr >> 21) & 0x1f;
+ rb = (instr >> 11) & 0x1f;
+ if (rs == rb) { /* mr */
+ rd = (instr >> 16) & 0x1f;
+ regs->gpr[rd] = regs->gpr[rs];
+ goto mtspr_out;
+ }
+ break;
+ case 0x3a6: /* mtspr */
+ spr = (instr >> 11) & 0x3ff;
+ switch (spr) {
+ case 0x20: /* mtxer */
+ regs->xer = (regs->gpr[rd] & 0xffffffffUL);
+ goto mtspr_out;
+ case 0x100: /* mtlr */
+ regs->link = regs->gpr[rd];
+ goto mtspr_out;
+ case 0x120: /* mtctr */
+ regs->ctr = regs->gpr[rd];
+mtspr_out:
+ regs->nip += 4;
+ return 1;
+ }
}
}
return 0;
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
index bd68df5fa78a..ddceefc06ecc 100644
--- a/arch/powerpc/mm/hash_low_32.S
+++ b/arch/powerpc/mm/hash_low_32.S
@@ -283,6 +283,7 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
#define PTEG_SIZE 64
#define LG_PTEG_SIZE 6
#define LDPTEu lwzu
+#define LDPTE lwz
#define STPTE stw
#define CMPPTE cmpw
#define PTE_H 0x40
@@ -389,13 +390,30 @@ _GLOBAL(hash_page_patch_C)
* and we know there is a definite (although small) speed
* advantage to putting the PTE in the primary PTEG, we always
* put the PTE in the primary PTEG.
+ *
+ * In addition, we skip any slot that is mapping kernel text in
+ * order to avoid a deadlock when not using BAT mappings if
+ * trying to hash in the kernel hash code itself after it has
+ * already taken the hash table lock. This works in conjunction
+ * with pre-faulting of the kernel text.
+ *
+ * If the hash table bucket is full of kernel text entries, we'll
+ * lockup here but that shouldn't happen
*/
- addis r4,r7,next_slot@ha
+
+1: addis r4,r7,next_slot@ha /* get next evict slot */
lwz r6,next_slot@l(r4)
- addi r6,r6,PTE_SIZE
+ addi r6,r6,PTE_SIZE /* search for candidate */
andi. r6,r6,7*PTE_SIZE
stw r6,next_slot@l(r4)
add r4,r3,r6
+ LDPTE r0,PTE_SIZE/2(r4) /* get PTE second word */
+ clrrwi r0,r0,12
+ lis r6,etext@h
+ ori r6,r6,etext@l /* get etext */
+ tophys(r6,r6)
+ cmpl cr0,r0,r6 /* compare and try again */
+ blt 1b
#ifndef CONFIG_SMP
/* Store PTE in PTEG */
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
index 9bc0a9c2b9bc..e64ce3eec36e 100644
--- a/arch/powerpc/mm/hash_low_64.S
+++ b/arch/powerpc/mm/hash_low_64.S
@@ -445,9 +445,12 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
htab_insert_pte:
/* real page number in r5, PTE RPN value + index */
- rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
+ andis. r0,r31,_PAGE_4K_PFN@h
+ srdi r5,r31,PTE_RPN_SHIFT
+ bne- htab_special_pfn
sldi r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
add r5,r5,r25
+htab_special_pfn:
sldi r5,r5,HW_PAGE_SHIFT
/* Calculate primary group hash */
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 6f1016acdbf6..79aedaf36f2b 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -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);
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 3c7fe2c65b5a..49618461defb 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -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 */
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index f6ffaaa7a5bf..8508f973d9cc 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -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);
}
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 0e53ca8f02fb..5fce6ccecb8d 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -115,6 +115,10 @@ void MMU_setup(void)
if (strstr(cmd_line, "noltlbs")) {
__map_without_ltlbs = 1;
}
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ __map_without_bats = 1;
+ __map_without_ltlbs = 1;
+#endif
}
/*
diff --git a/arch/powerpc/mm/lmb.c b/arch/powerpc/mm/lmb.c
index 716a2906a24d..e3a1e8dc536a 100644
--- a/arch/powerpc/mm/lmb.c
+++ b/arch/powerpc/mm/lmb.c
@@ -146,6 +146,10 @@ static long __init lmb_add_region(struct lmb_region *rgn, unsigned long base,
unsigned long rgnbase = rgn->region[i].base;
unsigned long rgnsize = rgn->region[i].size;
+ if ((rgnbase == base) && (rgnsize == size))
+ /* Already have this region, so we're done */
+ return 0;
+
adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);
if ( adjacent > 0 ) {
rgn->region[i].base -= size;
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 52f397c108a7..c4bcd7546424 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -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);
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index bea2d21ac6f7..9c4538bb04b0 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -19,9 +19,14 @@
* 2 of the License, or (at your option) any later version.
*
*/
+#include <linux/mm.h>
#include <asm/tlbflush.h>
#include <asm/mmu.h>
+extern void hash_preload(struct mm_struct *mm, unsigned long ea,
+ unsigned long access, unsigned long trap);
+
+
#ifdef CONFIG_PPC32
extern void mapin_ram(void);
extern int map_page(unsigned long va, phys_addr_t pa, int flags);
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index e86c37c82cfd..b3a592b25ab3 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -74,7 +74,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu)
while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) {
/* Try interrupt server first */
- interrupt_server = get_property(cpu_node,
+ interrupt_server = of_get_property(cpu_node,
"ibm,ppc-interrupt-server#s", &len);
len = len / sizeof(u32);
@@ -85,7 +85,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu)
return cpu_node;
}
} else {
- reg = get_property(cpu_node, "reg", &len);
+ reg = of_get_property(cpu_node, "reg", &len);
if (reg && (len > 0) && (reg[0] == hw_cpuid))
return cpu_node;
}
@@ -97,7 +97,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu)
/* must hold reference to node during call */
static const int *of_get_associativity(struct device_node *dev)
{
- return get_property(dev, "ibm,associativity", NULL);
+ return of_get_property(dev, "ibm,associativity", NULL);
}
/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
@@ -179,7 +179,7 @@ static int __init find_min_common_depth(void)
* configuration (should be all 0's) and the second is for a normal
* NUMA configuration.
*/
- ref_points = get_property(rtas_root,
+ ref_points = of_get_property(rtas_root,
"ibm,associativity-reference-points", &len);
if ((len >= 1) && ref_points) {
@@ -201,8 +201,8 @@ static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
if (!memory)
panic("numa.c: No memory nodes found!");
- *n_addr_cells = prom_n_addr_cells(memory);
- *n_size_cells = prom_n_size_cells(memory);
+ *n_addr_cells = of_n_addr_cells(memory);
+ *n_size_cells = of_n_size_cells(memory);
of_node_put(memory);
}
@@ -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;
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index c284bdac9947..bca560374927 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -183,8 +183,8 @@ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
* mem_init() sets high_memory so only do the check after that.
*/
if (mem_init_done && (p < virt_to_phys(high_memory))) {
- printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p,
- __builtin_return_address(0));
+ printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n",
+ (unsigned long long)p, __builtin_return_address(0));
return NULL;
}
@@ -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 */
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index 7cceb2c44cb9..05066674a7a0 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -85,8 +85,10 @@ unsigned long __init mmu_mapin_ram(void)
unsigned long max_size = (256<<20);
unsigned long align;
- if (__map_without_bats)
+ if (__map_without_bats) {
+ printk(KERN_DEBUG "RAM mapped without BATs\n");
return 0;
+ }
/* Set up BAT2 and if necessary BAT3 to cover RAM. */
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c
index b58baa65c4a7..fd8d08c325eb 100644
--- a/arch/powerpc/mm/tlb_64.c
+++ b/arch/powerpc/mm/tlb_64.c
@@ -120,17 +120,20 @@ void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
}
/*
- * Update the MMU hash table to correspond with a change to
- * a Linux PTE. If wrprot is true, it is permissible to
- * change the existing HPTE to read-only rather than removing it
- * (if we remove it we should clear the _PTE_HPTEFLAGS bits).
+ * A linux PTE was changed and the corresponding hash table entry
+ * neesd to be flushed. This function will either perform the flush
+ * immediately or will batch it up if the current CPU has an active
+ * batch on it.
+ *
+ * Must be called from within some kind of spinlock/non-preempt region...
*/
-void hpte_update(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, unsigned long pte, int huge)
+void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, unsigned long pte, int huge)
{
struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
- unsigned long vsid;
+ unsigned long vsid, vaddr;
unsigned int psize;
+ real_pte_t rpte;
int i;
i = batch->index;
@@ -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)
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 4ccef2d5530c..4b5f9528218c 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -12,6 +12,6 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o
-oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
+oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
oprofile-$(CONFIG_6xx) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index fbd62eacfdf4..1a7ef7e246d2 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -160,6 +160,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
case PPC_OPROFILE_POWER4:
model = &op_model_power4;
break;
+ case PPC_OPROFILE_PA6T:
+ model = &op_model_pa6t;
+ break;
#endif
#ifdef CONFIG_6xx
case PPC_OPROFILE_G4:
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index e08e1d7b3dc5..626b29f38304 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -37,6 +37,7 @@
#include <asm/system.h>
#include "../platforms/cell/interrupt.h"
+#include "../platforms/cell/cbe_regs.h"
#define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */
#define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying
@@ -130,7 +131,7 @@ static int pm_rtas_token;
static u32 reset_value[NR_PHYS_CTRS];
static int num_counters;
static int oprofile_running;
-static spinlock_t virt_cntr_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(virt_cntr_lock);
static u32 ctr_enabled;
diff --git a/arch/powerpc/oprofile/op_model_pa6t.c b/arch/powerpc/oprofile/op_model_pa6t.c
new file mode 100644
index 000000000000..e8a56b0adadc
--- /dev/null
+++ b/arch/powerpc/oprofile/op_model_pa6t.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Shashi Rao, PA Semi
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on arch/powerpc/oprofile/op_model_power4.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/percpu.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/oprofile_impl.h>
+#include <asm/reg.h>
+
+static unsigned char oprofile_running;
+
+/* mmcr values are set in pa6t_reg_setup, used in pa6t_cpu_setup */
+static u64 mmcr0_val;
+static u64 mmcr1_val;
+
+/* inited in pa6t_reg_setup */
+static u64 reset_value[OP_MAX_COUNTER];
+
+static inline u64 ctr_read(unsigned int i)
+{
+ switch (i) {
+ case 0:
+ return mfspr(SPRN_PA6T_PMC0);
+ case 1:
+ return mfspr(SPRN_PA6T_PMC1);
+ case 2:
+ return mfspr(SPRN_PA6T_PMC2);
+ case 3:
+ return mfspr(SPRN_PA6T_PMC3);
+ case 4:
+ return mfspr(SPRN_PA6T_PMC4);
+ case 5:
+ return mfspr(SPRN_PA6T_PMC5);
+ default:
+ printk(KERN_ERR "ctr_read called with bad arg %u\n", i);
+ return 0;
+ }
+}
+
+static inline void ctr_write(unsigned int i, u64 val)
+{
+ switch (i) {
+ case 0:
+ mtspr(SPRN_PA6T_PMC0, val);
+ break;
+ case 1:
+ mtspr(SPRN_PA6T_PMC1, val);
+ break;
+ case 2:
+ mtspr(SPRN_PA6T_PMC2, val);
+ break;
+ case 3:
+ mtspr(SPRN_PA6T_PMC3, val);
+ break;
+ case 4:
+ mtspr(SPRN_PA6T_PMC4, val);
+ break;
+ case 5:
+ mtspr(SPRN_PA6T_PMC5, val);
+ break;
+ default:
+ printk(KERN_ERR "ctr_write called with bad arg %u\n", i);
+ break;
+ }
+}
+
+
+/* precompute the values to stuff in the hardware registers */
+static void pa6t_reg_setup(struct op_counter_config *ctr,
+ struct op_system_config *sys,
+ int num_ctrs)
+{
+ int pmc;
+
+ /*
+ * adjust the mmcr0.en[0-5] and mmcr0.inten[0-5] values obtained from the
+ * event_mappings file by turning off the counters that the user doesn't
+ * care about
+ *
+ * setup user and kernel profiling
+ */
+ for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++)
+ if (!ctr[pmc].enabled) {
+ sys->mmcr0 &= ~(0x1UL << pmc);
+ sys->mmcr0 &= ~(0x1UL << (pmc+12));
+ pr_debug("turned off counter %u\n", pmc);
+ }
+
+ if (sys->enable_kernel)
+ sys->mmcr0 |= PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN;
+ else
+ sys->mmcr0 &= ~(PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN);
+
+ if (sys->enable_user)
+ sys->mmcr0 |= PA6T_MMCR0_PREN;
+ else
+ sys->mmcr0 &= ~PA6T_MMCR0_PREN;
+
+ /*
+ * The performance counter event settings are given in the mmcr0 and
+ * mmcr1 values passed from the user in the op_system_config
+ * structure (sys variable).
+ */
+ mmcr0_val = sys->mmcr0;
+ mmcr1_val = sys->mmcr1;
+ pr_debug("mmcr0_val inited to %016lx\n", sys->mmcr0);
+ pr_debug("mmcr1_val inited to %016lx\n", sys->mmcr1);
+
+ for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++) {
+ /* counters are 40 bit. Move to cputable at some point? */
+ reset_value[pmc] = (0x1UL << 39) - ctr[pmc].count;
+ pr_debug("reset_value for pmc%u inited to 0x%lx\n",
+ pmc, reset_value[pmc]);
+ }
+}
+
+/* configure registers on this cpu */
+static void pa6t_cpu_setup(struct op_counter_config *ctr)
+{
+ u64 mmcr0 = mmcr0_val;
+ u64 mmcr1 = mmcr1_val;
+
+ /* Default is all PMCs off */
+ mmcr0 &= ~(0x3FUL);
+ mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+ /* program selected programmable events in */
+ mtspr(SPRN_PA6T_MMCR1, mmcr1);
+
+ pr_debug("setup on cpu %d, mmcr0 %016lx\n", smp_processor_id(),
+ mfspr(SPRN_PA6T_MMCR0));
+ pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
+ mfspr(SPRN_PA6T_MMCR1));
+}
+
+static void pa6t_start(struct op_counter_config *ctr)
+{
+ int i;
+
+ /* Hold off event counting until rfid */
+ u64 mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
+
+ for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
+ if (ctr[i].enabled)
+ ctr_write(i, reset_value[i]);
+ else
+ ctr_write(i, 0UL);
+
+ mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+ oprofile_running = 1;
+
+ pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+}
+
+static void pa6t_stop(void)
+{
+ u64 mmcr0;
+
+ /* freeze counters */
+ mmcr0 = mfspr(SPRN_PA6T_MMCR0);
+ mmcr0 |= PA6T_MMCR0_FCM0;
+ mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+ oprofile_running = 0;
+
+ pr_debug("stop on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+}
+
+/* handle the perfmon overflow vector */
+static void pa6t_handle_interrupt(struct pt_regs *regs,
+ struct op_counter_config *ctr)
+{
+ unsigned long pc = mfspr(SPRN_PA6T_SIAR);
+ int is_kernel = is_kernel_addr(pc);
+ u64 val;
+ int i;
+ u64 mmcr0;
+
+ /* disable perfmon counting until rfid */
+ mmcr0 = mfspr(SPRN_PA6T_MMCR0);
+ mtspr(SPRN_PA6T_MMCR0, mmcr0 | PA6T_MMCR0_HANDDIS);
+
+ /* Record samples. We've got one global bit for whether a sample
+ * was taken, so add it for any counter that triggered overflow.
+ */
+ for (i = 0; i < cur_cpu_spec->num_pmcs; i++) {
+ val = ctr_read(i);
+ if (val & (0x1UL << 39)) { /* Overflow bit set */
+ if (oprofile_running && ctr[i].enabled) {
+ if (mmcr0 & PA6T_MMCR0_SIARLOG)
+ oprofile_add_ext_sample(pc, regs, i, is_kernel);
+ ctr_write(i, reset_value[i]);
+ } else {
+ ctr_write(i, 0UL);
+ }
+ }
+ }
+
+ /* Restore mmcr0 to a good known value since the PMI changes it */
+ mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
+ mtspr(SPRN_PA6T_MMCR0, mmcr0);
+}
+
+struct op_powerpc_model op_model_pa6t = {
+ .reg_setup = pa6t_reg_setup,
+ .cpu_setup = pa6t_cpu_setup,
+ .start = pa6t_start,
+ .stop = pa6t_stop,
+ .handle_interrupt = pa6t_handle_interrupt,
+};
diff --git a/arch/powerpc/platforms/4xx/Kconfig b/arch/powerpc/platforms/4xx/Kconfig
index 2f2a13ed7667..ded357c17414 100644
--- a/arch/powerpc/platforms/4xx/Kconfig
+++ b/arch/powerpc/platforms/4xx/Kconfig
@@ -3,278 +3,206 @@ config 4xx
depends on 40x || 44x
default y
-config WANT_EARLY_SERIAL
+config BOOKE
bool
- select SERIAL_8250
- default n
-
-menu "AMCC 4xx options"
- depends on 4xx
-
-choice
- prompt "Machine Type"
- depends on 40x
- default WALNUT
-
-config BUBINGA
- bool "Bubinga"
- select WANT_EARLY_SERIAL
- help
- This option enables support for the IBM 405EP evaluation board.
-
-config CPCI405
- bool "CPCI405"
- help
- This option enables support for the CPCI405 board.
-
-config EP405
- bool "EP405/EP405PC"
- help
- This option enables support for the EP405/EP405PC boards.
-
-config REDWOOD_5
- bool "Redwood-5"
- help
- This option enables support for the IBM STB04 evaluation board.
-
-config REDWOOD_6
- bool "Redwood-6"
- help
- This option enables support for the IBM STBx25xx evaluation board.
-
-config SYCAMORE
- bool "Sycamore"
- help
- This option enables support for the IBM PPC405GPr evaluation board.
-
-config WALNUT
- bool "Walnut"
- help
- This option enables support for the IBM PPC405GP evaluation board.
-
-config XILINX_ML300
- bool "Xilinx-ML300"
- help
- This option enables support for the Xilinx ML300 evaluation board.
-
-endchoice
-
-choice
- prompt "Machine Type"
depends on 44x
- default EBONY
-
-config BAMBOO
- bool "Bamboo"
- select WANT_EARLY_SERIAL
- help
- This option enables support for the IBM PPC440EP evaluation board.
-
-config EBONY
- bool "Ebony"
- select WANT_EARLY_SERIAL
- help
- This option enables support for the IBM PPC440GP evaluation board.
-
-config LUAN
- bool "Luan"
- select WANT_EARLY_SERIAL
- help
- This option enables support for the IBM PPC440SP evaluation board.
-
-config OCOTEA
- bool "Ocotea"
- select WANT_EARLY_SERIAL
- help
- This option enables support for the IBM PPC440GX evaluation board.
+ default y
-endchoice
+menu "AMCC 40x options"
+ depends on 40x
-config EP405PC
- bool "EP405PC Support"
- depends on EP405
+#config BUBINGA
+# bool "Bubinga"
+# depends on 40x
+# default n
+# select 405EP
+# help
+# This option enables support for the IBM 405EP evaluation board.
+
+#config CPCI405
+# bool "CPCI405"
+# depends on 40x
+# default n
+# select 405GP
+# help
+# This option enables support for the CPCI405 board.
+
+#config EP405
+# bool "EP405/EP405PC"
+# depends on 40x
+# default n
+# select 405GP
+# help
+# This option enables support for the EP405/EP405PC boards.
+
+#config EP405PC
+# bool "EP405PC Support"
+# depends on EP405
+# default y
+# help
+# This option enables support for the extra features of the EP405PC board.
+
+#config REDWOOD_5
+# bool "Redwood-5"
+# depends on 40x
+# default n
+# select STB03xxx
+# help
+# This option enables support for the IBM STB04 evaluation board.
+
+#config REDWOOD_6
+# bool "Redwood-6"
+# depends on 40x
+# default n
+# select STB03xxx
+# help
+# This option enables support for the IBM STBx25xx evaluation board.
+
+#config SYCAMORE
+# bool "Sycamore"
+# depends on 40x
+# default n
+# select 405GPR
+# help
+# This option enables support for the IBM PPC405GPr evaluation board.
+
+#config WALNUT
+# bool "Walnut"
+# depends on 40x
+# default y
+# select 405GP
+# help
+# This option enables support for the IBM PPC405GP evaluation board.
+
+#config XILINX_ML300
+# bool "Xilinx-ML300"
+# depends on 40x
+# default y
+# select VIRTEX_II_PRO
+# help
+# This option enables support for the Xilinx ML300 evaluation board.
+endmenu
-# It's often necessary to know the specific 4xx processor type.
-# Fortunately, it is impled (so far) from the board type, so we
-# don't need to ask more redundant questions.
+# 40x specific CPU modules, selected based on the board above.
config NP405H
bool
- depends on ASH
- default y
+ #depends on ASH
-config 440EP
+# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
+config 403GCX
bool
- depends on BAMBOO
- select PPC_FPU
- default y
+ #depends on OAK
+ select IBM405_ERR51
-config 440GP
+config 405GP
bool
- depends on EBONY
- default y
+ select IBM405_ERR77
+ select IBM405_ERR51
-config 440GX
+config 405EP
bool
- depends on OCOTEA
- default y
-config 440SP
+config 405GPR
bool
- depends on LUAN
- default y
-config 440
+config VIRTEX_II_PRO
bool
- depends on 440GP || 440SP || 440EP
- default y
+ select IBM405_ERR77
+ select IBM405_ERR51
-config 440A
+config STB03xxx
bool
- depends on 440GX
- default y
+ select IBM405_ERR77
+ select IBM405_ERR51
-config IBM440EP_ERR42
- bool
- depends on 440EP
- default y
+# 40x errata/workaround config symbols, selected by the CPU models above
# All 405-based cores up until the 405GPR and 405EP have this errata.
config IBM405_ERR77
bool
- depends on 40x && !403GCX && !405GPR && !405EP
- default y
# All 40x-based cores, up until the 405GPR and 405EP have this errata.
config IBM405_ERR51
bool
- depends on 40x && !405GPR && !405EP
- default y
-config BOOKE
- bool
+menu "AMCC 44x options"
depends on 44x
- default y
-
-config IBM_OCP
- bool
- depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
- default y
-config XILINX_OCP
- bool
- depends on XILINX_ML300
- default y
+#config BAMBOO
+# bool "Bamboo"
+# depends on 44x
+# default n
+# select 440EP
+# help
+# This option enables support for the IBM PPC440EP evaluation board.
-config IBM_EMAC4
- bool
- depends on 440GX || 440SP
- default y
-
-config BIOS_FIXUP
- bool
- depends on BUBINGA || EP405 || SYCAMORE || WALNUT
- default y
-
-# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
-config 403GCX
- bool
- depends on OAK
- default y
-
-config 405EP
- bool
- depends on BUBINGA
- default y
-
-config 405GP
- bool
- depends on CPCI405 || EP405 || WALNUT
- default y
-
-config 405GPR
- bool
- depends on SYCAMORE
+config EBONY
+ bool "Ebony"
+ depends on 44x
default y
+ select 440GP
+ help
+ This option enables support for the IBM PPC440GP evaluation board.
-config VIRTEX_II_PRO
- bool
- depends on XILINX_ML300
- default y
+#config LUAN
+# bool "Luan"
+# depends on 44x
+# default n
+# select 440SP
+# help
+# This option enables support for the IBM PPC440SP evaluation board.
+
+#config OCOTEA
+# bool "Ocotea"
+# depends on 44x
+# default n
+# select 440GX
+# help
+# This option enables support for the IBM PPC440GX evaluation board.
-config STB03xxx
- bool
- depends on REDWOOD_5 || REDWOOD_6
- default y
+endmenu
-config EMBEDDEDBOOT
+# 44x specific CPU modules, selected based on the board above.
+config 440EP
bool
- depends on EP405 || XILINX_ML300
- default y
+ select PPC_FPU
+ select IBM440EP_ERR42
-config IBM_OPENBIOS
+config 440GP
bool
- depends on ASH || BUBINGA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
- default y
+ select IBM_NEW_EMAC_ZMII
-config PPC4xx_DMA
- bool "PPC4xx DMA controller support"
- depends on 4xx
-
-config PPC4xx_EDMA
+config 440GX
bool
- depends on !STB03xxx && PPC4xx_DMA
- default y
-config PPC_GEN550
+config 440SP
bool
- depends on 4xx
- default y
-
-choice
- prompt "TTYS0 device and default console"
- depends on 40x
- default UART0_TTYS0
-
-config UART0_TTYS0
- bool "UART0"
-config UART0_TTYS1
- bool "UART1"
-
-endchoice
-
-config SERIAL_SICC
- bool "SICC Serial port support"
- depends on STB03xxx
-
-config UART1_DFLT_CONSOLE
+config 440A
bool
- depends on SERIAL_SICC && UART0_TTYS1
+ depends on 440GX
default y
-config SERIAL_SICC_CONSOLE
+# 44x errata/workaround config symbols, selected by the CPU models above
+config IBM440EP_ERR42
bool
- depends on SERIAL_SICC && UART0_TTYS1
- default y
-endmenu
+#config XILINX_OCP
+# bool
+# depends on XILINX_ML300
+# default y
-menu "IBM 40x options"
- depends on 40x
-
-config SERIAL_SICC
- bool "SICC Serial port"
- depends on STB03xxx
-
-config UART1_DFLT_CONSOLE
- bool
- depends on SERIAL_SICC && UART0_TTYS1
- default y
+#config BIOS_FIXUP
+# bool
+# depends on BUBINGA || EP405 || SYCAMORE || WALNUT
+# default y
-config SERIAL_SICC_CONSOLE
- bool
- depends on SERIAL_SICC && UART0_TTYS1
- default y
+#config PPC4xx_DMA
+# bool "PPC4xx DMA controller support"
+# depends on 4xx
-endmenu
+#config PPC4xx_EDMA
+# bool
+# depends on !STB03xxx && PPC4xx_DMA
+# default y
diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig
new file mode 100644
index 000000000000..bc4aa4a80a12
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/Kconfig
@@ -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
+
+
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c
index 8de034116681..a6bba97314eb 100644
--- a/arch/powerpc/platforms/52xx/efika.c
+++ b/arch/powerpc/platforms/52xx/efika.c
@@ -112,7 +112,7 @@ void __init efika_pcisetup(void)
return;
}
- bus_range = get_property(pcictrl, "bus-range", &len);
+ bus_range = of_get_property(pcictrl, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING EFIKA_PLATFORM_NAME
": Can't get bus-range for %s\n", pcictrl->full_name);
@@ -158,18 +158,17 @@ void __init efika_pcisetup(void)
static void efika_show_cpuinfo(struct seq_file *m)
{
struct device_node *root;
- const char *revision = NULL;
- const char *codegendescription = NULL;
- const char *codegenvendor = NULL;
+ const char *revision;
+ const char *codegendescription;
+ const char *codegenvendor;
root = of_find_node_by_path("/");
if (!root)
return;
- revision = get_property(root, "revision", NULL);
- codegendescription =
- get_property(root, "CODEGEN,description", NULL);
- codegenvendor = get_property(root, "CODEGEN,vendor", NULL);
+ revision = of_get_property(root, "revision", NULL);
+ codegendescription = of_get_property(root, "CODEGEN,description", NULL);
+ codegenvendor = of_get_property(root, "CODEGEN,vendor", NULL);
if (codegendescription)
seq_printf(m, "machine\t\t: %s\n", codegendescription);
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index cc3b40de21dd..8e2646ac417b 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -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");
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
index ed0cb694aea8..2dd415ff55a9 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -60,7 +60,7 @@ mpc52xx_find_ipb_freq(struct device_node *node)
of_node_get(node);
while (node) {
- p_ipb_freq = get_property(node, "bus-frequency", NULL);
+ p_ipb_freq = of_get_property(node, "bus-frequency", NULL);
if (p_ipb_freq)
break;
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
index faf161bdbc1c..34d34a26d305 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -370,7 +370,7 @@ mpc52xx_add_bridge(struct device_node *node)
return -EINVAL;
}
- bus_range = get_property(node, "bus-range", &len);
+ bus_range = of_get_property(node, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
node->full_name);
diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig
index 47d841ecf2e2..de7fce9cb6eb 100644
--- a/arch/powerpc/platforms/82xx/Kconfig
+++ b/arch/powerpc/platforms/82xx/Kconfig
@@ -1,21 +1,36 @@
-menu "Platform support"
- depends on PPC_82xx
-
choice
- prompt "Machine Type"
- default MPC82xx_ADS
+ prompt "Machine Type"
+ depends on PPC_82xx
+ default MPC82xx_ADS
config MPC82xx_ADS
- bool "Freescale MPC82xx ADS"
- select DEFAULT_UIMAGE
- select PQ2ADS
- select 8272
- select 8260
- select CPM2
- select FSL_SOC
- help
- This option enables support for the MPC8272 ADS board
+ bool "Freescale MPC82xx ADS"
+ select DEFAULT_UIMAGE
+ select PQ2ADS
+ select 8272
+ select 8260
+ select FSL_SOC
+ help
+ This option enables support for the MPC8272 ADS board
endchoice
-endmenu
+config PQ2ADS
+ bool
+ default n
+
+config 8260
+ bool
+ depends on 6xx
+ select CPM2
+ help
+ The MPC8260 is a typical embedded CPU made by Freescale. Selecting
+ this option means that you wish to build a kernel for a machine with
+ an 8260 class CPU.
+
+config 8272
+ bool
+ select 8260
+ help
+ The MPC8272 CPM has a different internal dpram setup than other CPM2
+ devices
diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c
index 74e7892cdfcf..cc9900d2e5ee 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx.c
@@ -55,17 +55,17 @@
static int __init get_freq(char *name, unsigned long *val)
{
struct device_node *cpu;
- unsigned int *fp;
+ const unsigned int *fp;
int found = 0;
/* The cpu node should have timebase and clock frequency properties */
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu) {
- fp = (unsigned int *)get_property(cpu, name, NULL);
+ fp = of_get_property(cpu, name, NULL);
if (fp) {
found = 1;
- *val = *fp++;
+ *val = *fp;
}
of_node_put(cpu);
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
index 7334c1a15b90..47cb09f08052 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -456,7 +456,7 @@ void m82xx_pci_init_irq(void)
iounmap(immap);
return;
}
- irq_map = get_property(np, "interrupt-map", &size);
+ irq_map = of_get_property(np, "interrupt-map", &size);
if ((!irq_map) || (size <= 7)) {
printk(KERN_INFO "No interrupt-map property of pci node\n");
iounmap(immap);
@@ -481,7 +481,7 @@ void m82xx_pci_init_irq(void)
}
pci_pic_node = of_node_get(np);
/* PCI interrupt controller registers: status and mask */
- regs = get_property(np, "reg", &size);
+ regs = of_get_property(np, "reg", &size);
if ((!regs) || (size <= 2)) {
printk(KERN_INFO "No reg property in pci pic node\n");
iounmap(immap);
@@ -521,20 +521,20 @@ void __init add_bridge(struct device_node *np)
struct pci_controller *hose;
struct resource r;
const int *bus_range;
- const void *ptr;
+ const uint *ptr;
memset(&r, 0, sizeof(r));
if (of_address_to_resource(np, 0, &r)) {
printk(KERN_INFO "No PCI reg property in device tree\n");
return;
}
- if (!(ptr = get_property(np, "clock-frequency", NULL))) {
+ if (!(ptr = of_get_property(np, "clock-frequency", NULL))) {
printk(KERN_INFO "No clock-frequency property in PCI node");
return;
}
- pci_clk_frq = *(uint *) ptr;
+ pci_clk_frq = *ptr;
of_node_put(np);
- bus_range = get_property(np, "bus-range", &len);
+ bus_range = of_get_property(np, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", np->full_name);
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 713b31a16ce9..19cafdf6df93 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -1,8 +1,6 @@
-menu "Platform support"
- depends on PPC_83xx
-
choice
prompt "Machine Type"
+ depends on PPC_83xx
default MPC834x_MDS
config MPC8313_RDB
@@ -18,6 +16,13 @@ config MPC832x_MDS
help
This option enables support for the MPC832x MDS evaluation board.
+config MPC832x_RDB
+ bool "Freescale MPC832x RDB"
+ select DEFAULT_UIMAGE
+ select QUICC_ENGINE
+ help
+ This option enables support for the MPC8323 RDB board.
+
config MPC834x_MDS
bool "Freescale MPC834x MDS"
select DEFAULT_UIMAGE
@@ -57,7 +62,7 @@ config PPC_MPC832x
bool
select PPC_UDBG_16550
select PPC_INDIRECT_PCI
- default y if MPC832x_MDS
+ default y if MPC832x_MDS || MPC832x_RDB
config MPC834x
bool
@@ -70,5 +75,3 @@ config PPC_MPC836x
select PPC_UDBG_16550
select PPC_INDIRECT_PCI
default y if MPC836x_MDS
-
-endmenu
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index dfc970d0df10..31a91b53f528 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -4,6 +4,7 @@
obj-y := misc.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o
+obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o
obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o
obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o
obj-$(CONFIG_MPC836x_MDS) += mpc836x_mds.o
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index 17e3a3c6d8b4..fff09f5d6edf 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -41,7 +41,6 @@
#include <asm/qe_ic.h>
#include "mpc83xx.h"
-#include "mpc832x_mds.h"
#undef DEBUG
#ifdef DEBUG
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.h b/arch/powerpc/platforms/83xx/mpc832x_mds.h
deleted file mode 100644
index a49588904f8a..000000000000
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Description:
- * MPC832x MDS board specific header.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#ifndef __MACH_MPC832x_MDS_H__
-#define __MACH_MPC832x_MDS_H__
-
-extern u8 *get_bcsr(void);
-
-#endif /* __MACH_MPC832x_MDS_H__ */
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
new file mode 100644
index 000000000000..6b71e9ffb11a
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -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
index 174ca4ef55f3..000000000000
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * arch/powerpc/platforms/83xx/mpc834x_itx.h
- *
- * MPC834X ITX common board definitions
- *
- * Maintainer: Kumar Gala <galak@kernel.crashing.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#ifndef __MACH_MPC83XX_ITX_H__
-#define __MACH_MPC83XX_ITX_H__
-
-#define PIRQA MPC83xx_IRQ_EXT4
-#define PIRQB MPC83xx_IRQ_EXT5
-#define PIRQC MPC83xx_IRQ_EXT6
-#define PIRQD MPC83xx_IRQ_EXT7
-
-#endif /* __MACH_MPC83XX_ITX_H__ */
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
index 9c3650555144..774457d09e94 100644
--- a/arch/powerpc/platforms/83xx/pci.c
+++ b/arch/powerpc/platforms/83xx/pci.c
@@ -60,7 +60,7 @@ int __init add_bridge(struct device_node *dev)
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
/* Get bus range if any */
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index e764c0aced88..629926e01e90 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -1,8 +1,6 @@
-menu "Platform support"
- depends on PPC_85xx
-
choice
prompt "Machine Type"
+ depends on PPC_85xx
default MPC8540_ADS
config MPC8540_ADS
@@ -30,6 +28,12 @@ config MPC85xx_MDS
help
This option enables support for the MPC85xx MDS board
+config MPC8544_DS
+ bool "Freescale MPC8544 DS"
+ select DEFAULT_UIMAGE
+ help
+ This option enables support for the MPC8544 DS board
+
endchoice
config MPC8540
@@ -40,33 +44,15 @@ config MPC8540
config MPC8560
bool
- select PPC_INDIRECT_PCI
+ select CPM2
default y if MPC8560_ADS
config MPC85xx
bool
select PPC_UDBG_16550
select PPC_INDIRECT_PCI
+ select PPC_INDIRECT_PCI_BE
+ select MPIC
select SERIAL_8250_SHARE_IRQ if SERIAL_8250
- default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS || MPC85xx_MDS
-
-config PPC_INDIRECT_PCI_BE
- bool
- depends on PPC_85xx
- default y
-
-config MPIC
- bool
- default y
-
-config CPM2
- bool
- depends on MPC8560
- default y
- help
- The CPM2 (Communications Processor Module) is a coprocessor on
- embedded CPUs made by Motorola. Selecting this option means that
- you wish to build a kernel for a machine with a CPM2 coprocessor
- on it.
-
-endmenu
+ default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS \
+ || MPC85xx_MDS || MPC8544_DS
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 4e63917ada9d..4e02cbb14cf7 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -5,4 +5,5 @@ obj-$(CONFIG_PPC_85xx) += misc.o pci.o
obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
+obj-$(CONFIG_MPC8544_DS) += mpc8544_ds.o
obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
diff --git a/arch/powerpc/platforms/85xx/mpc8544_ds.c b/arch/powerpc/platforms/85xx/mpc8544_ds.c
new file mode 100644
index 000000000000..2867f85e6325
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc8544_ds.c
@@ -0,0 +1,144 @@
+/*
+ * MPC8544 DS Board Setup
+ *
+ * Author Xianghua Xiao (x.xiao@freescale.com)
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/mpc85xx.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+#include <asm/i8259.h>
+
+#include <sysdev/fsl_soc.h>
+#include "mpc85xx.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+
+void __init mpc8544_ds_pic_init(void)
+{
+ struct mpic *mpic;
+ struct resource r;
+ struct device_node *np = NULL;
+#ifdef CONFIG_PPC_I8259
+ struct device_node *cascade_node = NULL;
+ int cascade_irq;
+#endif
+
+ np = of_find_node_by_type(np, "open-pic");
+
+ if (np == NULL) {
+ printk(KERN_ERR "Could not find open-pic node\n");
+ return;
+ }
+
+ if (of_address_to_resource(np, 0, &r)) {
+ printk(KERN_ERR "Failed to map mpic register space\n");
+ of_node_put(np);
+ return;
+ }
+
+ /* Alloc mpic structure and per isu has 16 INT entries. */
+ mpic = mpic_alloc(np, r.start,
+ MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+ 16, 64, " OPENPIC ");
+ BUG_ON(mpic == NULL);
+
+ /*
+ * 48 Internal Interrupts
+ */
+ mpic_assign_isu(mpic, 0, r.start + 0x10200);
+ mpic_assign_isu(mpic, 1, r.start + 0x10400);
+ mpic_assign_isu(mpic, 2, r.start + 0x10600);
+
+ /*
+ * 16 External interrupts
+ */
+ mpic_assign_isu(mpic, 3, r.start + 0x10000);
+
+ mpic_init(mpic);
+
+#ifdef CONFIG_PPC_I8259
+ /* Initialize the i8259 controller */
+ for_each_node_by_type(np, "interrupt-controller")
+ if (device_is_compatible(np, "chrp,iic")) {
+ cascade_node = np;
+ break;
+ }
+
+ if (cascade_node == NULL) {
+ printk(KERN_DEBUG "Could not find i8259 PIC\n");
+ return;
+ }
+
+ cascade_irq = irq_of_parse_and_map(cascade_node, 0);
+ if (cascade_irq == NO_IRQ) {
+ printk(KERN_ERR "Failed to map cascade interrupt\n");
+ return;
+ }
+
+ DBG("mpc8544ds: cascade mapped to irq %d\n", cascade_irq);
+
+ i8259_init(cascade_node, 0);
+ of_node_put(cascade_node);
+
+ set_irq_chained_handler(cascade_irq, mpc8544_8259_cascade);
+#endif /* CONFIG_PPC_I8259 */
+}
+
+
+/*
+ * Setup the architecture
+ */
+static void __init mpc8544_ds_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("mpc8544_ds_setup_arch()", 0);
+
+ printk("MPC8544 DS board from Freescale Semiconductor\n");
+}
+
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mpc8544_ds_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "MPC8544DS");
+}
+
+define_machine(mpc8544_ds) {
+ .name = "MPC8544 DS",
+ .probe = mpc8544_ds_probe,
+ .setup_arch = mpc8544_ds_setup_arch,
+ .init_IRQ = mpc8544_ds_pic_init,
+ .get_irq = mpic_get_irq,
+ .restart = mpc85xx_restart,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index 8ed034aeca5f..5d27621f0927 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -227,7 +227,7 @@ static void __init mpc85xx_ads_setup_arch(void)
if (cpu != 0) {
const unsigned int *fp;
- fp = get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 4232686be441..7e71636f9098 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -237,7 +237,7 @@ static void __init mpc85xx_cds_setup_arch(void)
if (cpu != 0) {
const unsigned int *fp;
- fp = get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 81144d2ae455..54db41689954 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -80,7 +80,7 @@ static void __init mpc85xx_mds_setup_arch(void)
np = of_find_node_by_type(NULL, "cpu");
if (np != NULL) {
const unsigned int *fp =
- get_property(np, "clock-frequency", NULL);
+ of_get_property(np, "clock-frequency", NULL);
if (fp != NULL)
loops_per_jiffy = *fp / HZ;
else
diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c
index 05930eeb6e7f..48f17e23d771 100644
--- a/arch/powerpc/platforms/85xx/pci.c
+++ b/arch/powerpc/platforms/85xx/pci.c
@@ -51,7 +51,7 @@ int __init add_bridge(struct device_node *dev)
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
/* Get bus range if any */
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index 0c70944d0e37..d1bcff500464 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -1,8 +1,6 @@
-menu "Platform Support"
- depends on PPC_86xx
-
choice
prompt "Machine Type"
+ depends on PPC_86xx
default MPC8641_HPCN
config MPC8641_HPCN
@@ -14,20 +12,10 @@ config MPC8641_HPCN
endchoice
-
config MPC8641
bool
select PPC_INDIRECT_PCI
+ select PPC_INDIRECT_PCI_BE
select PPC_UDBG_16550
+ select MPIC
default y if MPC8641_HPCN
-
-config MPIC
- bool
- default y
-
-config PPC_INDIRECT_PCI_BE
- bool
- depends on PPC_86xx
- default y
-
-endmenu
diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile
index 476a6eeee710..418fd8f4d268 100644
--- a/arch/powerpc/platforms/86xx/Makefile
+++ b/arch/powerpc/platforms/86xx/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_SMP) += mpc86xx_smp.o
obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o
-obj-$(CONFIG_PCI) += pci.o mpc86xx_pcie.o
+obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index f42f801cf84e..3d3d98f5bd4a 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -349,7 +349,7 @@ mpc86xx_hpcn_setup_arch(void)
if (np != 0) {
const unsigned int *fp;
- fp = get_property(np, "clock-frequency", NULL);
+ fp = of_get_property(np, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
@@ -384,7 +384,7 @@ mpc86xx_hpcn_show_cpuinfo(struct seq_file *m)
root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
seq_printf(m, "Machine\t\t: %s\n", model);
of_node_put(root);
diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
index 481e18ed5be9..8235c562661f 100644
--- a/arch/powerpc/platforms/86xx/pci.c
+++ b/arch/powerpc/platforms/86xx/pci.c
@@ -22,9 +22,9 @@
#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/prom.h>
-#include <asm/immap_86xx.h>
#include <asm/pci-bridge.h>
#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pcie.h>
#include "mpc86xx.h"
@@ -163,7 +163,7 @@ int __init add_bridge(struct device_node *dev)
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
/* Get bus range if any */
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int))
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index beea6834bb7e..39bb8c5ebe70 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -1,6 +1,3 @@
-menu "Platform support"
- depends on PPC_8xx
-
config FADS
bool
@@ -9,6 +6,7 @@ config CPM1
choice
prompt "8xx Machine Type"
+ depends on PPC_8xx
depends on 8xx
default MPC885ADS
@@ -36,38 +34,36 @@ config MPC885ADS
endchoice
menu "Freescale Ethernet driver platform-specific options"
- depends on (FS_ENET && MPC885ADS)
-
- config MPC8xx_SECOND_ETH
- bool "Second Ethernet channel"
- depends on MPC885ADS
- default y
- help
- This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
- The latter will use SCC1, for 885ADS you can select it below.
-
- choice
- prompt "Second Ethernet channel"
- depends on MPC8xx_SECOND_ETH
- default MPC8xx_SECOND_ETH_FEC2
-
- config MPC8xx_SECOND_ETH_FEC2
- bool "FEC2"
- depends on MPC885ADS
- help
- Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
- (often 2-nd UART) will not work if this is enabled.
-
- config MPC8xx_SECOND_ETH_SCC3
- bool "SCC3"
- depends on MPC885ADS
- help
- Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
- (often 1-nd UART) will not work if this is enabled.
-
- endchoice
+ depends on (FS_ENET && MPC885ADS)
-endmenu
+ config MPC8xx_SECOND_ETH
+ bool "Second Ethernet channel"
+ depends on MPC885ADS
+ default y
+ help
+ This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
+ The latter will use SCC1, for 885ADS you can select it below.
+
+ choice
+ prompt "Second Ethernet channel"
+ depends on MPC8xx_SECOND_ETH
+ default MPC8xx_SECOND_ETH_FEC2
+
+ config MPC8xx_SECOND_ETH_FEC2
+ bool "FEC2"
+ depends on MPC885ADS
+ help
+ Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
+ (often 2-nd UART) will not work if this is enabled.
+
+ config MPC8xx_SECOND_ETH_SCC3
+ bool "SCC3"
+ depends on MPC885ADS
+ help
+ Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
+ (often 1-nd UART) will not work if this is enabled.
+
+ endchoice
endmenu
@@ -98,7 +94,7 @@ config 8xx_CPU6
require workarounds for Linux (and most other OSes to work). If you
get a BUG() very early in boot, this might fix the problem. For
more details read the document entitled "MPC860 Family Device Errata
- Reference" on Motorola's website. This option also incurs a
+ Reference" on Freescale's website. This option also incurs a
performance hit.
If in doubt, say N here.
@@ -135,4 +131,3 @@ config UCODE_PATCH
depends on !NO_UCODE_PATCH
endmenu
-
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 9ed7125f0150..0901dbada350 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -85,17 +85,17 @@ init_internal_rtc(void)
static int __init get_freq(char *name, unsigned long *val)
{
struct device_node *cpu;
- unsigned int *fp;
+ const unsigned int *fp;
int found = 0;
/* The cpu node should have timebase and clock frequency properties */
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu) {
- fp = (unsigned int *)get_property(cpu, name, NULL);
+ fp = of_get_property(cpu, name, NULL);
if (fp) {
found = 1;
- *val = *fp++;
+ *val = *fp;
}
of_node_put(cpu);
@@ -262,7 +262,7 @@ void mpc8xx_show_cpuinfo(struct seq_file *m)
root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
seq_printf(m, "Machine\t\t: %s\n", model);
of_node_put(root);
diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h
index b5d19dd0619c..59bad2f9ae51 100644
--- a/arch/powerpc/platforms/8xx/mpc86xads.h
+++ b/arch/powerpc/platforms/8xx/mpc86xads.h
@@ -37,7 +37,7 @@
#define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET)
#define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver
-#define PCMCIA_MEM_ADDR (uint)0xff020000)
+#define PCMCIA_MEM_ADDR ((uint)0xff020000)
#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
/* Bits of interest in the BCSRs.
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
index ef52ce701b0e..a35315af5c53 100644
--- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
@@ -247,7 +247,7 @@ void init_smc_ioports(struct fs_uart_platform_info *data)
}
}
-int platform_device_skip(char *model, int id)
+int platform_device_skip(const char *model, int id)
{
return 0;
}
@@ -260,7 +260,7 @@ static void __init mpc86xads_setup_arch(void)
if (cpu != 0) {
const unsigned int *fp;
- fp = get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h
index 30cbebfe84c5..7c31aec284c2 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads.h
+++ b/arch/powerpc/platforms/8xx/mpc885ads.h
@@ -37,7 +37,7 @@
#define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET)
#define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver
-#define PCMCIA_MEM_ADDR (uint)0xff020000)
+#define PCMCIA_MEM_ADDR ((uint)0xff020000)
#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
/* Bits of interest in the BCSRs.
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index c5fefdf66c0a..a57b57785acd 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -322,7 +322,7 @@ void init_smc_ioports(struct fs_uart_platform_info *data)
}
}
-int platform_device_skip(char *model, int id)
+int platform_device_skip(const char *model, int id)
{
#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
const char *dev = "FEC";
@@ -346,7 +346,7 @@ static void __init mpc885ads_setup_arch(void)
if (cpu != 0) {
const unsigned int *fp;
- fp = get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
new file mode 100644
index 000000000000..51e33347c147
--- /dev/null
+++ b/arch/powerpc/platforms/Kconfig
@@ -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
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 06a85b704331..82551770917c 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -1,3 +1,26 @@
+config PPC_CELL
+ bool
+ default n
+
+config PPC_CELL_NATIVE
+ bool
+ select PPC_CELL
+ select PPC_DCR_MMIO
+ select PPC_OF_PLATFORM_PCI
+ select PPC_INDIRECT_IO
+ select PPC_NATIVE
+ select MPIC
+ default n
+
+config PPC_IBM_CELL_BLADE
+ bool "IBM Cell Blade"
+ depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_CELL_NATIVE
+ select PPC_RTAS
+ select MMIO_NVRAM
+ select PPC_UDBG_16550
+ select UDBG_RTAS_CONSOLE
+
menu "Cell Broadband Engine options"
depends on PPC_CELL
@@ -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
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c
index a3850fd1e94c..f9ac3fe3be97 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -25,9 +25,12 @@
#include <asm/hw_irq.h>
#include <asm/io.h>
+#include <asm/machdep.h>
#include <asm/processor.h>
#include <asm/prom.h>
#include <asm/time.h>
+#include <asm/pmi.h>
+#include <asm/of_platform.h>
#include "cbe_regs.h"
@@ -68,6 +71,38 @@ static u64 MIC_Slow_Next_Timer_table[] = {
* hardware specific functions
*/
+static struct of_device *pmi_dev;
+
+static int set_pmode_pmi(int cpu, unsigned int pmode)
+{
+ int ret;
+ pmi_message_t pmi_msg;
+#ifdef DEBUG
+ u64 time;
+#endif
+
+ pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
+ pmi_msg.data1 = cbe_cpu_to_node(cpu);
+ pmi_msg.data2 = pmode;
+
+#ifdef DEBUG
+ time = (u64) get_cycles();
+#endif
+
+ pmi_send_message(pmi_dev, pmi_msg);
+ ret = pmi_msg.data2;
+
+ pr_debug("PMI returned slow mode %d\n", ret);
+
+#ifdef DEBUG
+ time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */
+ time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */
+ pr_debug("had to wait %lu ns for a transition\n", time);
+#endif
+ return ret;
+}
+
+
static int get_pmode(int cpu)
{
int ret;
@@ -79,7 +114,7 @@ static int get_pmode(int cpu)
return ret;
}
-static int set_pmode(int cpu, unsigned int pmode)
+static int set_pmode_reg(int cpu, unsigned int pmode)
{
struct cbe_pmd_regs __iomem *pmd_regs;
struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -120,37 +155,71 @@ static int set_pmode(int cpu, unsigned int pmode)
return 0;
}
+static int set_pmode(int cpu, unsigned int slow_mode) {
+ if (pmi_dev)
+ return set_pmode_pmi(cpu, slow_mode);
+ else
+ return set_pmode_reg(cpu, slow_mode);
+}
+
+static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg)
+{
+ struct cpufreq_policy policy;
+ u8 cpu;
+ u8 cbe_pmode_new;
+
+ BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+
+ cpu = cbe_node_to_cpu(pmi_msg.data1);
+ cbe_pmode_new = pmi_msg.data2;
+
+ cpufreq_get_policy(&policy, cpu);
+
+ policy.max = min(policy.max, cbe_freqs[cbe_pmode_new].frequency);
+ policy.min = min(policy.min, policy.max);
+
+ pr_debug("cbe_handle_pmi: new policy.min=%d policy.max=%d\n", policy.min, policy.max);
+ cpufreq_set_policy(&policy);
+}
+
+static struct pmi_handler cbe_pmi_handler = {
+ .type = PMI_TYPE_FREQ_CHANGE,
+ .handle_pmi_message = cbe_cpufreq_handle_pmi,
+};
+
+
/*
* cpufreq functions
*/
-static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy)
+static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- u32 *max_freq;
+ const u32 *max_freqp;
+ u32 max_freq;
int i, cur_pmode;
struct device_node *cpu;
cpu = of_get_cpu_node(policy->cpu, NULL);
- if(!cpu)
+ if (!cpu)
return -ENODEV;
pr_debug("init cpufreq on CPU %d\n", policy->cpu);
- max_freq = (u32*) get_property(cpu, "clock-frequency", NULL);
+ max_freqp = of_get_property(cpu, "clock-frequency", NULL);
- if(!max_freq)
+ if (!max_freqp)
return -EINVAL;
- // we need the freq in kHz
- *max_freq /= 1000;
+ /* we need the freq in kHz */
+ max_freq = *max_freqp / 1000;
- pr_debug("max clock-frequency is at %u kHz\n", *max_freq);
+ pr_debug("max clock-frequency is at %u kHz\n", max_freq);
pr_debug("initializing frequency table\n");
- // initialize frequency table
+ /* initialize frequency table */
for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
- cbe_freqs[i].frequency = *max_freq / cbe_freqs[i].index;
+ cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index;
pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
}
@@ -167,10 +236,10 @@ static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy)
policy->cpus = cpu_sibling_map[policy->cpu];
#endif
- cpufreq_frequency_table_get_attr (cbe_freqs, policy->cpu);
+ cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
/* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
- return cpufreq_frequency_table_cpuinfo (policy, cbe_freqs);
+ return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
}
static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
@@ -202,7 +271,7 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target
freqs.new = cbe_freqs[cbe_pmode_new].frequency;
freqs.cpu = policy->cpu;
- mutex_lock (&cbe_switch_mutex);
+ mutex_lock(&cbe_switch_mutex);
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
@@ -233,11 +302,26 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
static int __init cbe_cpufreq_init(void)
{
+ struct device_node *np;
+
+ if (!machine_is(cell))
+ return -ENODEV;
+
+ np = of_find_node_by_type(NULL, "ibm,pmi");
+
+ pmi_dev = of_find_device_by_node(np);
+
+ if (pmi_dev)
+ pmi_register_handler(pmi_dev, &cbe_pmi_handler);
+
return cpufreq_register_driver(&cbe_cpufreq_driver);
}
static void __exit cbe_cpufreq_exit(void)
{
+ if (pmi_dev)
+ pmi_unregister_handler(pmi_dev, &cbe_pmi_handler);
+
cpufreq_unregister_driver(&cbe_cpufreq_driver);
}
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 9a0ee62691d5..12c9674b4b1f 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -14,6 +14,8 @@
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/ptrace.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
#include "cbe_regs.h"
@@ -27,6 +29,7 @@
static struct cbe_regs_map
{
struct device_node *cpu_node;
+ struct device_node *be_node;
struct cbe_pmd_regs __iomem *pmd_regs;
struct cbe_iic_regs __iomem *iic_regs;
struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -37,30 +40,43 @@ static int cbe_regs_map_count;
static struct cbe_thread_map
{
struct device_node *cpu_node;
+ struct device_node *be_node;
struct cbe_regs_map *regs;
+ unsigned int thread_id;
+ unsigned int cbe_id;
} cbe_thread_map[NR_CPUS];
+static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = CPU_MASK_NONE };
+static cpumask_t cbe_first_online_cpu = CPU_MASK_NONE;
+
static struct cbe_regs_map *cbe_find_map(struct device_node *np)
{
int i;
struct device_node *tmp_np;
- if (strcasecmp(np->type, "spe") == 0) {
- if (np->data == NULL) {
- /* walk up path until cpu node was found */
- tmp_np = np->parent;
- while (tmp_np != NULL && strcasecmp(tmp_np->type, "cpu") != 0)
- tmp_np = tmp_np->parent;
+ if (strcasecmp(np->type, "spe")) {
+ for (i = 0; i < cbe_regs_map_count; i++)
+ if (cbe_regs_maps[i].cpu_node == np ||
+ cbe_regs_maps[i].be_node == np)
+ return &cbe_regs_maps[i];
+ return NULL;
+ }
- np->data = cbe_find_map(tmp_np);
- }
+ if (np->data)
return np->data;
- }
- for (i = 0; i < cbe_regs_map_count; i++)
- if (cbe_regs_maps[i].cpu_node == np)
- return &cbe_regs_maps[i];
- return NULL;
+ /* walk up path until cpu or be node was found */
+ tmp_np = np;
+ do {
+ tmp_np = tmp_np->parent;
+ /* on a correct devicetree we wont get up to root */
+ BUG_ON(!tmp_np);
+ } while (strcasecmp(tmp_np->type, "cpu") &&
+ strcasecmp(tmp_np->type, "be"));
+
+ np->data = cbe_find_map(tmp_np);
+
+ return np->data;
}
struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np)
@@ -130,38 +146,105 @@ struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu)
}
EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs);
-/* FIXME
- * This is little more than a stub at the moment. It should be
- * fleshed out so that it works for both SMT and non-SMT, no
- * matter if the passed cpu is odd or even.
- * For SMT enabled, returns 0 for even-numbered cpu; otherwise 1.
- * For SMT disabled, returns 0 for all cpus.
- */
u32 cbe_get_hw_thread_id(int cpu)
{
- return (cpu & 1);
+ return cbe_thread_map[cpu].thread_id;
}
EXPORT_SYMBOL_GPL(cbe_get_hw_thread_id);
-void __init cbe_regs_init(void)
+u32 cbe_cpu_to_node(int cpu)
{
- int i;
- struct device_node *cpu;
+ return cbe_thread_map[cpu].cbe_id;
+}
+EXPORT_SYMBOL_GPL(cbe_cpu_to_node);
- /* Build local fast map of CPUs */
- for_each_possible_cpu(i)
- cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL);
+u32 cbe_node_to_cpu(int node)
+{
+ return find_first_bit( (unsigned long *) &cbe_local_mask[node], sizeof(cpumask_t));
+}
+EXPORT_SYMBOL_GPL(cbe_node_to_cpu);
- /* Find maps for each device tree CPU */
- for_each_node_by_type(cpu, "cpu") {
- struct cbe_regs_map *map = &cbe_regs_maps[cbe_regs_map_count++];
+static struct device_node *cbe_get_be_node(int cpu_id)
+{
+ struct device_node *np;
+
+ for_each_node_by_type (np, "be") {
+ int len,i;
+ const phandle *cpu_handle;
+
+ cpu_handle = of_get_property(np, "cpus", &len);
+
+ for (i=0; i<len; i++)
+ if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL))
+ return np;
+ }
+
+ return NULL;
+}
+
+void __init cbe_fill_regs_map(struct cbe_regs_map *map)
+{
+ if(map->be_node) {
+ struct device_node *be, *np;
+
+ be = map->be_node;
+
+ for_each_node_by_type(np, "pervasive")
+ if (of_get_parent(np) == be)
+ map->pmd_regs = of_iomap(np, 0);
+
+ for_each_node_by_type(np, "CBEA-Internal-Interrupt-Controller")
+ if (of_get_parent(np) == be)
+ map->iic_regs = of_iomap(np, 2);
+ for_each_node_by_type(np, "mic-tm")
+ if (of_get_parent(np) == be)
+ map->mic_tm_regs = of_iomap(np, 0);
+ } else {
+ struct device_node *cpu;
/* That hack must die die die ! */
const struct address_prop {
unsigned long address;
unsigned int len;
} __attribute__((packed)) *prop;
+ cpu = map->cpu_node;
+
+ prop = of_get_property(cpu, "pervasive", NULL);
+ if (prop != NULL)
+ map->pmd_regs = ioremap(prop->address, prop->len);
+
+ prop = of_get_property(cpu, "iic", NULL);
+ if (prop != NULL)
+ map->iic_regs = ioremap(prop->address, prop->len);
+
+ prop = of_get_property(cpu, "mic-tm", NULL);
+ if (prop != NULL)
+ map->mic_tm_regs = ioremap(prop->address, prop->len);
+ }
+}
+
+
+void __init cbe_regs_init(void)
+{
+ int i;
+ unsigned int thread_id;
+ struct device_node *cpu;
+
+ /* Build local fast map of CPUs */
+ for_each_possible_cpu(i) {
+ cbe_thread_map[i].cpu_node = of_get_cpu_node(i, &thread_id);
+ cbe_thread_map[i].be_node = cbe_get_be_node(i);
+ cbe_thread_map[i].thread_id = thread_id;
+ }
+
+ /* Find maps for each device tree CPU */
+ for_each_node_by_type(cpu, "cpu") {
+ struct cbe_regs_map *map;
+ unsigned int cbe_id;
+
+ cbe_id = cbe_regs_map_count++;
+ map = &cbe_regs_maps[cbe_id];
if (cbe_regs_map_count > MAX_CBE) {
printk(KERN_ERR "cbe_regs: More BE chips than supported"
@@ -170,22 +253,21 @@ void __init cbe_regs_init(void)
return;
}
map->cpu_node = cpu;
- for_each_possible_cpu(i)
- if (cbe_thread_map[i].cpu_node == cpu)
- cbe_thread_map[i].regs = map;
- prop = get_property(cpu, "pervasive", NULL);
- if (prop != NULL)
- map->pmd_regs = ioremap(prop->address, prop->len);
+ for_each_possible_cpu(i) {
+ struct cbe_thread_map *thread = &cbe_thread_map[i];
- prop = get_property(cpu, "iic", NULL);
- if (prop != NULL)
- map->iic_regs = ioremap(prop->address, prop->len);
+ if (thread->cpu_node == cpu) {
+ thread->regs = map;
+ thread->cbe_id = cbe_id;
+ map->be_node = thread->be_node;
+ cpu_set(i, cbe_local_mask[cbe_id]);
+ if(thread->thread_id == 0)
+ cpu_set(i, cbe_first_online_cpu);
+ }
+ }
- prop = (struct address_prop *)get_property(cpu, "mic-tm",
- NULL);
- if (prop != NULL)
- map->mic_tm_regs = ioremap(prop->address, prop->len);
+ cbe_fill_regs_map(map);
}
}
diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h
index 440a7ecc66ea..17d597144877 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.h
+++ b/arch/powerpc/platforms/cell/cbe_regs.h
@@ -255,6 +255,11 @@ struct cbe_mic_tm_regs {
extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np);
extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu);
+/* some utility functions to deal with SMT */
+extern u32 cbe_get_hw_thread_id(int cpu);
+extern u32 cbe_cpu_to_node(int cpu);
+extern u32 cbe_node_to_cpu(int node);
+
/* Init this module early */
extern void cbe_regs_init(void);
diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c
index 70e0d968d30f..f370f0fa6f4c 100644
--- a/arch/powerpc/platforms/cell/cbe_thermal.c
+++ b/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -1,6 +1,31 @@
/*
* thermal support for the cell processor
*
+ * This module adds some sysfs attributes to cpu and spu nodes.
+ * Base for measurements are the digital thermal sensors (DTS)
+ * located on the chip.
+ * The accuracy is 2 degrees, starting from 65 up to 125 degrees celsius
+ * The attributes can be found under
+ * /sys/devices/system/cpu/cpuX/thermal
+ * /sys/devices/system/spu/spuX/thermal
+ *
+ * The following attributes are added for each node:
+ * temperature:
+ * contains the current temperature measured by the DTS
+ * throttle_begin:
+ * throttling begins when temperature is greater or equal to
+ * throttle_begin. Setting this value to 125 prevents throttling.
+ * throttle_end:
+ * throttling is being ceased, if the temperature is lower than
+ * throttle_end. Due to a delay between applying throttling and
+ * a reduced temperature this value should be less than throttle_begin.
+ * A value equal to throttle_begin provides only a very little hysteresis.
+ * throttle_full_stop:
+ * If the temperatrue is greater or equal to throttle_full_stop,
+ * full throttling is applied to the cpu or spu. This value should be
+ * greater than throttle_begin and throttle_end. Setting this value to
+ * 65 prevents the unit from running code at all.
+ *
* (C) Copyright IBM Deutschland Entwicklung GmbH 2005
*
* Author: Christian Krafft <krafft@de.ibm.com>
@@ -31,6 +56,26 @@
#include "cbe_regs.h"
#include "spu_priv1_mmio.h"
+#define TEMP_MIN 65
+#define TEMP_MAX 125
+
+#define SYSDEV_PREFIX_ATTR(_prefix,_name,_mode) \
+struct sysdev_attribute attr_ ## _prefix ## _ ## _name = { \
+ .attr = { .name = __stringify(_name), .mode = _mode }, \
+ .show = _prefix ## _show_ ## _name, \
+ .store = _prefix ## _store_ ## _name, \
+};
+
+static inline u8 reg_to_temp(u8 reg_value)
+{
+ return ((reg_value & 0x3f) << 1) + TEMP_MIN;
+}
+
+static inline u8 temp_to_reg(u8 temp)
+{
+ return ((temp - TEMP_MIN) >> 1) & 0x3f;
+}
+
static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
{
struct spu *spu;
@@ -43,14 +88,14 @@ static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
/* returns the value for a given spu in a given register */
static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg)
{
- unsigned int *id;
+ const unsigned int *id;
union spe_reg value;
struct spu *spu;
/* getting the id from the reg attribute will not work on future device-tree layouts
* in future we should store the id to the spu struct and use it here */
spu = container_of(sysdev, struct spu, sysdev);
- id = (unsigned int *)get_property(spu_devnode(spu), "reg", NULL);
+ id = of_get_property(spu_devnode(spu), "reg", NULL);
value.val = in_be64(&reg->val);
return value.spe[*id];
@@ -58,20 +103,81 @@ static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iom
static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf)
{
- int value;
+ u8 value;
struct cbe_pmd_regs __iomem *pmd_regs;
pmd_regs = get_pmd_regs(sysdev);
value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1);
- /* clear all other bits */
+
+ return sprintf(buf, "%d\n", reg_to_temp(value));
+}
+
+static ssize_t show_throttle(struct cbe_pmd_regs __iomem *pmd_regs, char *buf, int pos)
+{
+ u64 value;
+
+ value = in_be64(&pmd_regs->tm_tpr.val);
+ /* access the corresponding byte */
+ value >>= pos;
value &= 0x3F;
- /* temp is stored in steps of 2 degrees */
- value *= 2;
- /* base temp is 65 degrees */
- value += 65;
- return sprintf(buf, "%d\n", (int) value);
+ return sprintf(buf, "%d\n", reg_to_temp(value));
+}
+
+static ssize_t store_throttle(struct cbe_pmd_regs __iomem *pmd_regs, const char *buf, size_t size, int pos)
+{
+ u64 reg_value;
+ int temp;
+ u64 new_value;
+ int ret;
+
+ ret = sscanf(buf, "%u", &temp);
+
+ if (ret != 1 || temp < TEMP_MIN || temp > TEMP_MAX)
+ return -EINVAL;
+
+ new_value = temp_to_reg(temp);
+
+ reg_value = in_be64(&pmd_regs->tm_tpr.val);
+
+ /* zero out bits for new value */
+ reg_value &= ~(0xffull << pos);
+ /* set bits to new value */
+ reg_value |= new_value << pos;
+
+ out_be64(&pmd_regs->tm_tpr.val, reg_value);
+ return size;
+}
+
+static ssize_t spu_show_throttle_end(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(get_pmd_regs(sysdev), buf, 0);
+}
+
+static ssize_t spu_show_throttle_begin(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(get_pmd_regs(sysdev), buf, 8);
+}
+
+static ssize_t spu_show_throttle_full_stop(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(get_pmd_regs(sysdev), buf, 16);
+}
+
+static ssize_t spu_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(get_pmd_regs(sysdev), buf, size, 0);
+}
+
+static ssize_t spu_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(get_pmd_regs(sysdev), buf, size, 8);
+}
+
+static ssize_t spu_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(get_pmd_regs(sysdev), buf, size, 16);
}
static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
@@ -82,16 +188,9 @@ static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
value = in_be64(&pmd_regs->ts_ctsr2);
- /* access the corresponding byte */
- value >>= pos;
- /* clear all other bits */
- value &= 0x3F;
- /* temp is stored in steps of 2 degrees */
- value *= 2;
- /* base temp is 65 degrees */
- value += 65;
+ value = (value >> pos) & 0x3f;
- return sprintf(buf, "%d\n", (int) value);
+ return sprintf(buf, "%d\n", reg_to_temp(value));
}
@@ -108,13 +207,52 @@ static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf)
return ppe_show_temp(sysdev, buf, 0);
}
+static ssize_t ppe_show_throttle_end(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 32);
+}
+
+static ssize_t ppe_show_throttle_begin(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 40);
+}
+
+static ssize_t ppe_show_throttle_full_stop(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 48);
+}
+
+static ssize_t ppe_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 32);
+}
+
+static ssize_t ppe_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 40);
+}
+
+static ssize_t ppe_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 48);
+}
+
+
static struct sysdev_attribute attr_spu_temperature = {
.attr = {.name = "temperature", .mode = 0400 },
.show = spu_show_temp,
};
+static SYSDEV_PREFIX_ATTR(spu, throttle_end, 0600);
+static SYSDEV_PREFIX_ATTR(spu, throttle_begin, 0600);
+static SYSDEV_PREFIX_ATTR(spu, throttle_full_stop, 0600);
+
+
static struct attribute *spu_attributes[] = {
&attr_spu_temperature.attr,
+ &attr_spu_throttle_end.attr,
+ &attr_spu_throttle_begin.attr,
+ &attr_spu_throttle_full_stop.attr,
NULL,
};
@@ -133,9 +271,16 @@ static struct sysdev_attribute attr_ppe_temperature1 = {
.show = ppe_show_temp1,
};
+static SYSDEV_PREFIX_ATTR(ppe, throttle_end, 0600);
+static SYSDEV_PREFIX_ATTR(ppe, throttle_begin, 0600);
+static SYSDEV_PREFIX_ATTR(ppe, throttle_full_stop, 0600);
+
static struct attribute *ppe_attributes[] = {
&attr_ppe_temperature0.attr,
&attr_ppe_temperature1.attr,
+ &attr_ppe_throttle_end.attr,
+ &attr_ppe_throttle_begin.attr,
+ &attr_ppe_throttle_full_stop.attr,
NULL,
};
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 6666d037eb44..4fc4e92775d0 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -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);
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c
index 7c73128305ec..d68d920eb2c4 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/platforms/cell/io-workarounds.c
@@ -318,7 +318,7 @@ static int __init spider_pci_workaround_init(void)
*/
list_for_each_entry(phb, &hose_list, list_node) {
struct device_node *np = phb->arch_data;
- const char *model = get_property(np, "model", NULL);
+ const char *model = of_get_property(np, "model", NULL);
/* If no model property or name isn't exactly "pci", skip */
if (model == NULL || strcmp(np->name, "pci"))
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 67d617b60a23..760caa76841a 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -291,9 +291,9 @@ static int cell_iommu_find_ioc(int nid, unsigned long *base)
const unsigned int *nidp;
const unsigned long *tmp;
- nidp = get_property(np, "node-id", NULL);
+ nidp = of_get_property(np, "node-id", NULL);
if (nidp && *nidp == nid) {
- tmp = get_property(np, "ioc-translation", NULL);
+ tmp = of_get_property(np, "ioc-translation", NULL);
if (tmp) {
*base = *tmp;
of_node_put(np);
@@ -430,7 +430,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
struct iommu_window *window;
const unsigned int *ioid;
- ioid = get_property(np, "ioid", NULL);
+ ioid = of_get_property(np, "ioid", NULL);
if (ioid == NULL)
printk(KERN_WARNING "iommu: missing ioid for %s using 0\n",
np->full_name);
@@ -496,7 +496,7 @@ static void cell_dma_dev_setup(struct device *dev)
struct dev_archdata *archdata = &dev->archdata;
/* If we run without iommu, no need to do anything */
- if (pci_dma_ops == &dma_direct_ops)
+ if (get_pci_dma_ops() == &dma_direct_ops)
return;
/* Current implementation uses the first window available in that
@@ -530,7 +530,7 @@ static int cell_of_bus_notify(struct notifier_block *nb, unsigned long action,
return 0;
/* We use the PCI DMA ops */
- dev->archdata.dma_ops = pci_dma_ops;
+ dev->archdata.dma_ops = get_pci_dma_ops();
cell_dma_dev_setup(dev);
@@ -549,7 +549,7 @@ static int __init cell_iommu_get_window(struct device_node *np,
unsigned long index;
/* Use ibm,dma-window if available, else, hard code ! */
- dma_window = get_property(np, "ibm,dma-window", NULL);
+ dma_window = of_get_property(np, "ibm,dma-window", NULL);
if (dma_window == NULL) {
*base = 0;
*size = 0x80000000u;
@@ -646,7 +646,7 @@ static int __init cell_iommu_init_disabled(void)
unsigned long base = 0, size;
/* When no iommu is present, we use direct DMA ops */
- pci_dma_ops = &dma_direct_ops;
+ set_pci_dma_ops(&dma_direct_ops);
/* First make sure all IOC translation is turned off */
cell_disable_iommus();
@@ -734,7 +734,7 @@ static int __init cell_iommu_init(void)
}
/* Setup default PCI iommu ops */
- pci_dma_ops = &dma_iommu_ops;
+ set_pci_dma_ops(&dma_iommu_ops);
bail:
/* Register callbacks on OF platform device addition/removal
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
index 0984c7071695..3961a085b432 100644
--- a/arch/powerpc/platforms/cell/ras.c
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -3,11 +3,13 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/smp.h>
+#include <linux/reboot.h>
#include <asm/reg.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/machdep.h>
+#include <asm/rtas.h>
#include "ras.h"
#include "cbe_regs.h"
@@ -82,6 +84,164 @@ static int cbe_machine_check_handler(struct pt_regs *regs)
return 0;
}
+struct ptcal_area {
+ struct list_head list;
+ int nid;
+ int order;
+ struct page *pages;
+};
+
+static LIST_HEAD(ptcal_list);
+
+static int ptcal_start_tok, ptcal_stop_tok;
+
+static int __init cbe_ptcal_enable_on_node(int nid, int order)
+{
+ struct ptcal_area *area;
+ int ret = -ENOMEM;
+ unsigned long addr;
+
+#ifdef CONFIG_CRASH_DUMP
+ rtas_call(ptcal_stop_tok, 1, 1, NULL, nid);
+#endif
+
+ area = kmalloc(sizeof(*area), GFP_KERNEL);
+ if (!area)
+ goto out_err;
+
+ area->nid = nid;
+ area->order = order;
+ area->pages = alloc_pages_node(area->nid, GFP_KERNEL, area->order);
+
+ if (!area->pages)
+ goto out_free_area;
+
+ addr = __pa(page_address(area->pages));
+
+ ret = -EIO;
+ if (rtas_call(ptcal_start_tok, 3, 1, NULL, area->nid,
+ (unsigned int)(addr >> 32),
+ (unsigned int)(addr & 0xffffffff))) {
+ printk(KERN_ERR "%s: error enabling PTCAL on node %d!\n",
+ __FUNCTION__, nid);
+ goto out_free_pages;
+ }
+
+ list_add(&area->list, &ptcal_list);
+
+ return 0;
+
+out_free_pages:
+ __free_pages(area->pages, area->order);
+out_free_area:
+ kfree(area);
+out_err:
+ return ret;
+}
+
+static int __init cbe_ptcal_enable(void)
+{
+ const u32 *size;
+ struct device_node *np;
+ int order, found_mic = 0;
+
+ np = of_find_node_by_path("/rtas");
+ if (!np)
+ return -ENODEV;
+
+ size = of_get_property(np, "ibm,cbe-ptcal-size", NULL);
+ if (!size)
+ return -ENODEV;
+
+ pr_debug("%s: enabling PTCAL, size = 0x%x\n", __FUNCTION__, *size);
+ order = get_order(*size);
+ of_node_put(np);
+
+ /* support for malta device trees, with be@/mic@ nodes */
+ for_each_node_by_type(np, "mic-tm") {
+ cbe_ptcal_enable_on_node(of_node_to_nid(np), order);
+ found_mic = 1;
+ }
+
+ if (found_mic)
+ return 0;
+
+ /* support for older device tree - use cpu nodes */
+ for_each_node_by_type(np, "cpu") {
+ const u32 *nid = of_get_property(np, "node-id", NULL);
+ if (!nid) {
+ printk(KERN_ERR "%s: node %s is missing node-id?\n",
+ __FUNCTION__, np->full_name);
+ continue;
+ }
+ cbe_ptcal_enable_on_node(*nid, order);
+ found_mic = 1;
+ }
+
+ return found_mic ? 0 : -ENODEV;
+}
+
+static int cbe_ptcal_disable(void)
+{
+ struct ptcal_area *area, *tmp;
+ int ret = 0;
+
+ pr_debug("%s: disabling PTCAL\n", __FUNCTION__);
+
+ list_for_each_entry_safe(area, tmp, &ptcal_list, list) {
+ /* disable ptcal on this node */
+ if (rtas_call(ptcal_stop_tok, 1, 1, NULL, area->nid)) {
+ printk(KERN_ERR "%s: error disabling PTCAL "
+ "on node %d!\n", __FUNCTION__,
+ area->nid);
+ ret = -EIO;
+ continue;
+ }
+
+ /* ensure we can access the PTCAL area */
+ memset(page_address(area->pages), 0,
+ 1 << (area->order + PAGE_SHIFT));
+
+ /* clean up */
+ list_del(&area->list);
+ __free_pages(area->pages, area->order);
+ kfree(area);
+ }
+
+ return ret;
+}
+
+static int cbe_ptcal_notify_reboot(struct notifier_block *nb,
+ unsigned long code, void *data)
+{
+ return cbe_ptcal_disable();
+}
+
+static struct notifier_block cbe_ptcal_reboot_notifier = {
+ .notifier_call = cbe_ptcal_notify_reboot
+};
+
+int __init cbe_ptcal_init(void)
+{
+ int ret;
+ ptcal_start_tok = rtas_token("ibm,cbe-start-ptcal");
+ ptcal_stop_tok = rtas_token("ibm,cbe-stop-ptcal");
+
+ if (ptcal_start_tok == RTAS_UNKNOWN_SERVICE
+ || ptcal_stop_tok == RTAS_UNKNOWN_SERVICE)
+ return -ENODEV;
+
+ ret = register_reboot_notifier(&cbe_ptcal_reboot_notifier);
+ if (ret) {
+ printk(KERN_ERR "Can't disable PTCAL, so not enabling\n");
+ return ret;
+ }
+
+ return cbe_ptcal_enable();
+}
+
+arch_initcall(cbe_ptcal_init);
+
void __init cbe_ras_init(void)
{
unsigned long hid0;
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 36989c2eee66..54b96183cb64 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -71,7 +71,7 @@ static void cell_show_cpuinfo(struct seq_file *m)
root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
seq_printf(m, "machine\t\t: CHRP %s\n", model);
of_node_put(root);
}
@@ -190,15 +190,6 @@ static int __init cell_probe(void)
return 1;
}
-/*
- * Cell has no legacy IO; anything calling this function has to
- * fail or bad things will happen
- */
-static int cell_check_legacy_ioport(unsigned int baseport)
-{
- return -ENODEV;
-}
-
define_machine(cell) {
.name = "Cell",
.probe = cell_probe,
@@ -211,7 +202,6 @@ define_machine(cell) {
.get_rtc_time = rtas_get_rtc_time,
.set_rtc_time = rtas_set_rtc_time,
.calibrate_decr = generic_calibrate_decr,
- .check_legacy_ioport = cell_check_legacy_ioport,
.progress = cell_progress,
.init_IRQ = cell_init_irq,
.pci_setup_phb = rtas_setup_phb,
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 21a9ebd4978e..fb1f15797bbb 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -254,25 +254,25 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
}
/* Now do the horrible hacks */
- tmp = get_property(pic->of_node, "#interrupt-cells", NULL);
+ tmp = of_get_property(pic->of_node, "#interrupt-cells", NULL);
if (tmp == NULL)
return NO_IRQ;
intsize = *tmp;
- imap = get_property(pic->of_node, "interrupt-map", &imaplen);
+ imap = of_get_property(pic->of_node, "interrupt-map", &imaplen);
if (imap == NULL || imaplen < (intsize + 1))
return NO_IRQ;
iic = of_find_node_by_phandle(imap[intsize]);
if (iic == NULL)
return NO_IRQ;
imap += intsize + 1;
- tmp = get_property(iic, "#interrupt-cells", NULL);
+ tmp = of_get_property(iic, "#interrupt-cells", NULL);
if (tmp == NULL)
return NO_IRQ;
intsize = *tmp;
/* Assume unit is last entry of interrupt specifier */
unit = imap[intsize - 1];
/* Ok, we have a unit, now let's try to get the node */
- tmp = get_property(iic, "ibm,interrupt-server-ranges", NULL);
+ tmp = of_get_property(iic, "ibm,interrupt-server-ranges", NULL);
if (tmp == NULL) {
of_node_put(iic);
return NO_IRQ;
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index eba7a2641dce..fec51525252e 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -36,12 +36,14 @@
#include <asm/xmon.h>
const struct spu_management_ops *spu_management_ops;
+EXPORT_SYMBOL_GPL(spu_management_ops);
+
const struct spu_priv1_ops *spu_priv1_ops;
static struct list_head spu_list[MAX_NUMNODES];
static LIST_HEAD(spu_full_list);
static DEFINE_MUTEX(spu_mutex);
-static spinlock_t spu_list_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(spu_list_lock);
EXPORT_SYMBOL_GPL(spu_priv1_ops);
@@ -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);
diff --git a/arch/powerpc/platforms/cell/spu_coredump.c b/arch/powerpc/platforms/cell/spu_coredump.c
index 6915b418ee73..4fd37ff1e210 100644
--- a/arch/powerpc/platforms/cell/spu_coredump.c
+++ b/arch/powerpc/platforms/cell/spu_coredump.c
@@ -26,19 +26,18 @@
#include <asm/spu.h>
-static struct spu_coredump_calls spu_coredump_calls;
+static struct spu_coredump_calls *spu_coredump_calls;
static DEFINE_MUTEX(spu_coredump_mutex);
int arch_notes_size(void)
{
long ret;
- struct module *owner = spu_coredump_calls.owner;
ret = -ENOSYS;
mutex_lock(&spu_coredump_mutex);
- if (owner && try_module_get(owner)) {
- ret = spu_coredump_calls.arch_notes_size();
- module_put(owner);
+ if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) {
+ ret = spu_coredump_calls->arch_notes_size();
+ module_put(spu_coredump_calls->owner);
}
mutex_unlock(&spu_coredump_mutex);
return ret;
@@ -46,36 +45,35 @@ int arch_notes_size(void)
void arch_write_notes(struct file *file)
{
- struct module *owner = spu_coredump_calls.owner;
-
mutex_lock(&spu_coredump_mutex);
- if (owner && try_module_get(owner)) {
- spu_coredump_calls.arch_write_notes(file);
- module_put(owner);
+ if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) {
+ spu_coredump_calls->arch_write_notes(file);
+ module_put(spu_coredump_calls->owner);
}
mutex_unlock(&spu_coredump_mutex);
}
int register_arch_coredump_calls(struct spu_coredump_calls *calls)
{
- if (spu_coredump_calls.owner)
- return -EBUSY;
+ int ret = 0;
+
mutex_lock(&spu_coredump_mutex);
- spu_coredump_calls.arch_notes_size = calls->arch_notes_size;
- spu_coredump_calls.arch_write_notes = calls->arch_write_notes;
- spu_coredump_calls.owner = calls->owner;
+ if (spu_coredump_calls)
+ ret = -EBUSY;
+ else
+ spu_coredump_calls = calls;
mutex_unlock(&spu_coredump_mutex);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(register_arch_coredump_calls);
void unregister_arch_coredump_calls(struct spu_coredump_calls *calls)
{
- BUG_ON(spu_coredump_calls.owner != calls->owner);
+ BUG_ON(spu_coredump_calls != calls);
mutex_lock(&spu_coredump_mutex);
- spu_coredump_calls.owner = NULL;
+ spu_coredump_calls = NULL;
mutex_unlock(&spu_coredump_mutex);
}
EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls);
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c
index e34599f53d28..1d4562ae463d 100644
--- a/arch/powerpc/platforms/cell/spu_manage.c
+++ b/arch/powerpc/platforms/cell/spu_manage.c
@@ -48,11 +48,11 @@ static u64 __init find_spu_unit_number(struct device_node *spe)
{
const unsigned int *prop;
int proplen;
- prop = get_property(spe, "unit-id", &proplen);
+ prop = of_get_property(spe, "unit-id", &proplen);
if (proplen == 4)
return (u64)*prop;
- prop = get_property(spe, "reg", &proplen);
+ prop = of_get_property(spe, "reg", &proplen);
if (proplen == 4)
return (u64)*prop;
@@ -76,12 +76,12 @@ static int __init spu_map_interrupts_old(struct spu *spu,
int nid;
/* Get the interrupt source unit from the device-tree */
- tmp = get_property(np, "isrc", NULL);
+ tmp = of_get_property(np, "isrc", NULL);
if (!tmp)
return -ENODEV;
isrc = tmp[0];
- tmp = get_property(np->parent->parent, "node-id", NULL);
+ tmp = of_get_property(np->parent->parent, "node-id", NULL);
if (!tmp) {
printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__);
nid = spu->node;
@@ -110,7 +110,7 @@ static void __iomem * __init spu_map_prop_old(struct spu *spu,
} __attribute__((packed)) *prop;
int proplen;
- prop = get_property(n, name, &proplen);
+ prop = of_get_property(n, name, &proplen);
if (prop == NULL || proplen != sizeof (struct address_prop))
return NULL;
@@ -124,11 +124,11 @@ static int __init spu_map_device_old(struct spu *spu)
int ret;
ret = -ENODEV;
- spu->name = get_property(node, "name", NULL);
+ spu->name = of_get_property(node, "name", NULL);
if (!spu->name)
goto out;
- prop = get_property(node, "local-store", NULL);
+ prop = of_get_property(node, "local-store", NULL);
if (!prop)
goto out;
spu->local_store_phys = *(unsigned long *)prop;
@@ -139,7 +139,7 @@ static int __init spu_map_device_old(struct spu *spu)
if (!spu->local_store)
goto out;
- prop = get_property(node, "problem", NULL);
+ prop = of_get_property(node, "problem", NULL);
if (!prop)
goto out_unmap;
spu->problem_phys = *(unsigned long *)prop;
@@ -226,7 +226,7 @@ static int __init spu_map_device(struct spu *spu)
struct device_node *np = spu->devnode;
int ret = -ENODEV;
- spu->name = get_property(np, "name", NULL);
+ spu->name = of_get_property(np, "name", NULL);
if (!spu->name)
goto out;
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
index 472217d19faf..2cd89c11af5a 100644
--- a/arch/powerpc/platforms/cell/spufs/Makefile
+++ b/arch/powerpc/platforms/cell/spufs/Makefile
@@ -1,4 +1,4 @@
-obj-y += switch.o
+obj-y += switch.o fault.o
obj-$(CONFIG_SPU_FS) += spufs.o
spufs-y += inode.o file.o context.o syscalls.o coredump.o
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
index 1898f0d3a8b8..3322528fa6eb 100644
--- a/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -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,
};
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 04ad2e364e97..a87d9ca3dba2 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -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);
}
@@ -119,46 +122,6 @@ void spu_unmap_mappings(struct spu_context *ctx)
}
/**
- * spu_acquire_exclusive - lock spu contex and protect against userspace access
- * @ctx: spu contex to lock
- *
- * Note:
- * Returns 0 and with the context locked on success
- * Returns negative error and with the context _unlocked_ on failure.
- */
-int spu_acquire_exclusive(struct spu_context *ctx)
-{
- int ret = -EINVAL;
-
- spu_acquire(ctx);
- /*
- * Context is about to be freed, so we can't acquire it anymore.
- */
- if (!ctx->owner)
- goto out_unlock;
-
- if (ctx->state == SPU_STATE_SAVED) {
- ret = spu_activate(ctx, 0);
- if (ret)
- goto out_unlock;
- } else {
- /*
- * We need to exclude userspace access to the context.
- *
- * To protect against memory access we invalidate all ptes
- * and make sure the pagefault handlers block on the mutex.
- */
- spu_unmap_mappings(ctx);
- }
-
- return 0;
-
- out_unlock:
- spu_release(ctx);
- return ret;
-}
-
-/**
* spu_acquire_runnable - lock spu contex and make sure it is in runnable state
* @ctx: spu contex to lock
*
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 725e19561159..5d9ad5a0307b 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -169,12 +169,12 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
struct spu_context *ctx;
loff_t pos = 0;
int sz, dfd, rc, total = 0;
- const int bufsz = 4096;
+ const int bufsz = PAGE_SIZE;
char *name;
char fullname[80], *buf;
struct elf_note en;
- buf = kmalloc(bufsz, GFP_KERNEL);
+ buf = (void *)get_zeroed_page(GFP_KERNEL);
if (!buf)
return;
@@ -187,9 +187,8 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
sz = spufs_coredump_read[i].size;
ctx = ctx_info->ctx;
- if (!ctx) {
- return;
- }
+ if (!ctx)
+ goto out;
sprintf(fullname, "SPU/%d/%s", dfd, name);
en.n_namesz = strlen(fullname) + 1;
@@ -197,23 +196,25 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
en.n_type = NT_SPU;
if (!spufs_dump_write(file, &en, sizeof(en)))
- return;
+ goto out;
if (!spufs_dump_write(file, fullname, en.n_namesz))
- return;
+ goto out;
if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4)))
- return;
+ goto out;
do {
rc = do_coredump_read(i, ctx, buf, bufsz, &pos);
if (rc > 0) {
if (!spufs_dump_write(file, buf, rc))
- return;
+ goto out;
total += rc;
}
} while (rc == bufsz && total < sz);
spufs_dump_seek(file, roundup((unsigned long)file->f_pos
- total + sz, 4));
+out:
+ free_page((unsigned long)buf);
}
static void spufs_arch_write_notes(struct file *file)
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
new file mode 100644
index 000000000000..0f75c07e29d8
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/fault.c
@@ -0,0 +1,211 @@
+/*
+ * Low-level SPU handling
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+
+#include "spufs.h"
+
+/*
+ * This ought to be kept in sync with the powerpc specific do_page_fault
+ * function. Currently, there are a few corner cases that we haven't had
+ * to handle fortunately.
+ */
+static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr)
+{
+ struct vm_area_struct *vma;
+ unsigned long is_write;
+ int ret;
+
+#if 0
+ if (!IS_VALID_EA(ea)) {
+ return -EFAULT;
+ }
+#endif /* XXX */
+ if (mm == NULL) {
+ return -EFAULT;
+ }
+ if (mm->pgd == NULL) {
+ return -EFAULT;
+ }
+
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, ea);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= ea)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (expand_stack(vma, ea))
+ goto bad_area;
+good_area:
+ is_write = dsisr & MFC_DSISR_ACCESS_PUT;
+ if (is_write) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ } else {
+ if (dsisr & MFC_DSISR_ACCESS_DENIED)
+ goto bad_area;
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto bad_area;
+ }
+ ret = 0;
+ switch (handle_mm_fault(mm, vma, ea, is_write)) {
+ case VM_FAULT_MINOR:
+ current->min_flt++;
+ break;
+ case VM_FAULT_MAJOR:
+ current->maj_flt++;
+ break;
+ case VM_FAULT_SIGBUS:
+ ret = -EFAULT;
+ goto bad_area;
+ case VM_FAULT_OOM:
+ ret = -ENOMEM;
+ goto bad_area;
+ default:
+ BUG();
+ }
+ up_read(&mm->mmap_sem);
+ return ret;
+
+bad_area:
+ up_read(&mm->mmap_sem);
+ return -EFAULT;
+}
+
+static void spufs_handle_dma_error(struct spu_context *ctx,
+ unsigned long ea, int type)
+{
+ if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
+ ctx->event_return |= type;
+ wake_up_all(&ctx->stop_wq);
+ } else {
+ siginfo_t info;
+ memset(&info, 0, sizeof(info));
+
+ switch (type) {
+ case SPE_EVENT_INVALID_DMA:
+ info.si_signo = SIGBUS;
+ info.si_code = BUS_OBJERR;
+ break;
+ case SPE_EVENT_SPE_DATA_STORAGE:
+ info.si_signo = SIGBUS;
+ info.si_addr = (void __user *)ea;
+ info.si_code = BUS_ADRERR;
+ break;
+ case SPE_EVENT_DMA_ALIGNMENT:
+ info.si_signo = SIGBUS;
+ /* DAR isn't set for an alignment fault :( */
+ info.si_code = BUS_ADRALN;
+ break;
+ case SPE_EVENT_SPE_ERROR:
+ info.si_signo = SIGILL;
+ info.si_addr = (void __user *)(unsigned long)
+ ctx->ops->npc_read(ctx) - 4;
+ info.si_code = ILL_ILLOPC;
+ break;
+ }
+ if (info.si_signo)
+ force_sig_info(info.si_signo, &info, current);
+ }
+}
+
+void spufs_dma_callback(struct spu *spu, int type)
+{
+ spufs_handle_dma_error(spu->ctx, spu->dar, type);
+}
+EXPORT_SYMBOL_GPL(spufs_dma_callback);
+
+/*
+ * bottom half handler for page faults, we can't do this from
+ * interrupt context, since we might need to sleep.
+ * we also need to give up the mutex so we can get scheduled
+ * out while waiting for the backing store.
+ *
+ * TODO: try calling hash_page from the interrupt handler first
+ * in order to speed up the easy case.
+ */
+int spufs_handle_class1(struct spu_context *ctx)
+{
+ u64 ea, dsisr, access;
+ unsigned long flags;
+ int ret;
+
+ /*
+ * dar and dsisr get passed from the registers
+ * to the spu_context, to this function, but not
+ * back to the spu if it gets scheduled again.
+ *
+ * if we don't handle the fault for a saved context
+ * in time, we can still expect to get the same fault
+ * the immediately after the context restore.
+ */
+ if (ctx->state == SPU_STATE_RUNNABLE) {
+ ea = ctx->spu->dar;
+ dsisr = ctx->spu->dsisr;
+ ctx->spu->dar= ctx->spu->dsisr = 0;
+ } else {
+ ea = ctx->csa.priv1.mfc_dar_RW;
+ dsisr = ctx->csa.priv1.mfc_dsisr_RW;
+ ctx->csa.priv1.mfc_dar_RW = 0;
+ ctx->csa.priv1.mfc_dsisr_RW = 0;
+ }
+
+ if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
+ return 0;
+
+ pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea,
+ dsisr, ctx->state);
+
+ /* we must not hold the lock when entering spu_handle_mm_fault */
+ spu_release(ctx);
+
+ access = (_PAGE_PRESENT | _PAGE_USER);
+ access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
+ local_irq_save(flags);
+ ret = hash_page(ea, access, 0x300);
+ local_irq_restore(flags);
+
+ /* hashing failed, so try the actual fault handler */
+ if (ret)
+ ret = spu_handle_mm_fault(current->mm, ea, dsisr);
+
+ spu_acquire(ctx);
+ /*
+ * If we handled the fault successfully and are in runnable
+ * state, restart the DMA.
+ * In case of unhandled error report the problem to user space.
+ */
+ if (!ret) {
+ if (ctx->spu)
+ ctx->ops->restart_dma(ctx);
+ } else
+ spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(spufs_handle_class1);
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 505266a568d4..d010b2464a98 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -44,9 +44,25 @@ spufs_mem_open(struct inode *inode, struct file *file)
{
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->local_store = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->local_store = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
+static int
+spufs_mem_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->local_store = NULL;
+ spin_unlock(&ctx->mapping_lock);
return 0;
}
@@ -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,
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
index ae42e03b8c86..428875c5e4ec 100644
--- a/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -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,
};
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 8079983ef94f..13e4f70ec8c0 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -36,6 +36,7 @@
#include <asm/prom.h>
#include <asm/semaphore.h>
#include <asm/spu.h>
+#include <asm/spu_priv1.h>
#include <asm/uaccess.h>
#include "spufs.h"
@@ -54,6 +55,7 @@ spufs_alloc_inode(struct super_block *sb)
ei->i_gang = NULL;
ei->i_ctx = NULL;
+ ei->i_openers = 0;
return &ei->vfs_inode;
}
@@ -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);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index f95a611ca362..57626600b1a4 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -18,27 +18,6 @@ void spufs_stop_callback(struct spu *spu)
wake_up_all(&ctx->stop_wq);
}
-void spufs_dma_callback(struct spu *spu, int type)
-{
- struct spu_context *ctx = spu->ctx;
-
- if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
- ctx->event_return |= type;
- wake_up_all(&ctx->stop_wq);
- } else {
- switch (type) {
- case SPE_EVENT_DMA_ALIGNMENT:
- case SPE_EVENT_SPE_DATA_STORAGE:
- case SPE_EVENT_INVALID_DMA:
- force_sig(SIGBUS, /* info, */ current);
- break;
- case SPE_EVENT_SPE_ERROR:
- force_sig(SIGILL, /* info */ current);
- break;
- }
- }
-}
-
static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
{
struct spu *spu;
@@ -63,13 +42,18 @@ static int spu_setup_isolated(struct spu_context *ctx)
const u32 status_loading = SPU_STATUS_RUNNING
| SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS;
+ ret = -ENODEV;
if (!isolated_loader)
- return -ENODEV;
-
- ret = spu_acquire_exclusive(ctx);
- if (ret)
goto out;
+ /*
+ * We need to exclude userspace access to the context.
+ *
+ * To protect against memory access we invalidate all ptes
+ * and make sure the pagefault handlers block on the mutex.
+ */
+ spu_unmap_mappings(ctx);
+
mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
/* purge the MFC DMA queue to ensure no spurious accesses before we
@@ -82,7 +66,7 @@ static int spu_setup_isolated(struct spu_context *ctx)
printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n",
__FUNCTION__);
ret = -EIO;
- goto out_unlock;
+ goto out;
}
cond_resched();
}
@@ -119,12 +103,15 @@ static int spu_setup_isolated(struct spu_context *ctx)
pr_debug("%s: isolated LOAD failed\n", __FUNCTION__);
ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
ret = -EACCES;
+ goto out_drop_priv;
+ }
- } else if (!(status & SPU_STATUS_ISOLATED_STATE)) {
+ if (!(status & SPU_STATUS_ISOLATED_STATE)) {
/* This isn't allowed by the CBEA, but check anyway */
pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__);
ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP);
ret = -EINVAL;
+ goto out_drop_priv;
}
out_drop_priv:
@@ -132,30 +119,19 @@ out_drop_priv:
sr1 |= MFC_STATE1_PROBLEM_STATE_MASK;
spu_mfc_sr1_set(ctx->spu, sr1);
-out_unlock:
- spu_release(ctx);
out:
return ret;
}
-static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
+static int spu_run_init(struct spu_context *ctx, u32 * npc)
{
- int ret;
- unsigned long runcntl = SPU_RUNCNTL_RUNNABLE;
-
- ret = spu_acquire_runnable(ctx, 0);
- if (ret)
- return ret;
-
if (ctx->flags & SPU_CREATE_ISOLATE) {
+ unsigned long runcntl;
+
if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) {
- /* Need to release ctx, because spu_setup_isolated will
- * acquire it exclusively.
- */
- spu_release(ctx);
- ret = spu_setup_isolated(ctx);
- if (!ret)
- ret = spu_acquire_runnable(ctx, 0);
+ int ret = spu_setup_isolated(ctx);
+ if (ret)
+ return ret;
}
/* if userspace has set the runcntrl register (eg, to issue an
@@ -164,16 +140,17 @@ static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
(SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
if (runcntl == 0)
runcntl = SPU_RUNCNTL_RUNNABLE;
+ ctx->ops->runcntl_write(ctx, runcntl);
} else {
spu_start_tick(ctx);
ctx->ops->npc_write(ctx, *npc);
+ ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
}
- ctx->ops->runcntl_write(ctx, runcntl);
- return ret;
+ return 0;
}
-static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
+static int spu_run_fini(struct spu_context *ctx, u32 * npc,
u32 * status)
{
int ret = 0;
@@ -189,19 +166,27 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
return ret;
}
-static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
+static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
u32 *status)
{
int ret;
- if ((ret = spu_run_fini(ctx, npc, status)) != 0)
+ ret = spu_run_fini(ctx, npc, status);
+ if (ret)
return ret;
- if (*status & (SPU_STATUS_STOPPED_BY_STOP |
- SPU_STATUS_STOPPED_BY_HALT)) {
+
+ if (*status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT))
return *status;
- }
- if ((ret = spu_run_init(ctx, npc)) != 0)
+
+ ret = spu_acquire_runnable(ctx, 0);
+ if (ret)
+ return ret;
+
+ ret = spu_run_init(ctx, npc);
+ if (ret) {
+ spu_release(ctx);
return ret;
+ }
return 0;
}
@@ -253,17 +238,17 @@ int spu_process_callback(struct spu_context *ctx)
{
struct spu_syscall_block s;
u32 ls_pointer, npc;
- char *ls;
+ void __iomem *ls;
long spu_ret;
int ret;
/* get syscall block from local store */
- npc = ctx->ops->npc_read(ctx);
- ls = ctx->ops->get_ls(ctx);
- ls_pointer = *(u32*)(ls + npc);
+ npc = ctx->ops->npc_read(ctx) & ~3;
+ ls = (void __iomem *)ctx->ops->get_ls(ctx);
+ ls_pointer = in_be32(ls + npc);
if (ls_pointer > (LS_SIZE - sizeof(s)))
return -EFAULT;
- memcpy(&s, ls + ls_pointer, sizeof (s));
+ memcpy_fromio(&s, ls + ls_pointer, sizeof(s));
/* do actual syscall without pinning the spu */
ret = 0;
@@ -283,7 +268,7 @@ int spu_process_callback(struct spu_context *ctx)
}
/* write result, jump over indirect pointer */
- memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret));
+ memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret));
ctx->ops->npc_write(ctx, npc);
ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
return ret;
@@ -292,11 +277,8 @@ int spu_process_callback(struct spu_context *ctx)
static inline int spu_process_events(struct spu_context *ctx)
{
struct spu *spu = ctx->spu;
- u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
int ret = 0;
- if (spu->dsisr & pte_fault)
- ret = spu_irq_class_1_bottom(spu);
if (spu->class_0_pending)
ret = spu_irq_class_0_bottom(spu);
if (!ret && signal_pending(current))
@@ -310,14 +292,21 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
int ret;
u32 status;
- if (down_interruptible(&ctx->run_sema))
+ if (mutex_lock_interruptible(&ctx->run_mutex))
return -ERESTARTSYS;
ctx->ops->master_start(ctx);
ctx->event_return = 0;
- ret = spu_run_init(ctx, npc);
+
+ ret = spu_acquire_runnable(ctx, 0);
if (ret)
+ return ret;
+
+ ret = spu_run_init(ctx, npc);
+ if (ret) {
+ spu_release(ctx);
goto out;
+ }
do {
ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
@@ -330,6 +319,10 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
break;
status &= ~SPU_STATUS_STOPPED_BY_STOP;
}
+ ret = spufs_handle_class1(ctx);
+ if (ret)
+ break;
+
if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
ret = spu_reacquire_runnable(ctx, npc, &status);
if (ret) {
@@ -363,6 +356,6 @@ out2:
out:
*event = ctx->event_return;
- up(&ctx->run_sema);
+ mutex_unlock(&ctx->run_mutex);
return ret;
}
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 39823cec0844..91030b8abdca 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -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)
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 5c4e47d69d79..0a947fd7de57 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -41,7 +41,7 @@ struct spu_gang;
/* ctx->sched_flags */
enum {
- SPU_SCHED_WAKE = 0, /* currently unused */
+ SPU_SCHED_EXITING = 0,
};
struct spu_context {
@@ -50,16 +50,17 @@ struct spu_context {
spinlock_t mmio_lock; /* protects mmio access */
struct address_space *local_store; /* local store mapping. */
struct address_space *mfc; /* 'mfc' area mappings. */
- struct address_space *cntl; /* 'control' area mappings. */
- struct address_space *signal1; /* 'signal1' area mappings. */
- struct address_space *signal2; /* 'signal2' area mappings. */
- struct address_space *mss; /* 'mss' area mappings. */
- struct address_space *psmap; /* 'psmap' area mappings. */
+ struct address_space *cntl; /* 'control' area mappings. */
+ struct address_space *signal1; /* 'signal1' area mappings. */
+ struct address_space *signal2; /* 'signal2' area mappings. */
+ struct address_space *mss; /* 'mss' area mappings. */
+ struct address_space *psmap; /* 'psmap' area mappings. */
+ spinlock_t mapping_lock;
u64 object_id; /* user space pointer for oprofile */
enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
struct mutex state_mutex;
- struct semaphore run_sema;
+ struct mutex run_mutex;
struct mm_struct *owner;
@@ -140,6 +141,7 @@ struct spu_context_ops {
struct spu_dma_info * info);
void (*proxydma_info_read) (struct spu_context * ctx,
struct spu_proxydma_info * info);
+ void (*restart_dma)(struct spu_context *ctx);
};
extern struct spu_context_ops spu_hw_ops;
@@ -149,6 +151,7 @@ struct spufs_inode_info {
struct spu_context *i_ctx;
struct spu_gang *i_gang;
struct inode vfs_inode;
+ int i_openers;
};
#define SPUFS_I(inode) \
container_of(inode, struct spufs_inode_info, vfs_inode)
@@ -170,6 +173,9 @@ int put_spu_gang(struct spu_gang *gang);
void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx);
void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx);
+/* fault handling */
+int spufs_handle_class1(struct spu_context *ctx);
+
/* context management */
static inline void spu_acquire(struct spu_context *ctx)
{
@@ -190,7 +196,6 @@ void spu_unmap_mappings(struct spu_context *ctx);
void spu_forget(struct spu_context *ctx);
int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags);
void spu_acquire_saved(struct spu_context *ctx);
-int spu_acquire_exclusive(struct spu_context *ctx);
int spu_activate(struct spu_context *ctx, unsigned long flags);
void spu_deactivate(struct spu_context *ctx);
@@ -218,14 +223,13 @@ extern char *isolated_loader;
prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \
if (condition) \
break; \
- if (!signal_pending(current)) { \
- spu_release(ctx); \
- schedule(); \
- spu_acquire(ctx); \
- continue; \
+ if (signal_pending(current)) { \
+ __ret = -ERESTARTSYS; \
+ break; \
} \
- __ret = -ERESTARTSYS; \
- break; \
+ spu_release(ctx); \
+ schedule(); \
+ spu_acquire(ctx); \
} \
finish_wait(&(wq), &__wait); \
__ret; \
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index fd91c73de34e..8347c4a3f894 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -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
index 000000000000..2db1e293433e
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/Kconfig
@@ -0,0 +1,9 @@
+config PPC_CELLEB
+ bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
+ depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_CELL
+ select PPC_OF_PLATFORM_PCI
+ select HAS_TXX9_SERIAL
+ select PPC_UDBG_BEAT
+ select USB_OHCI_BIG_ENDIAN_MMIO
+ select USB_EHCI_BIG_ENDIAN_MMIO
diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c
index f63b94c65353..755d869d8553 100644
--- a/arch/powerpc/platforms/celleb/iommu.c
+++ b/arch/powerpc/platforms/celleb/iommu.c
@@ -37,7 +37,7 @@ static int __init find_dma_window(u64 *io_space_id, u64 *ioid,
const unsigned long *dma_window;
for_each_node_by_type(dn, "ioif") {
- dma_window = get_property(dn, "toshiba,dma-window", NULL);
+ dma_window = of_get_property(dn, "toshiba,dma-window", NULL);
if (dma_window) {
*io_space_id = (dma_window[0] >> 32) & 0xffffffffUL;
*ioid = dma_window[0] & 0x7ffUL;
@@ -80,7 +80,7 @@ static int celleb_of_bus_notify(struct notifier_block *nb,
if (action != BUS_NOTIFY_ADD_DEVICE)
return 0;
- dev->archdata.dma_ops = pci_dma_ops;
+ dev->archdata.dma_ops = get_pci_dma_ops();
return 0;
}
@@ -95,7 +95,7 @@ static int __init celleb_init_iommu(void)
return -ENODEV;
celleb_init_direct_mapping();
- pci_dma_ops = &dma_direct_ops;
+ set_pci_dma_ops(&dma_direct_ops);
bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier);
return 0;
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c
index 98de836dfed3..d1adf34cd5e8 100644
--- a/arch/powerpc/platforms/celleb/pci.c
+++ b/arch/powerpc/platforms/celleb/pci.c
@@ -309,13 +309,13 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
goto error;
}
- name = get_property(node, "model", &rlen);
+ name = of_get_property(node, "model", &rlen);
if (!name) {
printk(KERN_ERR "PCI: model property not found.\n");
goto error;
}
- wi4 = get_property(node, "reg", &rlen);
+ wi4 = of_get_property(node, "reg", &rlen);
if (wi4 == NULL)
goto error;
@@ -352,10 +352,10 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
}
pr_debug("PCI: res assigned 0x%016lx\n", (unsigned long)*res);
- wi0 = get_property(node, "device-id", NULL);
- wi1 = get_property(node, "vendor-id", NULL);
- wi2 = get_property(node, "class-code", NULL);
- wi3 = get_property(node, "revision-id", NULL);
+ wi0 = of_get_property(node, "device-id", NULL);
+ wi1 = of_get_property(node, "vendor-id", NULL);
+ wi2 = of_get_property(node, "class-code", NULL);
+ wi3 = of_get_property(node, "revision-id", NULL);
celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff);
celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff);
@@ -376,7 +376,7 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr);
- li = get_property(node, "interrupts", &rlen);
+ li = of_get_property(node, "interrupts", &rlen);
val = li[0];
celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1);
celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val);
@@ -424,7 +424,7 @@ static int __devinit phb_set_bus_ranges(struct device_node *dev,
const int *bus_range;
unsigned int len;
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int))
return 1;
@@ -451,7 +451,7 @@ int __devinit celleb_setup_phb(struct pci_controller *phb)
struct device_node *node;
unsigned int rlen;
- name = get_property(dev, "name", &rlen);
+ name = of_get_property(dev, "name", &rlen);
if (!name)
return 1;
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c
index 5f4d0d933238..596ab2a788d4 100644
--- a/arch/powerpc/platforms/celleb/setup.c
+++ b/arch/powerpc/platforms/celleb/setup.c
@@ -67,7 +67,7 @@ static void celleb_show_cpuinfo(struct seq_file *m)
root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
/* using "CHRP" is to trick anaconda into installing FCx into Celleb */
seq_printf(m, "machine\t\t: %s %s\n", celleb_machine_type, model);
of_node_put(root);
@@ -128,15 +128,6 @@ static int __init celleb_probe(void)
return 1;
}
-/*
- * Cell has no legacy IO; anything calling this function has to
- * fail or bad things will happen
- */
-static int celleb_check_legacy_ioport(unsigned int baseport)
-{
- return -ENODEV;
-}
-
#ifdef CONFIG_KEXEC
static void celleb_kexec_cpu_down(int crash, int secondary)
{
@@ -173,7 +164,6 @@ define_machine(celleb) {
.get_rtc_time = beat_get_rtc_time,
.set_rtc_time = beat_set_rtc_time,
.calibrate_decr = generic_calibrate_decr,
- .check_legacy_ioport = celleb_check_legacy_ioport,
.progress = celleb_progress,
.power_save = beat_power_save,
.nvram_size = beat_nvram_get_size,
diff --git a/arch/powerpc/platforms/chrp/Kconfig b/arch/powerpc/platforms/chrp/Kconfig
new file mode 100644
index 000000000000..d2c690531963
--- /dev/null
+++ b/arch/powerpc/platforms/chrp/Kconfig
@@ -0,0 +1,11 @@
+config PPC_CHRP
+ bool "Common Hardware Reference Platform (CHRP) based machines"
+ depends on PPC_MULTIPLATFORM && PPC32
+ select MPIC
+ select PPC_I8259
+ select PPC_INDIRECT_PCI
+ select PPC_RTAS
+ select PPC_MPC106
+ select PPC_UDBG_16550
+ select PPC_NATIVE
+ default y
diff --git a/arch/powerpc/platforms/chrp/nvram.c b/arch/powerpc/platforms/chrp/nvram.c
index 0dd4a64757d9..8efd4244701c 100644
--- a/arch/powerpc/platforms/chrp/nvram.c
+++ b/arch/powerpc/platforms/chrp/nvram.c
@@ -74,7 +74,7 @@ void __init chrp_nvram_init(void)
if (nvram == NULL)
return;
- nbytes_p = get_property(nvram, "#bytes", &proplen);
+ nbytes_p = of_get_property(nvram, "#bytes", &proplen);
if (nbytes_p == NULL || proplen != sizeof(unsigned int))
return;
diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c
index ddb4a116ea89..1469d6478f67 100644
--- a/arch/powerpc/platforms/chrp/pci.c
+++ b/arch/powerpc/platforms/chrp/pci.c
@@ -7,7 +7,6 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
-#include <linux/ide.h>
#include <asm/io.h>
#include <asm/pgtable.h>
@@ -137,9 +136,11 @@ hydra_init(void)
struct device_node *np;
struct resource r;
- np = find_devices("mac-io");
- if (np == NULL || of_address_to_resource(np, 0, &r))
+ np = of_find_node_by_name(NULL, "mac-io");
+ if (np == NULL || of_address_to_resource(np, 0, &r)) {
+ of_node_put(np);
return 0;
+ }
Hydra = ioremap(r.start, r.end-r.start);
printk("Hydra Mac I/O at %llx\n", (unsigned long long)r.start);
printk("Hydra Feature_Control was %x",
@@ -186,10 +187,9 @@ setup_python(struct pci_controller *hose, struct device_node *dev)
/* Marvell Discovery II based Pegasos 2 */
static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev)
{
- struct device_node *root = find_path_device("/");
+ struct device_node *root = of_find_node_by_path("/");
struct device_node *rtas;
- of_node_get(root);
rtas = of_find_node_by_name (root, "rtas");
if (rtas) {
hose->ops = &rtas_pci_ops;
@@ -199,6 +199,7 @@ static void __init setup_peg2(struct pci_controller *hose, struct device_node *d
" your firmware\n");
}
pci_assign_all_buses = 1;
+ /* keep the reference to the root node */
}
void __init
@@ -211,14 +212,14 @@ chrp_find_bridges(void)
const unsigned int *dma;
const char *model, *machine;
int is_longtrail = 0, is_mot = 0, is_pegasos = 0;
- struct device_node *root = find_path_device("/");
+ struct device_node *root = of_find_node_by_path("/");
struct resource r;
/*
* The PCI host bridge nodes on some machines don't have
* properties to adequately identify them, so we have to
* look at what sort of machine this is as well.
*/
- machine = get_property(root, "model", NULL);
+ machine = of_get_property(root, "model", NULL);
if (machine != NULL) {
is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
is_mot = strncmp(machine, "MOT", 3) == 0;
@@ -237,7 +238,7 @@ chrp_find_bridges(void)
dev->full_name);
continue;
}
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s\n",
dev->full_name);
@@ -263,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 */
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 117c9a0055bd..1870038a8e0a 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -28,7 +28,6 @@
#include <linux/adb.h>
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/ide.h>
#include <linux/console.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
@@ -111,9 +110,9 @@ void chrp_show_cpuinfo(struct seq_file *m)
struct device_node *root;
const char *model = "";
- root = find_path_device("/");
+ root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
seq_printf(m, "machine\t\t: CHRP %s\n", model);
/* longtrail (goldengate) stuff */
@@ -161,6 +160,7 @@ void chrp_show_cpuinfo(struct seq_file *m)
gg2_cachetypes[(t>>2) & 3],
gg2_cachemodes[t & 3]);
}
+ of_node_put(root);
}
/*
@@ -205,13 +205,15 @@ static void __init sio_init(void)
{
struct device_node *root;
- if ((root = find_path_device("/")) &&
- !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
+ if ((root = of_find_node_by_path("/")) &&
+ !strncmp(of_get_property(root, "model", NULL),
+ "IBM,LongTrail", 13)) {
/* logical device 0 (KBC/Keyboard) */
sio_fixup_irq("keyboard", 0, 1, 2);
/* select logical device 1 (KBC/Mouse) */
sio_fixup_irq("mouse", 1, 12, 2);
}
+ of_node_put(root);
}
@@ -224,12 +226,12 @@ static void __init pegasos_set_l2cr(void)
return;
/* Enable L2 cache if needed */
- np = find_type_devices("cpu");
+ np = of_find_node_by_type(NULL, "cpu");
if (np != NULL) {
- const unsigned int *l2cr = get_property(np, "l2cr", NULL);
+ const unsigned int *l2cr = of_get_property(np, "l2cr", NULL);
if (l2cr == NULL) {
printk ("Pegasos l2cr : no cpu l2cr property found\n");
- return;
+ goto out;
}
if (!((*l2cr) & 0x80000000)) {
printk ("Pegasos l2cr : L2 cache was not active, "
@@ -238,6 +240,8 @@ static void __init pegasos_set_l2cr(void)
_set_L2CR((*l2cr) | 0x80000000);
}
}
+out:
+ of_node_put(np);
}
static void briq_restart(char *cmd)
@@ -250,14 +254,14 @@ static void briq_restart(char *cmd)
void __init chrp_setup_arch(void)
{
- struct device_node *root = find_path_device ("/");
+ struct device_node *root = of_find_node_by_path("/");
const char *machine = NULL;
/* init to some ~sane value until calibrate_delay() runs */
loops_per_jiffy = 50000000/HZ;
if (root)
- machine = get_property(root, "model", NULL);
+ machine = of_get_property(root, "model", NULL);
if (machine && strncmp(machine, "Pegasos", 7) == 0) {
_chrp_type = _CHRP_Pegasos;
} else if (machine && strncmp(machine, "IBM", 3) == 0) {
@@ -273,6 +277,7 @@ void __init chrp_setup_arch(void)
/* Let's assume it is an IBM chrp if all else fails */
_chrp_type = _CHRP_IBM;
}
+ of_node_put(root);
printk("chrp type = %x [%s]\n", _chrp_type, chrp_names[_chrp_type]);
rtas_initialize();
@@ -361,8 +366,8 @@ static void __init chrp_find_openpic(void)
return;
root = of_find_node_by_path("/");
if (root) {
- opprop = get_property(root, "platform-open-pic", &oplen);
- na = prom_n_addr_cells(root);
+ opprop = of_get_property(root, "platform-open-pic", &oplen);
+ na = of_n_addr_cells(root);
}
if (opprop && oplen >= na * sizeof(unsigned int)) {
opaddr = opprop[na-1]; /* assume 32-bit */
@@ -378,7 +383,7 @@ static void __init chrp_find_openpic(void)
printk(KERN_INFO "OpenPIC at %lx\n", opaddr);
- iranges = get_property(np, "interrupt-ranges", &len);
+ iranges = of_get_property(np, "interrupt-ranges", &len);
if (iranges == NULL)
len = 0; /* non-distributed mpic */
else
@@ -427,7 +432,7 @@ static void __init chrp_find_openpic(void)
of_node_put(np);
}
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
static struct irqaction xmon_irqaction = {
.handler = xmon_irq,
.mask = CPU_MASK_NONE,
@@ -463,15 +468,16 @@ static void __init chrp_find_8259(void)
* Also, Pegasos-type platforms don't have a proper node to start
* from anyway
*/
- for (np = find_devices("pci"); np != NULL; np = np->next) {
- const unsigned int *addrp = get_property(np,
+ for_each_node_by_name(np, "pci") {
+ const unsigned int *addrp = of_get_property(np,
"8259-interrupt-acknowledge", NULL);
if (addrp == NULL)
continue;
- chrp_int_ack = addrp[prom_n_addr_cells(np)-1];
+ chrp_int_ack = addrp[of_n_addr_cells(np)-1];
break;
}
+ of_node_put(np);
if (np == NULL)
printk(KERN_WARNING "Cannot find PCI interrupt acknowledge"
" address, polling\n");
@@ -493,7 +499,7 @@ static void __init chrp_find_8259(void)
void __init chrp_init_IRQ(void)
{
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
struct device_node *kbd;
#endif
chrp_find_openpic();
@@ -510,13 +516,14 @@ void __init chrp_init_IRQ(void)
if (_chrp_type == _CHRP_Pegasos)
ppc_md.get_irq = i8259_irq;
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
/* see if there is a keyboard in the device tree
with a parent of type "adb" */
- for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
+ for_each_node_by_name(kbd, "keyboard")
if (kbd->parent && kbd->parent->type
&& strcmp(kbd->parent->type, "adb") == 0)
break;
+ of_node_put(kbd);
if (kbd)
setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction);
#endif
@@ -542,9 +549,9 @@ chrp_init2(void)
/* Get the event scan rate for the rtas so we know how
* often it expects a heartbeat. -- Cort
*/
- device = find_devices("rtas");
+ device = of_find_node_by_name(NULL, "rtas");
if (device)
- p = get_property(device, "rtas-event-scan-rate", NULL);
+ p = of_get_property(device, "rtas-event-scan-rate", NULL);
if (p && *p) {
/*
* Arrange to call chrp_event_scan at least *p times
@@ -571,6 +578,7 @@ chrp_init2(void)
printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
*p, interval);
}
+ of_node_put(device);
if (ppc_md.progress)
ppc_md.progress(" Have fun! ", 0x7777);
diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c
index 7d7889026936..96d1e4b3c493 100644
--- a/arch/powerpc/platforms/chrp/time.c
+++ b/arch/powerpc/platforms/chrp/time.c
@@ -39,12 +39,17 @@ long __init chrp_time_init(void)
struct resource r;
int base;
- rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
+ rtcs = of_find_compatible_node(NULL, "rtc", "pnpPNP,b00");
if (rtcs == NULL)
- rtcs = find_compatible_devices("rtc", "ds1385-rtc");
- if (rtcs == NULL || of_address_to_resource(rtcs, 0, &r))
+ rtcs = of_find_compatible_node(NULL, "rtc", "ds1385-rtc");
+ if (rtcs == NULL)
+ return 0;
+ if (of_address_to_resource(rtcs, 0, &r)) {
+ of_node_put(rtcs);
return 0;
-
+ }
+ of_node_put(rtcs);
+
base = r.start;
nvram_as1 = 0;
nvram_as0 = base;
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index 3410bcbc9dbe..9557908ef545 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -2,78 +2,6 @@ choice
prompt "Machine Type"
depends on EMBEDDED6xx
-config KATANA
- bool "Artesyn-Katana"
- help
- Select KATANA if configuring an Artesyn KATANA 750i or 3750
- cPCI board.
-
-config WILLOW
- bool "Cogent-Willow"
-
-config CPCI690
- bool "Force-CPCI690"
- help
- Select CPCI690 if configuring a Force CPCI690 cPCI board.
-
-config POWERPMC250
- bool "Force-PowerPMC250"
-
-config CHESTNUT
- bool "IBM 750FX Eval board or 750GX Eval board"
- help
- Select CHESTNUT if configuring an IBM 750FX Eval Board or a
- IBM 750GX Eval board.
-
-config SPRUCE
- bool "IBM-Spruce"
- select PPC_INDIRECT_PCI
-
-config HDPU
- bool "Sky-HDPU"
- help
- Select HDPU if configuring a Sky Computers Compute Blade.
-
-config HDPU_FEATURES
- depends on HDPU
- tristate "HDPU-Features"
- help
- Select to enable HDPU enhanced features.
-
-config EV64260
- bool "Marvell-EV64260BP"
- help
- Select EV64260 if configuring a Marvell (formerly Galileo)
- EV64260BP Evaluation platform.
-
-config LOPEC
- bool "Motorola-LoPEC"
- select PPC_I8259
-
-config MVME5100
- bool "Motorola-MVME5100"
- select PPC_INDIRECT_PCI
-
-config PPLUS
- bool "Motorola-PowerPlus"
- select PPC_I8259
- select PPC_INDIRECT_PCI
-
-config PRPMC750
- bool "Motorola-PrPMC750"
- select PPC_INDIRECT_PCI
-
-config PRPMC800
- bool "Motorola-PrPMC800"
- select PPC_INDIRECT_PCI
-
-config SANDPOINT
- bool "Motorola-Sandpoint"
- select PPC_I8259
- help
- Select SANDPOINT if configuring for a Motorola Sandpoint X3
- (any flavor).
-
config LINKSTATION
bool "Linkstation / Kurobox(HG) from Buffalo"
select MPIC
@@ -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
diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c
index 3f6c4114f908..b412f006a9c5 100644
--- a/arch/powerpc/platforms/embedded6xx/linkstation.c
+++ b/arch/powerpc/platforms/embedded6xx/linkstation.c
@@ -58,11 +58,11 @@ static int __init add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
- int *bus_range;
+ const int *bus_range;
printk("Adding PCI host bridge %s\n", dev->full_name);
- bus_range = (int *) get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int))
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
@@ -106,7 +106,7 @@ static void __init linkstation_init_IRQ(void)
{
struct mpic *mpic;
struct device_node *dnp;
- void *prop;
+ const u32 *prop;
int size;
phys_addr_t paddr;
@@ -114,7 +114,7 @@ static void __init linkstation_init_IRQ(void)
if (dnp == NULL)
return;
- prop = (struct device_node *)get_property(dnp, "reg", &size);
+ prop = of_get_property(dnp, "reg", &size);
paddr = (phys_addr_t)of_translate_address(dnp, prop);
mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, 4, 32, " EPIC ");
diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c
index 0e837762cc5b..d0bee9f19e4e 100644
--- a/arch/powerpc/platforms/embedded6xx/ls_uart.c
+++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c
@@ -110,8 +110,8 @@ static int __init ls_uarts_init(void)
if (!avr)
return -EINVAL;
- avr_clock = *(u32*)get_property(avr, "clock-frequency", &len);
- phys_addr = ((u32*)get_property(avr, "reg", &len))[0];
+ avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len);
+ phys_addr = ((u32*)of_get_property(avr, "reg", &len))[0];
if (!avr_clock || !phys_addr)
return -EINVAL;
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index 3fcc85f60fbf..c3f64ddb0be6 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -25,7 +25,6 @@
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/irq.h>
-#include <linux/ide.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/serial.h>
@@ -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);
}
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index 54e6b3b6f261..46c3a8e7c3a8 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -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
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index d7a756d5135c..3b6a9666c2c0 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -171,7 +171,7 @@ void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn)
{
struct iommu_table *tbl;
struct pci_dn *pdn = PCI_DN(dn);
- const u32 *lsn = get_property(dn, "linux,logical-slot-number", NULL);
+ const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL);
BUG_ON(lsn == NULL);
@@ -194,5 +194,5 @@ void iommu_init_early_iSeries(void)
ppc_md.tce_build = tce_build_iSeries;
ppc_md.tce_free = tce_free_iSeries;
- pci_dma_ops = &dma_iommu_ops;
+ set_pci_dma_ops(&dma_iommu_ops);
}
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index 5225abfafd9b..63b33675848b 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -30,7 +30,6 @@
#include <linux/param.h>
#include <linux/string.h>
#include <linux/bootmem.h>
-#include <linux/ide.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
@@ -337,6 +336,8 @@ unsigned int iSeries_get_irq(void)
return irq;
}
+#ifdef CONFIG_PCI
+
static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
@@ -384,3 +385,4 @@ void __init iSeries_init_IRQ(void)
"failed with rc 0x%x\n", ret);
}
+#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 4a06d9c34986..9c974227155e 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -24,7 +24,6 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/ide.h>
#include <linux/pci.h>
#include <asm/io.h>
@@ -177,7 +176,7 @@ void __init iSeries_pci_final_fixup(void)
struct pci_dn *pdn = PCI_DN(node);
const u32 *agent;
- agent = get_property(node, "linux,agent-id", NULL);
+ agent = of_get_property(node, "linux,agent-id", NULL);
if ((pdn != NULL) && (agent != NULL)) {
u8 irq = iSeries_allocate_IRQ(pdn->busno, 0,
pdn->bussubno);
@@ -755,7 +754,7 @@ void __init iSeries_pcibios_init(void)
if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
continue;
- busp = get_property(node, "bus-range", NULL);
+ busp = of_get_property(node, "bus-range", NULL);
if (busp == NULL)
continue;
bus = *busp;
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index cce7e309340c..7f5dcee814d4 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -628,15 +628,6 @@ static void iseries_iounmap(volatile void __iomem *token)
{
}
-/*
- * iSeries has no legacy IO, anything calling this function has to
- * fail or bad things will happen
- */
-static int iseries_check_legacy_ioport(unsigned int baseport)
-{
- return -ENODEV;
-}
-
static int __init iseries_probe(void)
{
unsigned long root = of_get_flat_dt_root();
@@ -667,7 +658,6 @@ define_machine(iseries) {
.calibrate_decr = generic_calibrate_decr,
.progress = iSeries_progress,
.probe = iseries_probe,
- .check_legacy_ioport = iseries_check_legacy_ioport,
.ioremap = iseries_ioremap,
.iounmap = iseries_iounmap,
/* XXX Implement enable_pmcs for iSeries */
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
index e2100ece9c65..2ca2d8a9de97 100644
--- a/arch/powerpc/platforms/iseries/viopath.c
+++ b/arch/powerpc/platforms/iseries/viopath.c
@@ -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
index 000000000000..f7c95eb5d8ba
--- /dev/null
+++ b/arch/powerpc/platforms/maple/Kconfig
@@ -0,0 +1,17 @@
+config PPC_MAPLE
+ depends on PPC_MULTIPLATFORM && PPC64
+ bool "Maple 970FX Evaluation Board"
+ select MPIC
+ select U3_DART
+ select MPIC_U3_HT_IRQS
+ select GENERIC_TBSYNC
+ select PPC_UDBG_16550
+ select PPC_970_NAP
+ select PPC_NATIVE
+ select PPC_RTAS
+ select MMIO_NVRAM
+ select ATA_NONSTANDARD if ATA
+ default n
+ help
+ This option enables support for the Maple 970FX Evaluation Board.
+ For more information, refer to <http://www.970eval.com>
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 73c59904697f..b1d3b99c3f9d 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -44,11 +44,11 @@ static int __init fixup_one_level_bus_range(struct device_node *node, int higher
int len;
/* For PCI<->PCI bridges or CardBus bridges, we go down */
- class_code = get_property(node, "class-code", NULL);
+ class_code = of_get_property(node, "class-code", NULL);
if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
continue;
- bus_range = get_property(node, "bus-range", &len);
+ bus_range = of_get_property(node, "bus-range", &len);
if (bus_range != NULL && len > 2 * sizeof(int)) {
if (bus_range[1] > higher)
higher = bus_range[1];
@@ -77,7 +77,7 @@ static void __init fixup_bus_range(struct device_node *bridge)
bridge->full_name);
return;
}
- bus_range = (int *)prop->value;
+ bus_range = prop->value;
bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
}
@@ -454,7 +454,7 @@ static int __init add_bridge(struct device_node *dev)
DBG("Adding PCI host bridge %s\n", dev->full_name);
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
dev->full_name);
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 82d3f9e28d7c..2a30c5b2532e 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -32,7 +32,6 @@
#include <linux/initrd.h>
#include <linux/vt_kern.h>
#include <linux/console.h>
-#include <linux/ide.h>
#include <linux/pci.h>
#include <linux/adb.h>
#include <linux/cuda.h>
@@ -114,8 +113,8 @@ static void maple_restart(char *cmd)
printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
goto fail;
}
- maple_nvram_offset = get_property(sp, "restart-addr", NULL);
- maple_nvram_command = get_property(sp, "restart-value", NULL);
+ maple_nvram_offset = of_get_property(sp, "restart-addr", NULL);
+ maple_nvram_command = of_get_property(sp, "restart-value", NULL);
of_node_put(sp);
/* send command */
@@ -141,8 +140,8 @@ static void maple_power_off(void)
printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
goto fail;
}
- maple_nvram_offset = get_property(sp, "power-off-addr", NULL);
- maple_nvram_command = get_property(sp, "power-off-value", NULL);
+ maple_nvram_offset = of_get_property(sp, "power-off-addr", NULL);
+ maple_nvram_command = of_get_property(sp, "power-off-value", NULL);
of_node_put(sp);
/* send command */
@@ -249,8 +248,8 @@ static void __init maple_init_IRQ(void)
/* Find address list in /platform-open-pic */
root = of_find_node_by_path("/");
- naddr = prom_n_addr_cells(root);
- opprop = get_property(root, "platform-open-pic", &opplen);
+ naddr = of_n_addr_cells(root);
+ opprop = of_get_property(root, "platform-open-pic", &opplen);
if (opprop != 0) {
openpic_addr = of_read_number(opprop, naddr);
has_isus = (opplen > naddr);
@@ -261,11 +260,11 @@ static void __init maple_init_IRQ(void)
BUG_ON(openpic_addr == 0);
/* Check for a big endian MPIC */
- if (get_property(np, "big-endian", NULL) != NULL)
+ if (of_get_property(np, "big-endian", NULL) != NULL)
flags |= MPIC_BIG_ENDIAN;
/* XXX Maple specific bits */
- flags |= MPIC_BROKEN_U3 | MPIC_WANTS_RESET;
+ flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET;
/* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */
flags |= MPIC_BIG_ENDIAN;
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig
index 68dc529dfd2f..eb4dbc705b06 100644
--- a/arch/powerpc/platforms/pasemi/Kconfig
+++ b/arch/powerpc/platforms/pasemi/Kconfig
@@ -1,3 +1,15 @@
+config PPC_PASEMI
+ depends on PPC_MULTIPLATFORM && PPC64
+ bool "PA Semi SoC-based platforms"
+ default n
+ select MPIC
+ select PPC_UDBG_16550
+ select GENERIC_TBSYNC
+ select PPC_NATIVE
+ help
+ This option enables support for PA Semi's PWRficient line
+ of SoC processors, including PA6T-1682M
+
menu "PA Semi PWRficient options"
depends on PPC_PASEMI
@@ -7,4 +19,11 @@ config PPC_PASEMI_IOMMU
help
IOMMU support for PA6T-1682M
+config PPC_PASEMI_MDIO
+ depends on PHYLIB
+ tristate "MDIO support via GPIO"
+ default y
+ help
+ Driver for MDIO via GPIO on PWRficient platforms
+
endmenu
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile
index e657ccae90a9..2cd2a4f26a48 100644
--- a/arch/powerpc/platforms/pasemi/Makefile
+++ b/arch/powerpc/platforms/pasemi/Makefile
@@ -1,2 +1,3 @@
obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o
-
+obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o
+obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c
new file mode 100644
index 000000000000..2a57d6023685
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/cpufreq.c
@@ -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
index 000000000000..c91a33593bb8
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Olof Johansson, PA Semi
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on drivers/net/fs_enet/mii-bitbang.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <asm/of_platform.h>
+
+#define DELAY 1
+
+static void __iomem *gpio_regs;
+
+struct gpio_priv {
+ int mdc_pin;
+ int mdio_pin;
+};
+
+#define MDC_PIN(bus) (((struct gpio_priv *)bus->priv)->mdc_pin)
+#define MDIO_PIN(bus) (((struct gpio_priv *)bus->priv)->mdio_pin)
+
+static inline void mdio_lo(struct mii_bus *bus)
+{
+ out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus));
+}
+
+static inline void mdio_hi(struct mii_bus *bus)
+{
+ out_le32(gpio_regs, 1 << MDIO_PIN(bus));
+}
+
+static inline void mdc_lo(struct mii_bus *bus)
+{
+ out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus));
+}
+
+static inline void mdc_hi(struct mii_bus *bus)
+{
+ out_le32(gpio_regs, 1 << MDC_PIN(bus));
+}
+
+static inline void mdio_active(struct mii_bus *bus)
+{
+ out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus)));
+}
+
+static inline void mdio_tristate(struct mii_bus *bus)
+{
+ out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus)));
+}
+
+static inline int mdio_read(struct mii_bus *bus)
+{
+ return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus)));
+}
+
+static void clock_out(struct mii_bus *bus, int bit)
+{
+ if (bit)
+ mdio_hi(bus);
+ else
+ mdio_lo(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ mdc_lo(bus);
+}
+
+/* Utility to send the preamble, address, and register (common to read and write). */
+static void bitbang_pre(struct mii_bus *bus, int read, u8 addr, u8 reg)
+{
+ int i;
+
+ /* CFE uses a really long preamble (40 bits). We'll do the same. */
+ mdio_active(bus);
+ for (i = 0; i < 40; i++) {
+ clock_out(bus, 1);
+ }
+
+ /* send the start bit (01) and the read opcode (10) or write (10) */
+ clock_out(bus, 0);
+ clock_out(bus, 1);
+
+ clock_out(bus, read);
+ clock_out(bus, !read);
+
+ /* send the PHY address */
+ for (i = 0; i < 5; i++) {
+ clock_out(bus, (addr & 0x10) != 0);
+ addr <<= 1;
+ }
+
+ /* send the register address */
+ for (i = 0; i < 5; i++) {
+ clock_out(bus, (reg & 0x10) != 0);
+ reg <<= 1;
+ }
+}
+
+static int gpio_mdio_read(struct mii_bus *bus, int phy_id, int location)
+{
+ u16 rdreg;
+ int ret, i;
+ u8 addr = phy_id & 0xff;
+ u8 reg = location & 0xff;
+
+ bitbang_pre(bus, 1, addr, reg);
+
+ /* tri-state our MDIO I/O pin so we can read */
+ mdio_tristate(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ mdc_lo(bus);
+
+ /* read 16 bits of register data, MSB first */
+ rdreg = 0;
+ for (i = 0; i < 16; i++) {
+ mdc_lo(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ mdc_lo(bus);
+ udelay(DELAY);
+ rdreg <<= 1;
+ rdreg |= mdio_read(bus);
+ }
+
+ mdc_hi(bus);
+ udelay(DELAY);
+ mdc_lo(bus);
+ udelay(DELAY);
+
+ ret = rdreg;
+
+ return ret;
+}
+
+static int gpio_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+{
+ int i;
+
+ u8 addr = phy_id & 0xff;
+ u8 reg = location & 0xff;
+ u16 value = val & 0xffff;
+
+ bitbang_pre(bus, 0, addr, reg);
+
+ /* send the turnaround (10) */
+ mdc_lo(bus);
+ mdio_hi(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ mdc_lo(bus);
+ mdio_lo(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+
+ /* write 16 bits of register data, MSB first */
+ for (i = 0; i < 16; i++) {
+ mdc_lo(bus);
+ if (value & 0x8000)
+ mdio_hi(bus);
+ else
+ mdio_lo(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ value <<= 1;
+ }
+
+ /*
+ * Tri-state the MDIO line.
+ */
+ mdio_tristate(bus);
+ mdc_lo(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ return 0;
+}
+
+static int gpio_mdio_reset(struct mii_bus *bus)
+{
+ /*nothing here - dunno how to reset it*/
+ return 0;
+}
+
+
+static int __devinit gpio_mdio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device *dev = &ofdev->dev;
+ struct device_node *np = ofdev->node;
+ struct device_node *gpio_np;
+ struct mii_bus *new_bus;
+ struct resource res;
+ struct gpio_priv *priv;
+ const unsigned int *prop;
+ int err = 0;
+ int i;
+
+ gpio_np = of_find_compatible_node(NULL, "gpio", "1682m-gpio");
+
+ if (!gpio_np)
+ return -ENODEV;
+
+ err = of_address_to_resource(gpio_np, 0, &res);
+ of_node_put(gpio_np);
+
+ if (err)
+ return -EINVAL;
+
+ if (!gpio_regs)
+ gpio_regs = ioremap(res.start, 0x100);
+
+ if (!gpio_regs)
+ return -EPERM;
+
+ priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+ if (new_bus == NULL)
+ return -ENOMEM;
+
+ new_bus->name = "pasemi gpio mdio bus",
+ new_bus->read = &gpio_mdio_read,
+ new_bus->write = &gpio_mdio_write,
+ new_bus->reset = &gpio_mdio_reset,
+
+ prop = of_get_property(np, "reg", NULL);
+ new_bus->id = *prop;
+ new_bus->priv = priv;
+
+ new_bus->phy_mask = 0;
+
+ new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ for(i = 0; i < PHY_MAX_ADDR; ++i)
+ new_bus->irq[i] = irq_create_mapping(NULL, 10);
+
+
+ prop = of_get_property(np, "mdc-pin", NULL);
+ priv->mdc_pin = *prop;
+
+ prop = of_get_property(np, "mdio-pin", NULL);
+ priv->mdio_pin = *prop;
+
+ new_bus->dev = dev;
+ dev_set_drvdata(dev, new_bus);
+
+ err = mdiobus_register(new_bus);
+
+ if (0 != err) {
+ printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n",
+ new_bus->name, err);
+ goto bus_register_fail;
+ }
+
+ return 0;
+
+bus_register_fail:
+ kfree(new_bus);
+
+ return err;
+}
+
+
+static int gpio_mdio_remove(struct of_device *dev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&dev->dev);
+
+ mdiobus_unregister(bus);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ kfree(bus->priv);
+ bus->priv = NULL;
+ kfree(bus);
+
+ return 0;
+}
+
+static struct of_device_id gpio_mdio_match[] =
+{
+ {
+ .compatible = "gpio-mdio",
+ },
+ {},
+};
+
+static struct of_platform_driver gpio_mdio_driver =
+{
+ .name = "gpio-mdio-bitbang",
+ .match_table = gpio_mdio_match,
+ .probe = gpio_mdio_probe,
+ .remove = gpio_mdio_remove,
+};
+
+int gpio_mdio_init(void)
+{
+ return of_register_platform_driver(&gpio_mdio_driver);
+}
+
+void gpio_mdio_exit(void)
+{
+ of_unregister_platform_driver(&gpio_mdio_driver);
+}
+device_initcall(gpio_mdio_init);
+
diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c
index 1ca3ff381591..5985ce0c5c48 100644
--- a/arch/powerpc/platforms/pasemi/idle.c
+++ b/arch/powerpc/platforms/pasemi/idle.c
@@ -61,6 +61,10 @@ static int pasemi_system_reset_exception(struct pt_regs *regs)
/* do system reset */
return 0;
}
+
+ /* Set higher astate since we come out of power savings at 0 */
+ restore_astate(hard_smp_processor_id());
+
/* everything handled */
regs->msr |= MSR_RI;
return 1;
@@ -68,6 +72,11 @@ static int pasemi_system_reset_exception(struct pt_regs *regs)
void __init pasemi_idle_init(void)
{
+#ifndef CONFIG_PPC_PASEMI_CPUFREQ
+ printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n");
+ current_mode = 0;
+#endif
+
ppc_md.system_reset_exception = pasemi_system_reset_exception;
ppc_md.power_save = modes[current_mode].entry;
printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name);
diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c
index 71dbf1a56e13..95fa6a7d15ee 100644
--- a/arch/powerpc/platforms/pasemi/iommu.c
+++ b/arch/powerpc/platforms/pasemi/iommu.c
@@ -249,13 +249,13 @@ void iommu_init_early_pasemi(void)
iommu_off = 1;
#else
iommu_off = of_chosen &&
- get_property(of_chosen, "linux,iommu-off", NULL);
+ of_get_property(of_chosen, "linux,iommu-off", NULL);
#endif
if (iommu_off) {
/* Direct I/O, IOMMU off */
ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_null;
ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_null;
- pci_dma_ops = &dma_direct_ops;
+ set_pci_dma_ops(&dma_direct_ops);
return;
}
@@ -266,7 +266,7 @@ void iommu_init_early_pasemi(void)
ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi;
ppc_md.tce_build = iobmap_build;
ppc_md.tce_free = iobmap_free;
- pci_dma_ops = &dma_iommu_ops;
+ set_pci_dma_ops(&dma_iommu_ops);
}
void __init alloc_iobmap_l2(void)
diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h
index 2d3927e6edb0..be8495497611 100644
--- a/arch/powerpc/platforms/pasemi/pasemi.h
+++ b/arch/powerpc/platforms/pasemi/pasemi.h
@@ -14,6 +14,14 @@ extern void __init pasemi_idle_init(void);
extern void idle_spin(void);
extern void idle_doze(void);
+/* Restore astate to last set */
+#ifdef CONFIG_PPC_PASEMI_CPUFREQ
+extern void restore_astate(int cpu);
+#else
+static inline void restore_astate(int cpu)
+{
+}
+#endif
#endif /* _PASEMI_PASEMI_H */
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index 7ecb2ba24db9..056243da360b 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -33,7 +33,17 @@
#define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))
-#define CONFIG_OFFSET_VALID(off) ((off) < 4096)
+static inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset)
+{
+ /* Device 0 Function 0 is special: It's config space spans function 1 as
+ * well, so allow larger offset. It's really a two-function device but the
+ * second function does not probe.
+ */
+ if (bus == 0 && devfn == 0)
+ return offset < 8192;
+ else
+ return offset < 4096;
+}
static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose,
u8 bus, u8 devfn, int offset)
@@ -51,7 +61,7 @@ static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn,
if (!hose)
return PCIBIOS_DEVICE_NOT_FOUND;
- if (!CONFIG_OFFSET_VALID(offset))
+ if (!pa_pxp_offset_valid(bus->number, devfn, offset))
return PCIBIOS_BAD_REGISTER_NUMBER;
addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
@@ -85,7 +95,7 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn,
if (!hose)
return PCIBIOS_DEVICE_NOT_FOUND;
- if (!CONFIG_OFFSET_VALID(offset))
+ if (!pa_pxp_offset_valid(bus->number, devfn, offset))
return PCIBIOS_BAD_REGISTER_NUMBER;
addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index 449cf1a08291..f88f0ec4c8cb 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -35,6 +35,7 @@
#include <asm/mpic.h>
#include <asm/smp.h>
#include <asm/time.h>
+#include <asm/of_platform.h>
#include "pasemi.h"
@@ -101,12 +102,6 @@ void __init pas_setup_arch(void)
pasemi_idle_init();
}
-/* No legacy IO on our parts */
-static int pas_check_legacy_ioport(unsigned int baseport)
-{
- return -ENODEV;
-}
-
static __init void pas_init_IRQ(void)
{
struct device_node *np;
@@ -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
index 000000000000..5b7afe50039a
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/Kconfig
@@ -0,0 +1,20 @@
+config PPC_PMAC
+ bool "Apple PowerMac based machines"
+ depends on PPC_MULTIPLATFORM
+ select MPIC
+ select PPC_INDIRECT_PCI if PPC32
+ select PPC_MPC106 if PPC32
+ select PPC_NATIVE
+ default y
+
+config PPC_PMAC64
+ bool
+ depends on PPC_PMAC && POWER4
+ select MPIC
+ select U3_DART
+ select MPIC_U3_HT_IRQS
+ select GENERIC_TBSYNC
+ select PPC_970_NAP
+ default y
+
+
diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
index de7440e62cc4..d679964ae2ab 100644
--- a/arch/powerpc/platforms/powermac/backlight.c
+++ b/arch/powerpc/platforms/powermac/backlight.c
@@ -56,13 +56,16 @@ struct backlight_device *pmac_backlight;
int pmac_has_backlight_type(const char *type)
{
- struct device_node* bk_node = find_devices("backlight");
+ struct device_node* bk_node = of_find_node_by_name(NULL, "backlight");
if (bk_node) {
- const char *prop = get_property(bk_node,
+ const char *prop = of_get_property(bk_node,
"backlight-control", NULL);
- if (prop && strncmp(prop, type, strlen(type)) == 0)
+ if (prop && strncmp(prop, type, strlen(type)) == 0) {
+ of_node_put(bk_node);
return 1;
+ }
+ of_node_put(bk_node);
}
return 0;
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index c2b6b4134f68..8943a9456bb7 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -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;
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index 9d22361a26d6..567d5523b690 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -410,7 +410,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
/* Get first CPU node */
for (cpunode = NULL;
(cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
- const u32 *reg = get_property(cpunode, "reg", NULL);
+ const u32 *reg = of_get_property(cpunode, "reg", NULL);
if (reg == NULL || (*reg) != 0)
continue;
if (!strcmp(cpunode->type, "cpu"))
@@ -422,7 +422,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
}
/* Check 970FX for now */
- valp = get_property(cpunode, "cpu-version", NULL);
+ valp = of_get_property(cpunode, "cpu-version", NULL);
if (!valp) {
DBG("No cpu-version property !\n");
goto bail_noprops;
@@ -434,7 +434,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
}
/* Look for the powertune data in the device-tree */
- g5_pmode_data = get_property(cpunode, "power-mode-data",&psize);
+ g5_pmode_data = of_get_property(cpunode, "power-mode-data",&psize);
if (!g5_pmode_data) {
DBG("No power-mode-data !\n");
goto bail_noprops;
@@ -493,7 +493,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
* half freq in this version. So far, I haven't yet seen a machine
* supporting anything else.
*/
- valp = get_property(cpunode, "clock-frequency", NULL);
+ valp = of_get_property(cpunode, "clock-frequency", NULL);
if (!valp)
return -ENODEV;
max_freq = (*valp)/1000;
@@ -563,7 +563,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
/* Lookup the cpuid eeprom node */
cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
if (cpuid != NULL)
- eeprom = get_property(cpuid, "cpuid", NULL);
+ eeprom = of_get_property(cpuid, "cpuid", NULL);
if (eeprom == NULL) {
printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n");
rc = -ENODEV;
@@ -573,13 +573,13 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
/* Lookup the i2c hwclock */
for (hwclock = NULL;
(hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){
- const char *loc = get_property(hwclock,
+ const char *loc = of_get_property(hwclock,
"hwctrl-location", NULL);
if (loc == NULL)
continue;
if (strcmp(loc, "CPU CLOCK"))
continue;
- if (!get_property(hwclock, "platform-get-frequency", NULL))
+ if (!of_get_property(hwclock, "platform-get-frequency", NULL))
continue;
break;
}
@@ -638,7 +638,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
*/
/* Get max frequency from device-tree */
- valp = get_property(cpunode, "clock-frequency", NULL);
+ valp = of_get_property(cpunode, "clock-frequency", NULL);
if (!valp) {
printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n");
rc = -ENODEV;
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index 24cc50c1774a..52cfdd86c928 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -1044,6 +1044,7 @@ core99_reset_cpu(struct device_node *node, long param, long value)
unsigned long flags;
struct macio_chip *macio;
struct device_node *np;
+ struct device_node *cpus;
const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0,
KL_GPIO_RESET_CPU1,
KL_GPIO_RESET_CPU2,
@@ -1053,12 +1054,12 @@ core99_reset_cpu(struct device_node *node, long param, long value)
if (macio->type != macio_keylargo)
return -ENODEV;
- np = find_path_device("/cpus");
- if (np == NULL)
+ cpus = of_find_node_by_path("/cpus");
+ if (cpus == NULL)
return -ENODEV;
- for (np = np->child; np != NULL; np = np->sibling) {
- const u32 *num = get_property(np, "reg", NULL);
- const u32 *rst = get_property(np, "soft-reset", NULL);
+ for (np = cpus->child; np != NULL; np = np->sibling) {
+ const u32 *num = of_get_property(np, "reg", NULL);
+ const u32 *rst = of_get_property(np, "soft-reset", NULL);
if (num == NULL || rst == NULL)
continue;
if (param == *num) {
@@ -1066,6 +1067,7 @@ core99_reset_cpu(struct device_node *node, long param, long value)
break;
}
}
+ of_node_put(cpus);
if (np == NULL || reset_io == 0)
reset_io = dflt_reset_lines[param];
@@ -1095,7 +1097,7 @@ core99_usb_enable(struct device_node *node, long param, long value)
macio->type != macio_intrepid)
return -ENODEV;
- prop = get_property(node, "AAPL,clock-id", NULL);
+ prop = of_get_property(node, "AAPL,clock-id", NULL);
if (!prop)
return -ENODEV;
if (strncmp(prop, "usb0u048", 8) == 0)
@@ -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
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index bfc4829162f1..5430e146b3e9 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -491,7 +491,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
* on all i2c keywest nodes so far ... we would have to fallback
* to macio parsing if that wasn't the case
*/
- addrp = get_property(np, "AAPL,address", NULL);
+ addrp = of_get_property(np, "AAPL,address", NULL);
if (addrp == NULL) {
printk(KERN_ERR "low_i2c: Can't find address for %s\n",
np->full_name);
@@ -505,13 +505,13 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
host->timeout_timer.function = kw_i2c_timeout;
host->timeout_timer.data = (unsigned long)host;
- psteps = get_property(np, "AAPL,address-step", NULL);
+ psteps = of_get_property(np, "AAPL,address-step", NULL);
steps = psteps ? (*psteps) : 0x10;
for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
steps >>= 1;
/* Select interface rate */
host->speed = KW_I2C_MODE_25KHZ;
- prate = get_property(np, "AAPL,i2c-rate", NULL);
+ prate = of_get_property(np, "AAPL,i2c-rate", NULL);
if (prate) switch(*prate) {
case 100:
host->speed = KW_I2C_MODE_100KHZ;
@@ -619,7 +619,7 @@ static void __init kw_i2c_probe(void)
} else {
for (child = NULL;
(child = of_get_next_child(np, child)) != NULL;) {
- const u32 *reg = get_property(child,
+ const u32 *reg = of_get_property(child,
"reg", NULL);
if (reg == NULL)
continue;
@@ -905,7 +905,7 @@ static void __init smu_i2c_probe(void)
if (strcmp(busnode->type, "i2c") &&
strcmp(busnode->type, "i2c-bus"))
continue;
- reg = get_property(busnode, "reg", NULL);
+ reg = of_get_property(busnode, "reg", NULL);
if (reg == NULL)
continue;
@@ -950,7 +950,8 @@ struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node)
if (p == bus->busnode) {
if (prev && bus->flags & pmac_i2c_multibus) {
const u32 *reg;
- reg = get_property(prev, "reg", NULL);
+ reg = of_get_property(prev, "reg",
+ NULL);
if (!reg)
continue;
if (((*reg) >> 8) != bus->channel)
@@ -971,7 +972,7 @@ EXPORT_SYMBOL_GPL(pmac_i2c_find_bus);
u8 pmac_i2c_get_dev_addr(struct device_node *device)
{
- const u32 *reg = get_property(device, "reg", NULL);
+ const u32 *reg = of_get_property(device, "reg", NULL);
if (reg == NULL)
return 0;
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 6fbac308ded6..22c4ae4c6934 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -70,11 +70,11 @@ static int __init fixup_one_level_bus_range(struct device_node *node, int higher
int len;
/* For PCI<->PCI bridges or CardBus bridges, we go down */
- class_code = get_property(node, "class-code", NULL);
+ class_code = of_get_property(node, "class-code", NULL);
if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
continue;
- bus_range = get_property(node, "bus-range", &len);
+ bus_range = of_get_property(node, "bus-range", &len);
if (bus_range != NULL && len > 2 * sizeof(int)) {
if (bus_range[1] > higher)
higher = bus_range[1];
@@ -100,7 +100,7 @@ static void __init fixup_bus_range(struct device_node *bridge)
if (prop == NULL || prop->length < 2 * sizeof(int))
return;
- bus_range = (int *)prop->value;
+ bus_range = prop->value;
bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
}
@@ -246,8 +246,8 @@ static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
if (np == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
- vendor = get_property(np, "vendor-id", NULL);
- device = get_property(np, "device-id", NULL);
+ vendor = of_get_property(np, "vendor-id", NULL);
+ device = of_get_property(np, "device-id", NULL);
if (vendor == NULL || device == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -622,13 +622,14 @@ static void __init init_p2pbridge(void)
/* XXX it would be better here to identify the specific
PCI-PCI bridge chip we have. */
- if ((p2pbridge = find_devices("pci-bridge")) == 0
+ p2pbridge = of_find_node_by_name(NULL, "pci-bridge");
+ if (p2pbridge == NULL
|| p2pbridge->parent == NULL
|| strcmp(p2pbridge->parent->name, "pci") != 0)
- return;
+ goto done;
if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
DBG("Can't find PCI infos for PCI<->PCI bridge\n");
- return;
+ goto done;
}
/* Warning: At this point, we have not yet renumbered all busses.
* So we must use OF walking to find out hose
@@ -636,16 +637,18 @@ static void __init init_p2pbridge(void)
hose = pci_find_hose_for_OF_device(p2pbridge);
if (!hose) {
DBG("Can't find hose for PCI<->PCI bridge\n");
- return;
+ goto done;
}
if (early_read_config_word(hose, bus, devfn,
PCI_BRIDGE_CONTROL, &val) < 0) {
printk(KERN_ERR "init_p2pbridge: couldn't read bridge"
" control\n");
- return;
+ goto done;
}
val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
+done:
+ of_node_put(p2pbridge);
}
static void __init init_second_ohare(void)
@@ -691,17 +694,17 @@ static void __init fixup_nec_usb2(void)
const u32 *prop;
u8 bus, devfn;
- prop = get_property(nec, "vendor-id", NULL);
+ prop = of_get_property(nec, "vendor-id", NULL);
if (prop == NULL)
continue;
if (0x1033 != *prop)
continue;
- prop = get_property(nec, "device-id", NULL);
+ prop = of_get_property(nec, "device-id", NULL);
if (prop == NULL)
continue;
if (0x0035 != *prop)
continue;
- prop = get_property(nec, "reg", NULL);
+ prop = of_get_property(nec, "reg", NULL);
if (prop == NULL)
continue;
devfn = (prop[0] >> 8) & 0xff;
@@ -909,7 +912,7 @@ static int __init add_bridge(struct device_node *dev)
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
/* Get bus range if any */
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
@@ -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
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
index 5c6c15c5f9a3..45d54b9ad9e0 100644
--- a/arch/powerpc/platforms/powermac/pfunc_base.c
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -114,7 +114,7 @@ static void macio_gpio_init_one(struct macio_chip *macio)
* we just create them all
*/
for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) {
- const u32 *reg = get_property(gp, "reg", NULL);
+ const u32 *reg = of_get_property(gp, "reg", NULL);
unsigned long offset;
if (reg == NULL)
continue;
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c
index 7651f278615a..85434231ae14 100644
--- a/arch/powerpc/platforms/powermac/pfunc_core.c
+++ b/arch/powerpc/platforms/powermac/pfunc_core.c
@@ -692,8 +692,7 @@ static int pmf_add_functions(struct pmf_device *dev, void *driverdata)
name = pp->name + plen;
if (strlen(name) && pp->length >= 12)
count += pmf_add_function_prop(dev, driverdata, name,
- (u32 *)pp->value,
- pp->length);
+ pp->value, pp->length);
}
return count;
}
@@ -821,7 +820,7 @@ struct pmf_function *__pmf_find_function(struct device_node *target,
* one, then we fallback to a direct call attempt
*/
snprintf(fname, 63, "platform-%s", name);
- prop = get_property(target, fname, NULL);
+ prop = of_get_property(target, fname, NULL);
if (prop == NULL)
goto find_it;
ph = *prop;
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 5e5c0e4add91..ae5097ac0378 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -482,14 +482,14 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,
pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
flags |= MPIC_WANTS_RESET;
- if (get_property(np, "big-endian", NULL))
+ if (of_get_property(np, "big-endian", NULL))
flags |= MPIC_BIG_ENDIAN;
/* Primary Big Endian means HT interrupts. This is quite dodgy
* but works until I find a better way
*/
if (master && (flags & MPIC_BIG_ENDIAN))
- flags |= MPIC_BROKEN_U3;
+ flags |= MPIC_U3_HT_IRQS;
mpic = mpic_alloc(np, r.start, flags, 0, 0, name);
if (mpic == NULL)
@@ -510,7 +510,7 @@ static int __init pmac_pic_probe_mpic(void)
for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
!= NULL;) {
if (master == NULL &&
- get_property(np, "interrupts", NULL) == NULL)
+ of_get_property(np, "interrupts", NULL) == NULL)
master = of_node_get(np);
else if (slave == NULL)
slave = of_node_get(np);
@@ -575,7 +575,7 @@ void __init pmac_pic_init(void)
#ifdef CONFIG_PPC32
if (!pmac_newworld)
flags |= OF_IMAP_OLDWORLD_MAC;
- if (get_property(of_chosen, "linux,bootx", NULL) != NULL)
+ if (of_get_property(of_chosen, "linux,bootx", NULL) != NULL)
flags |= OF_IMAP_NO_PHANDLE;
#endif /* CONFIG_PPC_32 */
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 651fa424ea06..b820cabac697 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -42,7 +42,6 @@
#include <linux/initrd.h>
#include <linux/vt_kern.h>
#include <linux/console.h>
-#include <linux/ide.h>
#include <linux/pci.h>
#include <linux/adb.h>
#include <linux/cuda.h>
@@ -135,12 +134,12 @@ static void pmac_show_cpuinfo(struct seq_file *m)
seq_printf(m, "machine\t\t: ");
np = of_find_node_by_path("/");
if (np != NULL) {
- pp = get_property(np, "model", NULL);
+ pp = of_get_property(np, "model", NULL);
if (pp != NULL)
seq_printf(m, "%s\n", pp);
else
seq_printf(m, "PowerMac\n");
- pp = get_property(np, "compatible", &plen);
+ pp = of_get_property(np, "compatible", &plen);
if (pp != NULL) {
seq_printf(m, "motherboard\t:");
while (plen > 0) {
@@ -164,11 +163,13 @@ static void pmac_show_cpuinfo(struct seq_file *m)
if (np == NULL)
np = of_find_node_by_type(NULL, "cache");
if (np != NULL) {
- const unsigned int *ic = get_property(np, "i-cache-size", NULL);
- const unsigned int *dc = get_property(np, "d-cache-size", NULL);
+ const unsigned int *ic =
+ of_get_property(np, "i-cache-size", NULL);
+ const unsigned int *dc =
+ of_get_property(np, "d-cache-size", NULL);
seq_printf(m, "L2 cache\t:");
has_l2cache = 1;
- if (get_property(np, "cache-unified", NULL) != 0 && dc) {
+ if (of_get_property(np, "cache-unified", NULL) != 0 && dc) {
seq_printf(m, " %dK unified", *dc / 1024);
} else {
if (ic)
@@ -177,7 +178,7 @@ static void pmac_show_cpuinfo(struct seq_file *m)
seq_printf(m, "%s %dK data",
(ic? " +": ""), *dc / 1024);
}
- pp = get_property(np, "ram-type", NULL);
+ pp = of_get_property(np, "ram-type", NULL);
if (pp)
seq_printf(m, " %s", pp);
seq_printf(m, "\n");
@@ -192,8 +193,11 @@ static void pmac_show_cpuinfo(struct seq_file *m)
#ifndef CONFIG_ADB_CUDA
int find_via_cuda(void)
{
- if (!find_devices("via-cuda"))
+ struct device_node *dn = of_find_node_by_name(NULL, "via-cuda");
+
+ if (!dn)
return 0;
+ of_node_put(dn);
printk("WARNING ! Your machine is CUDA-based but your kernel\n");
printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n");
return 0;
@@ -203,8 +207,11 @@ int find_via_cuda(void)
#ifndef CONFIG_ADB_PMU
int find_via_pmu(void)
{
- if (!find_devices("via-pmu"))
+ struct device_node *dn = of_find_node_by_name(NULL, "via-pmu");
+
+ if (!dn)
return 0;
+ of_node_put(dn);
printk("WARNING ! Your machine is PMU-based but your kernel\n");
printk(" wasn't compiled with CONFIG_ADB_PMU option !\n");
return 0;
@@ -224,6 +231,8 @@ static volatile u32 *sysctrl_regs;
static void __init ohare_init(void)
{
+ struct device_node *dn;
+
/* this area has the CPU identification register
and some registers used by smp boards */
sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
@@ -233,7 +242,9 @@ static void __init ohare_init(void)
* We assume that we have a PSX memory controller iff
* we have an ohare I/O controller.
*/
- if (find_devices("ohare") != NULL) {
+ dn = of_find_node_by_name(NULL, "ohare");
+ if (dn) {
+ of_node_put(dn);
if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
if (sysctrl_regs[4] & 0x10)
sysctrl_regs[4] |= 0x04000020;
@@ -249,18 +260,19 @@ static void __init l2cr_init(void)
{
/* Checks "l2cr-value" property in the registry */
if (cpu_has_feature(CPU_FTR_L2CR)) {
- struct device_node *np = find_devices("cpus");
+ struct device_node *np = of_find_node_by_name(NULL, "cpus");
if (np == 0)
- np = find_type_devices("cpu");
+ np = of_find_node_by_type(NULL, "cpu");
if (np != 0) {
const unsigned int *l2cr =
- get_property(np, "l2cr-value", NULL);
+ of_get_property(np, "l2cr-value", NULL);
if (l2cr != 0) {
ppc_override_l2cr = 1;
ppc_override_l2cr_value = *l2cr;
_set_L2CR(0);
_set_L2CR(ppc_override_l2cr_value);
}
+ of_node_put(np);
}
}
@@ -286,7 +298,7 @@ static void __init pmac_setup_arch(void)
loops_per_jiffy = 50000000 / HZ;
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu != NULL) {
- fp = get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != NULL) {
if (pvr >= 0x30 && pvr < 0x80)
/* PPC970 etc. */
@@ -303,7 +315,7 @@ static void __init pmac_setup_arch(void)
/* See if newworld or oldworld */
for (ic = NULL; (ic = of_find_all_nodes(ic)) != NULL; )
- if (get_property(ic, "interrupt-controller", NULL))
+ if (of_get_property(ic, "interrupt-controller", NULL))
break;
if (ic) {
pmac_newworld = 1;
@@ -341,8 +353,15 @@ static void __init pmac_setup_arch(void)
#ifdef CONFIG_SMP
/* Check for Core99 */
- if (find_devices("uni-n") || find_devices("u3") || find_devices("u4"))
+ ic = of_find_node_by_name(NULL, "uni-n");
+ if (!ic)
+ ic = of_find_node_by_name(NULL, "u3");
+ if (!ic)
+ ic = of_find_node_by_name(NULL, "u4");
+ if (ic) {
+ of_node_put(ic);
smp_ops = &core99_smp_ops;
+ }
#ifdef CONFIG_PPC32
else
smp_ops = &psurge_smp_ops;
@@ -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,
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index d73fb73802bb..6f32c4eca6e5 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -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);
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index a4173906e945..bf9da56942e8 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -297,49 +297,11 @@ int __init via_calibrate_decr(void)
}
#endif
-#ifdef CONFIG_PM
-/*
- * Reset the time after a sleep.
- */
-static int
-time_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
- static unsigned long time_diff;
- unsigned long flags;
- unsigned long seq;
- struct timespec tv;
-
- switch (when) {
- case PBOOK_SLEEP_NOW:
- do {
- seq = read_seqbegin_irqsave(&xtime_lock, flags);
- time_diff = xtime.tv_sec - pmac_get_boot_time();
- } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
- break;
- case PBOOK_WAKE:
- tv.tv_sec = pmac_get_boot_time() + time_diff;
- tv.tv_nsec = 0;
- do_settimeofday(&tv);
- break;
- }
- return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier time_sleep_notifier = {
- time_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PM */
-
/*
* Query the OF and get the decr frequency.
*/
void __init pmac_calibrate_decr(void)
{
-#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
- /* XXX why here? */
- pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif
-
generic_calibrate_decr();
#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index 379db05b0082..47de4d3fc167 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -81,7 +81,7 @@ void udbg_scc_init(int force_scc)
macio = of_get_parent(escc);
if (macio == NULL)
goto bail;
- path = get_property(of_chosen, "linux,stdout-path", NULL);
+ path = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (path != NULL)
stdout = of_find_node_by_path(path);
for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) {
@@ -96,13 +96,13 @@ void udbg_scc_init(int force_scc)
ch = ch_def ? ch_def : ch_a;
/* Get address within mac-io ASIC */
- reg = get_property(escc, "reg", NULL);
+ reg = of_get_property(escc, "reg", NULL);
if (reg == NULL)
goto bail;
addr = reg[0];
/* Get address of mac-io PCI itself */
- reg = get_property(macio, "assigned-addresses", NULL);
+ reg = of_get_property(macio, "assigned-addresses", NULL);
if (reg == NULL)
goto bail;
addr += reg[2];
diff --git a/arch/powerpc/platforms/prep/Kconfig b/arch/powerpc/platforms/prep/Kconfig
index 673ac47a1626..29d411279b0c 100644
--- a/arch/powerpc/platforms/prep/Kconfig
+++ b/arch/powerpc/platforms/prep/Kconfig
@@ -1,3 +1,12 @@
+config PPC_PREP
+ bool "PowerPC Reference Platform (PReP) based machines"
+ depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
+ select MPIC
+ select PPC_I8259
+ select PPC_INDIRECT_PCI
+ select PPC_UDBG_16550
+ select PPC_NATIVE
+ default n
config PREP_RESIDUAL
bool "Support for PReP Residual Data"
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 1a481a60a883..40f0008af4d1 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -1,3 +1,19 @@
+config PPC_PS3
+ bool "Sony PS3 (incomplete)"
+ depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_CELL
+ select USB_ARCH_HAS_OHCI
+ select USB_OHCI_LITTLE_ENDIAN
+ select USB_OHCI_BIG_ENDIAN_MMIO
+ select USB_ARCH_HAS_EHCI
+ select USB_EHCI_BIG_ENDIAN_MMIO
+ help
+ This option enables support for the Sony PS3 game console
+ and other platforms using the PS3 hypervisor.
+ Support for this platform is not yet complete, so
+ enabling this will not result in a bootable kernel on a
+ PS3 system.
+
menu "PS3 Platform Options"
depends on PPC_PS3
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index e12e59fea13a..ea60c451cf87 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -39,7 +39,7 @@ static unsigned long htab_addr;
static unsigned char *bolttab;
static unsigned char *inusetab;
-static spinlock_t ps3_bolttab_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ps3_bolttab_lock);
#define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \
_debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__)
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index a57032cf6f1b..16e4e401b820 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -1,3 +1,13 @@
+config PPC_PSERIES
+ depends on PPC_MULTIPLATFORM && PPC64
+ bool "IBM pSeries & new (POWER5-based) iSeries"
+ select MPIC
+ select PPC_I8259
+ select PPC_RTAS
+ select RTAS_ERROR_LOGGING
+ select PPC_UDBG_16550
+ select PPC_NATIVE
+ default y
config PPC_SPLPAR
depends on PPC_PSERIES
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 2dfd05095a25..90235d598751 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -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
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 6cedbc002e0f..48fbd442e9df 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -74,7 +74,10 @@
* is broken and panic. This sets the threshold for how many read
* attempts we allow before panicking.
*/
-#define EEH_MAX_FAILS 100000
+#define EEH_MAX_FAILS 2100000
+
+/* Time to wait for a PCI slot to retport status, in milliseconds */
+#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
/* RTAS tokens */
static int ibm_set_eeh_option;
@@ -83,6 +86,7 @@ static int ibm_read_slot_reset_state;
static int ibm_read_slot_reset_state2;
static int ibm_slot_error_detail;
static int ibm_get_config_addr_info;
+static int ibm_get_config_addr_info2;
static int ibm_configure_bridge;
int eeh_subsystem_enabled;
@@ -168,6 +172,55 @@ static int read_slot_reset_state(struct pci_dn *pdn, int rets[])
}
/**
+ * eeh_wait_for_slot_status - returns error status of slot
+ * @pdn pci device node
+ * @max_wait_msecs maximum number to millisecs to wait
+ *
+ * Return negative value if a permanent error, else return
+ * Partition Endpoint (PE) status value.
+ *
+ * If @max_wait_msecs is positive, then this routine will
+ * sleep until a valid status can be obtained, or until
+ * the max allowed wait time is exceeded, in which case
+ * a -2 is returned.
+ */
+int
+eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs)
+{
+ int rc;
+ int rets[3];
+ int mwait;
+
+ while (1) {
+ rc = read_slot_reset_state(pdn, rets);
+ if (rc) return rc;
+ if (rets[1] == 0) return -1; /* EEH is not supported */
+
+ if (rets[0] != 5) return rets[0]; /* return actual status */
+
+ if (rets[2] == 0) return -1; /* permanently unavailable */
+
+ if (max_wait_msecs <= 0) return -1;
+
+ mwait = rets[2];
+ if (mwait <= 0) {
+ printk (KERN_WARNING
+ "EEH: Firmware returned bad wait value=%d\n", mwait);
+ mwait = 1000;
+ } else if (mwait > 300*1000) {
+ printk (KERN_WARNING
+ "EEH: Firmware is taking too long, time=%d\n", mwait);
+ mwait = 300*1000;
+ }
+ max_wait_msecs -= mwait;
+ msleep (mwait);
+ }
+
+ printk(KERN_WARNING "EEH: Timed out waiting for slot status\n");
+ return -2;
+}
+
+/**
* eeh_token_to_phys - convert EEH address token to phys address
* @token i/o token, should be address in the form 0xA....
*/
@@ -229,7 +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:
@@ -458,38 +505,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)
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index a4c0bf84ef2e..3170e003f76a 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -158,7 +158,8 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
return;
rc = driver->err_handler->slot_reset(dev);
- if (*res == PCI_ERS_RESULT_NONE) *res = rc;
+ if ((*res == PCI_ERS_RESULT_NONE) ||
+ (*res == PCI_ERS_RESULT_RECOVERED)) *res = rc;
if (*res == PCI_ERS_RESULT_DISCONNECT &&
rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
}
@@ -248,6 +249,7 @@ static void eeh_report_failure(struct pci_dev *dev, void *userdata)
static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
{
+ struct device_node *dn;
int cnt, rc;
/* pcibios will clear the counter; save the value */
@@ -263,23 +265,20 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
if (rc)
return rc;
- /* New-style config addrs might be shared across multiple devices,
- * Walk over all functions on this device */
- if (pe_dn->eeh_pe_config_addr) {
- struct device_node *pe = pe_dn->node;
- pe = pe->parent->child;
- while (pe) {
- struct pci_dn *ppe = PCI_DN(pe);
- if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
- rtas_configure_bridge(ppe);
- eeh_restore_bars(ppe);
- }
- pe = pe->sibling;
+ /* Walk over all functions on this device. */
+ dn = pe_dn->node;
+ if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+ dn = dn->parent->child;
+
+ while (dn) {
+ struct pci_dn *ppe = PCI_DN(dn);
+ /* On Power4, always true because eeh_pe_config_addr=0 */
+ if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
+ rtas_configure_bridge(ppe);
+ eeh_restore_bars(ppe);
}
- } else {
- rtas_configure_bridge(pe_dn);
- eeh_restore_bars(pe_dn);
- }
+ dn = dn->sibling;
+ }
/* Give the system 5 seconds to finish running the user-space
* hotplug shutdown scripts, e.g. ifdown for ethernet. Yes,
@@ -299,7 +298,7 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
/* The longest amount of time to wait for a pci device
* to come back on line, in seconds.
*/
-#define MAX_WAIT_FOR_RECOVERY 15
+#define MAX_WAIT_FOR_RECOVERY 150
struct pci_dn * handle_eeh_events (struct eeh_event *event)
{
@@ -315,14 +314,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
if (!frozen_dn) {
- location = get_property(event->dn, "ibm,loc-code", NULL);
+ location = of_get_property(event->dn, "ibm,loc-code", NULL);
location = location ? location : "unknown";
printk(KERN_ERR "EEH: Error: Cannot find partition endpoint "
"for location=%s pci addr=%s\n",
location, pci_name(event->dev));
return NULL;
}
- location = get_property(frozen_dn, "ibm,loc-code", NULL);
+ location = of_get_property(frozen_dn, "ibm,loc-code", NULL);
location = location ? location : "unknown";
/* There are two different styles for coming up with the PE.
@@ -341,13 +340,6 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
return NULL;
}
-#if 0
- /* We may get "permanent failure" messages on empty slots.
- * These are false alarms. Empty slots have no child dn. */
- if ((event->state == pci_channel_io_perm_failure) && (frozen_device == NULL))
- return;
-#endif
-
frozen_pdn = PCI_DN(frozen_dn);
frozen_pdn->eeh_freeze_count++;
@@ -362,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);
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c
index 49037edf7d39..ddb80f5d850b 100644
--- a/arch/powerpc/platforms/pseries/eeh_event.c
+++ b/arch/powerpc/platforms/pseries/eeh_event.c
@@ -118,9 +118,7 @@ static void eeh_thread_launcher(struct work_struct *dummy)
* (from a workqueue).
*/
int eeh_send_failure_event (struct device_node *dn,
- struct pci_dev *dev,
- enum pci_channel_state state,
- int time_unavail)
+ struct pci_dev *dev)
{
unsigned long flags;
struct eeh_event *event;
@@ -128,7 +126,7 @@ int eeh_send_failure_event (struct device_node *dn,
if (!mem_init_done) {
printk(KERN_ERR "EEH: event during early boot not handled\n");
- location = get_property(dn, "ibm,loc-code", NULL);
+ location = of_get_property(dn, "ibm,loc-code", NULL);
printk(KERN_ERR "EEH: device node = %s\n", dn->full_name);
printk(KERN_ERR "EEH: PCI location = %s\n", location);
return 1;
@@ -144,8 +142,6 @@ int eeh_send_failure_event (struct device_node *dn,
event->dn = dn;
event->dev = dev;
- event->state = state;
- event->time_unavail = time_unavail;
/* We may or may not be called in an interrupt context */
spin_lock_irqsave(&eeh_eventlist_lock, flags);
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 90522e3c9d46..29bf83bfb1f0 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -80,7 +80,7 @@ void __init fw_feature_init(void)
goto out;
}
- hypertas = get_property(dn, "ibm,hypertas-functions", &len);
+ hypertas = of_get_property(dn, "ibm,hypertas-functions", &len);
if (hypertas == NULL)
goto out;
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index f460b9cbfd46..9711eb0d5496 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -143,7 +143,7 @@ static int pseries_add_processor(struct device_node *np)
int err = -ENOSPC, len, nthreads, i;
const u32 *intserv;
- intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+ intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
if (!intserv)
return 0;
@@ -203,7 +203,7 @@ static void pseries_remove_processor(struct device_node *np)
int len, nthreads, i;
const u32 *intserv;
- intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+ intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
if (!intserv)
return;
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index e6653a868b91..66665c82415c 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -242,6 +242,7 @@ static unsigned long tce_get_pSeriesLP(struct iommu_table *tbl, long tcenum)
return tce_ret;
}
+#ifdef CONFIG_PCI
static void iommu_table_setparms(struct pci_controller *phb,
struct device_node *dn,
struct iommu_table *tbl)
@@ -252,8 +253,8 @@ static void iommu_table_setparms(struct pci_controller *phb,
node = (struct device_node *)phb->arch_data;
- basep = get_property(node, "linux,tce-base", NULL);
- sizep = get_property(node, "linux,tce-size", NULL);
+ basep = of_get_property(node, "linux,tce-base", NULL);
+ sizep = of_get_property(node, "linux,tce-size", NULL);
if (basep == NULL || sizep == NULL) {
printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has "
"missing tce entries !\n", dn->full_name);
@@ -403,7 +404,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
/* Find nearest ibm,dma-window, walking up the device tree */
for (pdn = dn; pdn != NULL; pdn = pdn->parent) {
- dma_window = get_property(pdn, "ibm,dma-window", NULL);
+ dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
if (dma_window != NULL)
break;
}
@@ -478,29 +479,6 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
pci_name(dev));
}
-static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
-{
- int err = NOTIFY_OK;
- struct device_node *np = node;
- struct pci_dn *pci = PCI_DN(np);
-
- switch (action) {
- case PSERIES_RECONFIG_REMOVE:
- if (pci && pci->iommu_table &&
- get_property(np, "ibm,dma-window", NULL))
- iommu_free_table(np);
- break;
- default:
- err = NOTIFY_DONE;
- break;
- }
- return err;
-}
-
-static struct notifier_block iommu_reconfig_nb = {
- .notifier_call = iommu_reconfig_notifier,
-};
-
static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
{
struct device_node *pdn, *dn;
@@ -521,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);
}
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 843ee9643211..3a70e8ad7bc8 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -209,13 +209,13 @@ void __init find_udbg_vterm(void)
/* find the boot console from /chosen/stdout */
if (!of_chosen)
return;
- name = get_property(of_chosen, "linux,stdout-path", NULL);
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (name == NULL)
return;
stdout_node = of_find_node_by_path(name);
if (!stdout_node)
return;
- name = get_property(stdout_node, "name", NULL);
+ name = of_get_property(stdout_node, "name", NULL);
if (!name) {
printk(KERN_WARNING "stdout node missing 'name' property!\n");
goto out;
@@ -226,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];
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 64163cecdf93..f68903e15bd5 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -130,7 +130,7 @@ int __init pSeries_nvram_init(void)
if (nvram == NULL)
return -ENODEV;
- nbytes_p = get_property(nvram, "#bytes", &proplen);
+ nbytes_p = of_get_property(nvram, "#bytes", &proplen);
if (nbytes_p == NULL || proplen != sizeof(unsigned int))
return -EIO;
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index fa59124ce3fe..2c6ded29f73d 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/string.h>
+#include <asm/eeh.h>
#include <asm/pci-bridge.h>
#include <asm/prom.h>
#include <asm/ppc-pci.h>
@@ -39,7 +40,7 @@ void pcibios_name_device(struct pci_dev *dev)
*/
dn = pci_device_to_OF_node(dev);
if (dn) {
- char *loc_code = get_property(dn, "ibm,loc-code", 0);
+ const char *loc_code = of_get_property(dn, "ibm,loc-code", 0);
if (loc_code) {
int loc_len = strlen(loc_code);
if (loc_len < sizeof(dev->dev.name)) {
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index ac56b868913a..fdc1a369f767 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -29,6 +29,7 @@
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
#include <asm/firmware.h>
+#include <asm/eeh.h>
static struct pci_bus *
find_bus_among_children(struct pci_bus *bus,
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index edc038873113..53aa04101ced 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -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++) {
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index 77d0937d5c07..9797b10b2935 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -363,7 +363,7 @@ static int get_eventscan_parms(void)
node = of_find_node_by_path("/rtas");
- ip = get_property(node, "rtas-event-scan-rate", NULL);
+ ip = of_get_property(node, "rtas-event-scan-rate", NULL);
if (ip == NULL) {
printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n");
of_node_put(node);
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 34aff47b1f55..33eec2822c66 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -65,6 +65,7 @@
#include <asm/udbg.h>
#include <asm/smp.h>
#include <asm/firmware.h>
+#include <asm/eeh.h>
#include "plpar_wrappers.h"
#include "pseries.h"
@@ -92,7 +93,7 @@ static void pSeries_show_cpuinfo(struct seq_file *m)
root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
seq_printf(m, "machine\t\t: CHRP %s\n", model);
of_node_put(root);
}
@@ -138,8 +139,8 @@ static void __init pseries_mpic_init_IRQ(void)
struct mpic *mpic;
np = of_find_node_by_path("/");
- naddr = prom_n_addr_cells(np);
- opprop = get_property(np, "platform-open-pic", &opplen);
+ naddr = of_n_addr_cells(np);
+ opprop = of_get_property(np, "platform-open-pic", &opplen);
if (opprop != 0) {
openpic_addr = of_read_number(opprop, naddr);
printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
@@ -188,11 +189,11 @@ static void __init pseries_mpic_init_IRQ(void)
break;
if (strcmp(np->name, "pci") != 0)
continue;
- addrp = get_property(np, "8259-interrupt-acknowledge",
+ addrp = of_get_property(np, "8259-interrupt-acknowledge",
NULL);
if (addrp == NULL)
continue;
- naddr = prom_n_addr_cells(np);
+ naddr = of_n_addr_cells(np);
intack = addrp[naddr-1];
if (naddr > 1)
intack |= ((unsigned long)addrp[naddr-2]) << 32;
@@ -225,7 +226,7 @@ static void __init pseries_discover_pic(void)
for (np = NULL; (np = of_find_node_by_name(np,
"interrupt-controller"));) {
- typep = get_property(np, "compatible", NULL);
+ typep = of_get_property(np, "compatible", NULL);
if (strstr(typep, "open-pic")) {
pSeries_mpic_node = of_node_get(np);
ppc_md.init_IRQ = pseries_mpic_init_IRQ;
@@ -334,32 +335,6 @@ static void __init pSeries_init_early(void)
DBG(" <- pSeries_init_early()\n");
}
-
-static int pSeries_check_legacy_ioport(unsigned int baseport)
-{
- struct device_node *np;
-
-#define I8042_DATA_REG 0x60
-#define FDC_BASE 0x3f0
-
-
- switch(baseport) {
- case I8042_DATA_REG:
- np = of_find_node_by_type(NULL, "8042");
- if (np == NULL)
- return -ENODEV;
- of_node_put(np);
- break;
- case FDC_BASE:
- np = of_find_node_by_type(NULL, "fdc");
- if (np == NULL)
- return -ENODEV;
- of_node_put(np);
- break;
- }
- return 0;
-}
-
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
@@ -514,6 +489,10 @@ void pSeries_power_off(void)
for (;;);
}
+#ifndef CONFIG_PCI
+void pSeries_final_fixup(void) { }
+#endif
+
define_machine(pseries) {
.name = "pSeries",
.probe = pSeries_probe,
@@ -532,7 +511,6 @@ define_machine(pseries) {
.set_rtc_time = rtas_set_rtc_time,
.calibrate_decr = generic_calibrate_decr,
.progress = rtas_progress,
- .check_legacy_ioport = pSeries_check_legacy_ioport,
.system_reset_exception = pSeries_system_reset_exception,
.machine_check_exception = pSeries_machine_check_exception,
};
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 81d172d65038..896cbf340c42 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -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;
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 26ca3ffbc1de..e96ca9618dbb 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -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
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index 1488535b0e13..336186dd7f10 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -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);
}
diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c
index 1fc5819e7d18..574b6ef44e0b 100644
--- a/arch/powerpc/sysdev/dcr.c
+++ b/arch/powerpc/sysdev/dcr.c
@@ -26,7 +26,7 @@
unsigned int dcr_resource_start(struct device_node *np, unsigned int index)
{
unsigned int ds;
- const u32 *dr = get_property(np, "dcr-reg", &ds);
+ const u32 *dr = of_get_property(np, "dcr-reg", &ds);
if (dr == NULL || ds & 1 || index >= (ds / 8))
return 0;
@@ -37,7 +37,7 @@ unsigned int dcr_resource_start(struct device_node *np, unsigned int index)
unsigned int dcr_resource_len(struct device_node *np, unsigned int index)
{
unsigned int ds;
- const u32 *dr = get_property(np, "dcr-reg", &ds);
+ const u32 *dr = of_get_property(np, "dcr-reg", &ds);
if (dr == NULL || ds & 1 || index >= (ds / 8))
return 0;
@@ -53,9 +53,9 @@ static struct device_node * find_dcr_parent(struct device_node * node)
const u32 *p;
for (par = of_node_get(node); par;) {
- if (get_property(par, "dcr-controller", NULL))
+ if (of_get_property(par, "dcr-controller", NULL))
break;
- p = get_property(par, "dcr-parent", NULL);
+ p = of_get_property(par, "dcr-parent", NULL);
tmp = par;
if (p == NULL)
par = of_get_parent(par);
@@ -80,13 +80,13 @@ u64 of_translate_dcr_address(struct device_node *dev,
return OF_BAD_ADDR;
/* Stride is not properly defined yet, default to 0x10 for Axon */
- p = get_property(dp, "dcr-mmio-stride", NULL);
+ p = of_get_property(dp, "dcr-mmio-stride", NULL);
stride = (p == NULL) ? 0x10 : *p;
/* XXX FIXME: Which property name is to use of the 2 following ? */
- p = get_property(dp, "dcr-mmio-range", NULL);
+ p = of_get_property(dp, "dcr-mmio-range", NULL);
if (p == NULL)
- p = get_property(dp, "dcr-mmio-space", NULL);
+ p = of_get_property(dp, "dcr-mmio-space", NULL);
if (p == NULL)
return OF_BAD_ADDR;
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_pcie.c b/arch/powerpc/sysdev/fsl_pcie.c
index a2f4f730213e..041c07e8b665 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_pcie.c
+++ b/arch/powerpc/sysdev/fsl_pcie.c
@@ -24,8 +24,6 @@
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
-#include "mpc86xx.h"
-
#define PCI_CFG_OUT out_be32
/* ERRATA PCI-Ex 14 PCIE Controller timeout */
diff --git a/arch/powerpc/sysdev/fsl_pcie.h b/arch/powerpc/sysdev/fsl_pcie.h
new file mode 100644
index 000000000000..8d9779c84bea
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_pcie.h
@@ -0,0 +1,94 @@
+/*
+ * MPC85xx/86xx PCI Express structure define
+ *
+ * Copyright 2007 Freescale Semiconductor, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __POWERPC_FSL_PCIE_H
+#define __POWERPC_FSL_PCIE_H
+
+/* PCIE Express IO block registers in 85xx/86xx */
+
+struct ccsr_pex {
+ __be32 __iomem pex_config_addr; /* 0x.000 - PCI Express Configuration Address Register */
+ __be32 __iomem pex_config_data; /* 0x.004 - PCI Express Configuration Data Register */
+ u8 __iomem res1[4];
+ __be32 __iomem pex_otb_cpl_tor; /* 0x.00c - PCI Express Outbound completion timeout register */
+ __be32 __iomem pex_conf_tor; /* 0x.010 - PCI Express configuration timeout register */
+ u8 __iomem res2[12];
+ __be32 __iomem pex_pme_mes_dr; /* 0x.020 - PCI Express PME and message detect register */
+ __be32 __iomem pex_pme_mes_disr; /* 0x.024 - PCI Express PME and message disable register */
+ __be32 __iomem pex_pme_mes_ier; /* 0x.028 - PCI Express PME and message interrupt enable register */
+ __be32 __iomem pex_pmcr; /* 0x.02c - PCI Express power management command register */
+ u8 __iomem res3[3024];
+ __be32 __iomem pexotar0; /* 0x.c00 - PCI Express outbound translation address register 0 */
+ __be32 __iomem pexotear0; /* 0x.c04 - PCI Express outbound translation extended address register 0*/
+ u8 __iomem res4[8];
+ __be32 __iomem pexowar0; /* 0x.c10 - PCI Express outbound window attributes register 0*/
+ u8 __iomem res5[12];
+ __be32 __iomem pexotar1; /* 0x.c20 - PCI Express outbound translation address register 1 */
+ __be32 __iomem pexotear1; /* 0x.c24 - PCI Express outbound translation extended address register 1*/
+ __be32 __iomem pexowbar1; /* 0x.c28 - PCI Express outbound window base address register 1*/
+ u8 __iomem res6[4];
+ __be32 __iomem pexowar1; /* 0x.c30 - PCI Express outbound window attributes register 1*/
+ u8 __iomem res7[12];
+ __be32 __iomem pexotar2; /* 0x.c40 - PCI Express outbound translation address register 2 */
+ __be32 __iomem pexotear2; /* 0x.c44 - PCI Express outbound translation extended address register 2*/
+ __be32 __iomem pexowbar2; /* 0x.c48 - PCI Express outbound window base address register 2*/
+ u8 __iomem res8[4];
+ __be32 __iomem pexowar2; /* 0x.c50 - PCI Express outbound window attributes register 2*/
+ u8 __iomem res9[12];
+ __be32 __iomem pexotar3; /* 0x.c60 - PCI Express outbound translation address register 3 */
+ __be32 __iomem pexotear3; /* 0x.c64 - PCI Express outbound translation extended address register 3*/
+ __be32 __iomem pexowbar3; /* 0x.c68 - PCI Express outbound window base address register 3*/
+ u8 __iomem res10[4];
+ __be32 __iomem pexowar3; /* 0x.c70 - PCI Express outbound window attributes register 3*/
+ u8 __iomem res11[12];
+ __be32 __iomem pexotar4; /* 0x.c80 - PCI Express outbound translation address register 4 */
+ __be32 __iomem pexotear4; /* 0x.c84 - PCI Express outbound translation extended address register 4*/
+ __be32 __iomem pexowbar4; /* 0x.c88 - PCI Express outbound window base address register 4*/
+ u8 __iomem res12[4];
+ __be32 __iomem pexowar4; /* 0x.c90 - PCI Express outbound window attributes register 4*/
+ u8 __iomem res13[12];
+ u8 __iomem res14[256];
+ __be32 __iomem pexitar3; /* 0x.da0 - PCI Express inbound translation address register 3 */
+ u8 __iomem res15[4];
+ __be32 __iomem pexiwbar3; /* 0x.da8 - PCI Express inbound window base address register 3 */
+ __be32 __iomem pexiwbear3; /* 0x.dac - PCI Express inbound window base extended address register 3 */
+ __be32 __iomem pexiwar3; /* 0x.db0 - PCI Express inbound window attributes register 3 */
+ u8 __iomem res16[12];
+ __be32 __iomem pexitar2; /* 0x.dc0 - PCI Express inbound translation address register 2 */
+ u8 __iomem res17[4];
+ __be32 __iomem pexiwbar2; /* 0x.dc8 - PCI Express inbound window base address register 2 */
+ __be32 __iomem pexiwbear2; /* 0x.dcc - PCI Express inbound window base extended address register 2 */
+ __be32 __iomem pexiwar2; /* 0x.dd0 - PCI Express inbound window attributes register 2 */
+ u8 __iomem res18[12];
+ __be32 __iomem pexitar1; /* 0x.de0 - PCI Express inbound translation address register 2 */
+ u8 __iomem res19[4];
+ __be32 __iomem pexiwbar1; /* 0x.de8 - PCI Express inbound window base address register 2 */
+ __be32 __iomem pexiwbear1; /* 0x.dec - PCI Express inbound window base extended address register 2 */
+ __be32 __iomem pexiwar1; /* 0x.df0 - PCI Express inbound window attributes register 2 */
+ u8 __iomem res20[12];
+ __be32 __iomem pex_err_dr; /* 0x.e00 - PCI Express error detect register */
+ u8 __iomem res21[4];
+ __be32 __iomem pex_err_en; /* 0x.e08 - PCI Express error interrupt enable register */
+ u8 __iomem res22[4];
+ __be32 __iomem pex_err_disr; /* 0x.e10 - PCI Express error disable register */
+ u8 __iomem res23[12];
+ __be32 __iomem pex_err_cap_stat; /* 0x.e20 - PCI Express error capture status register */
+ u8 __iomem res24[4];
+ __be32 __iomem pex_err_cap_r0; /* 0x.e28 - PCI Express error capture register 0 */
+ __be32 __iomem pex_err_cap_r1; /* 0x.e2c - PCI Express error capture register 0 */
+ __be32 __iomem pex_err_cap_r2; /* 0x.e30 - PCI Express error capture register 0 */
+ __be32 __iomem pex_err_cap_r3; /* 0x.e34 - PCI Express error capture register 0 */
+};
+
+#endif /* __POWERPC_FSL_PCIE_H */
+#endif /* __KERNEL__ */
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index d20f02927f72..8a123c71449f 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -52,7 +52,7 @@ phys_addr_t get_immrbase(void)
soc = of_find_node_by_type(NULL, "soc");
if (soc) {
unsigned int size;
- const void *prop = get_property(soc, "reg", &size);
+ const void *prop = of_get_property(soc, "reg", &size);
if (prop)
immrbase = of_translate_address(soc, prop);
@@ -78,8 +78,8 @@ u32 get_brgfreq(void)
node = of_find_node_by_type(NULL, "cpm");
if (node) {
unsigned int size;
- const unsigned int *prop = get_property(node, "brg-frequency",
- &size);
+ const unsigned int *prop = of_get_property(node,
+ "brg-frequency", &size);
if (prop)
brgfreq = *prop;
@@ -103,8 +103,8 @@ u32 get_baudrate(void)
node = of_find_node_by_type(NULL, "serial");
if (node) {
unsigned int size;
- const unsigned int *prop = get_property(node, "current-speed",
- &size);
+ const unsigned int *prop = of_get_property(node,
+ "current-speed", &size);
if (prop)
fs_baudrate = *prop;
@@ -153,7 +153,8 @@ static int __init gfar_mdio_of_init(void)
while ((child = of_get_next_child(np, child)) != NULL) {
int irq = irq_of_parse_and_map(child, 0);
if (irq != NO_IRQ) {
- const u32 *id = get_property(child, "reg", NULL);
+ const u32 *id = of_get_property(child,
+ "reg", NULL);
mdio_data.irq[*id] = irq;
}
}
@@ -209,7 +210,7 @@ static int __init gfar_of_init(void)
of_irq_to_resource(np, 0, &r[1]);
- model = get_property(np, "model", NULL);
+ model = of_get_property(np, "model", NULL);
/* If we aren't the FEC we have multiple interrupts */
if (model && strcasecmp(model, "FEC")) {
@@ -253,7 +254,7 @@ static int __init gfar_of_init(void)
FSL_GIANFAR_DEV_HAS_VLAN |
FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
- ph = get_property(np, "phy-handle", NULL);
+ ph = of_get_property(np, "phy-handle", NULL);
phy = of_find_node_by_phandle(*ph);
if (phy == NULL) {
@@ -263,7 +264,7 @@ static int __init gfar_of_init(void)
mdio = of_get_parent(phy);
- id = get_property(phy, "reg", NULL);
+ id = of_get_property(phy, "reg", NULL);
ret = of_address_to_resource(mdio, 0, &res);
if (ret) {
of_node_put(phy);
@@ -325,11 +326,11 @@ static int __init fsl_i2c_of_init(void)
}
i2c_data.device_flags = 0;
- flags = get_property(np, "dfsrr", NULL);
+ flags = of_get_property(np, "dfsrr", NULL);
if (flags)
i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
- flags = get_property(np, "fsl5200-clocking", NULL);
+ flags = of_get_property(np, "fsl5200-clocking", NULL);
if (flags)
i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
@@ -374,7 +375,7 @@ static int __init mpc83xx_wdt_init(void)
goto nosoc;
}
- freq = get_property(soc, "bus-frequency", NULL);
+ freq = of_get_property(soc, "bus-frequency", NULL);
if (!freq) {
ret = -ENODEV;
goto err;
@@ -466,15 +467,15 @@ static int __init fsl_usb_of_init(void)
usb_data.operating_mode = FSL_USB2_MPH_HOST;
- prop = get_property(np, "port0", NULL);
+ prop = of_get_property(np, "port0", NULL);
if (prop)
usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
- prop = get_property(np, "port1", NULL);
+ prop = of_get_property(np, "port1", NULL);
if (prop)
usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
- prop = get_property(np, "phy_type", NULL);
+ prop = of_get_property(np, "phy_type", NULL);
usb_data.phy_mode = determine_usb_phy(prop);
ret =
@@ -501,7 +502,7 @@ static int __init fsl_usb_of_init(void)
of_irq_to_resource(np, 0, &r[1]);
- prop = get_property(np, "dr_mode", NULL);
+ prop = of_get_property(np, "dr_mode", NULL);
if (!prop || !strcmp(prop, "host")) {
usb_data.operating_mode = FSL_USB2_DR_HOST;
@@ -538,7 +539,7 @@ static int __init fsl_usb_of_init(void)
goto err;
}
- prop = get_property(np, "phy_type", NULL);
+ prop = of_get_property(np, "phy_type", NULL);
usb_data.phy_mode = determine_usb_phy(prop);
if (usb_dev_dr_host) {
@@ -633,7 +634,7 @@ static int __init fs_enet_of_init(void)
goto err;
}
- model = get_property(np, "model", NULL);
+ model = of_get_property(np, "model", NULL);
if (model == NULL) {
ret = -ENODEV;
goto unreg;
@@ -643,7 +644,7 @@ static int __init fs_enet_of_init(void)
if (mac_addr)
memcpy(fs_enet_data.macaddr, mac_addr, 6);
- ph = get_property(np, "phy-handle", NULL);
+ ph = of_get_property(np, "phy-handle", NULL);
phy = of_find_node_by_phandle(*ph);
if (phy == NULL) {
@@ -651,12 +652,12 @@ static int __init fs_enet_of_init(void)
goto unreg;
}
- phy_addr = get_property(phy, "reg", NULL);
+ phy_addr = of_get_property(phy, "reg", NULL);
fs_enet_data.phy_addr = *phy_addr;
- phy_irq = get_property(phy, "interrupts", NULL);
+ phy_irq = of_get_property(phy, "interrupts", NULL);
- id = get_property(np, "device-id", NULL);
+ id = of_get_property(np, "device-id", NULL);
fs_enet_data.fs_no = *id;
strcpy(fs_enet_data.fs_type, model);
@@ -668,8 +669,10 @@ static int __init fs_enet_of_init(void)
goto unreg;
}
- fs_enet_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
- fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
+ fs_enet_data.clk_rx = *((u32 *)of_get_property(np,
+ "rx-clock", NULL));
+ fs_enet_data.clk_tx = *((u32 *)of_get_property(np,
+ "tx-clock", NULL));
if (strstr(model, "FCC")) {
int fcc_index = *id - 1;
@@ -690,7 +693,7 @@ static int __init fs_enet_of_init(void)
fs_enet_data.bus_id = (char*)&bus_id[(*id)];
fs_enet_data.init_ioports = init_fcc_ioports;
- mdio_bb_prop = get_property(phy, "bitbang", NULL);
+ mdio_bb_prop = of_get_property(phy, "bitbang", NULL);
if (mdio_bb_prop) {
struct platform_device *fs_enet_mdio_bb_dev;
struct fs_mii_bb_platform_info fs_enet_mdio_bb_data;
@@ -796,10 +799,10 @@ static int __init cpm_uart_of_init(void)
goto err;
}
- id = get_property(np, "device-id", NULL);
+ id = of_get_property(np, "device-id", NULL);
cpm_uart_data.fs_no = *id;
- model = (char*)get_property(np, "model", NULL);
+ model = of_get_property(np, "model", NULL);
strcpy(cpm_uart_data.fs_type, model);
cpm_uart_data.uart_clk = ppc_proc_freq;
@@ -808,8 +811,10 @@ static int __init cpm_uart_of_init(void)
cpm_uart_data.tx_buf_size = 32;
cpm_uart_data.rx_num_fifo = 4;
cpm_uart_data.rx_buf_size = 32;
- cpm_uart_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
- cpm_uart_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
+ cpm_uart_data.clk_rx = *((u32 *)of_get_property(np,
+ "rx-clock", NULL));
+ cpm_uart_data.clk_tx = *((u32 *)of_get_property(np,
+ "tx-clock", NULL));
ret =
platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
@@ -833,7 +838,7 @@ arch_initcall(cpm_uart_of_init);
#ifdef CONFIG_8xx
extern void init_scc_ioports(struct fs_platform_info*);
-extern int platform_device_skip(char *model, int id);
+extern int platform_device_skip(const char *model, int id);
static int __init fs_enet_mdio_of_init(void)
{
@@ -900,21 +905,22 @@ static int __init fs_enet_of_init(void)
struct resource r[4];
struct device_node *phy = NULL, *mdio = NULL;
struct fs_platform_info fs_enet_data;
- unsigned int *id, *phy_addr;
+ 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;
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index bcfb900481f8..0b84b7c775d8 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -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++) {
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c
index a5282011d39e..85a7c99c1003 100644
--- a/arch/powerpc/sysdev/pmi.c
+++ b/arch/powerpc/sysdev/pmi.c
@@ -33,7 +33,7 @@
#include <asm/of_platform.h>
#include <asm/io.h>
#include <asm/pmi.h>
-
+#include <asm/prom.h>
struct pmi_data {
struct list_head handler;
@@ -49,21 +49,6 @@ struct pmi_data {
};
-
-static void __iomem *of_iomap(struct device_node *np)
-{
- struct resource res;
-
- if (of_address_to_resource(np, 0, &res))
- return NULL;
-
- pr_debug("Resource start: 0x%lx\n", res.start);
- pr_debug("Resource end: 0x%lx\n", res.end);
-
- return ioremap(res.start, 1 + res.end - res.start);
-}
-
-
static int pmi_irq_handler(int irq, void *dev_id)
{
struct pmi_data *data;
@@ -118,6 +103,7 @@ out:
static struct of_device_id pmi_match[] = {
{ .type = "ibm,pmi", .name = "ibm,pmi" },
+ { .type = "ibm,pmi" },
{},
};
@@ -153,7 +139,7 @@ static int pmi_of_probe(struct of_device *dev,
goto out;
}
- data->pmi_reg = of_iomap(np);
+ data->pmi_reg = of_iomap(np, 0);
if (!data->pmi_reg) {
printk(KERN_ERR "pmi: invalid register address.\n");
rc = -EFAULT;
@@ -279,6 +265,9 @@ void pmi_register_handler(struct of_device *device,
struct pmi_data *data;
data = device->dev.driver_data;
+ if (!data)
+ return;
+
spin_lock(&data->handler_spinlock);
list_add_tail(&handler->node, &data->handler);
spin_unlock(&data->handler_spinlock);
@@ -289,10 +278,12 @@ void pmi_unregister_handler(struct of_device *device,
struct pmi_handler *handler)
{
struct pmi_data *data;
+ data = device->dev.driver_data;
- pr_debug("pmi: unregistering handler %p\n", handler);
+ if (!data)
+ return;
- data = device->dev.driver_data;
+ pr_debug("pmi: unregistering handler %p\n", handler);
spin_lock(&data->handler_spinlock);
list_del(&handler->node);
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig
index a725e80befa8..887739f3badc 100644
--- a/arch/powerpc/sysdev/qe_lib/Kconfig
+++ b/arch/powerpc/sysdev/qe_lib/Kconfig
@@ -2,11 +2,8 @@
# QE Communication options
#
-menu "QE Options"
- depends on QUICC_ENGINE
-
config UCC_SLOW
- bool "UCC Slow Protocols Support"
+ bool
default n
select UCC
help
@@ -14,10 +11,9 @@ config UCC_SLOW
protocols: UART, BISYNC, QMC
config UCC_FAST
- bool "UCC Fast Protocols Support"
+ bool
default n
select UCC
- select UCC_SLOW
help
This option provides qe_lib support to UCC fast
protocols: HDLC, Ethernet, ATM, transparent
@@ -26,5 +22,3 @@ config UCC
bool
default y if UCC_FAST || UCC_SLOW
-endmenu
-
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index 43f6cc9d7ea0..7f4c07543961 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -71,7 +71,7 @@ phys_addr_t get_qe_base(void)
qe = of_find_node_by_type(NULL, "qe");
if (qe) {
unsigned int size;
- const void *prop = get_property(qe, "reg", &size);
+ const void *prop = of_get_property(qe, "reg", &size);
qebase = of_translate_address(qe, prop);
of_node_put(qe);
};
@@ -158,7 +158,7 @@ unsigned int get_brg_clk(void)
qe = of_find_node_by_type(NULL, "qe");
if (qe) {
unsigned int size;
- const u32 *prop = get_property(qe, "brg-frequency", &size);
+ const u32 *prop = of_get_property(qe, "brg-frequency", &size);
brg_clk = *prop;
of_node_put(qe);
};
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
index 0afe6bfe3714..e32b45bf9ff5 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_io.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -53,7 +53,7 @@ int par_io_init(struct device_node *np)
return ret;
par_io = ioremap(res.start, res.end - res.start + 1);
- num_ports = get_property(np, "num-ports", NULL);
+ num_ports = of_get_property(np, "num-ports", NULL);
if (num_ports)
num_par_io_ports = *num_ports;
@@ -161,7 +161,7 @@ int par_io_of_config(struct device_node *np)
return -1;
}
- ph = get_property(np, "pio-handle", NULL);
+ ph = of_get_property(np, "pio-handle", NULL);
if (ph == 0) {
printk(KERN_ERR "pio-handle not available \n");
return -1;
@@ -169,7 +169,7 @@ int par_io_of_config(struct device_node *np)
pio = of_find_node_by_phandle(*ph);
- pio_map = get_property(pio, "pio-map", &pio_map_len);
+ pio_map = of_get_property(pio, "pio-map", &pio_map_len);
if (pio_map == NULL) {
printk(KERN_ERR "pio-map is not set! \n");
return -1;
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
index a457ac1c6639..66137bf2dfb0 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
@@ -210,6 +210,9 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
uf_regs = uccf->uf_regs;
uccf->p_ucce = (u32 *) & (uf_regs->ucce);
uccf->p_uccm = (u32 *) & (uf_regs->uccm);
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+ uccf->p_utodr = (u16 *) & (uf_regs->utodr);
+#endif
#ifdef STATISTICS
uccf->tx_frames = 0;
uccf->rx_frames = 0;
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
index 817df73ecf56..b930d686a4d1 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
@@ -187,7 +187,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
uccs->us_pram = qe_muram_addr(uccs->us_pram_offset);
/* Init Guemr register */
- if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->regs)))) {
+ if ((ret = ucc_init_guemr((struct ucc_common *) us_regs))) {
printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__);
ucc_slow_free(uccs);
return ret;
@@ -195,7 +195,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
/* Set UCC to slow type */
if ((ret = ucc_set_type(us_info->ucc_num,
- (struct ucc_common *) (us_info->regs),
+ (struct ucc_common *) us_regs,
UCC_SPEED_TYPE_SLOW))) {
printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__);
ucc_slow_free(uccs);
diff --git a/arch/powerpc/sysdev/timer.c b/arch/powerpc/sysdev/timer.c
new file mode 100644
index 000000000000..4a01748b4217
--- /dev/null
+++ b/arch/powerpc/sysdev/timer.c
@@ -0,0 +1,71 @@
+/*
+ * Common code to keep time when machine suspends.
+ *
+ * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ */
+
+#include <linux/time.h>
+#include <linux/sysdev.h>
+#include <asm/rtc.h>
+
+static unsigned long suspend_rtc_time;
+
+/*
+ * Reset the time after a sleep.
+ */
+static int timer_resume(struct sys_device *dev)
+{
+ struct timeval tv;
+ struct timespec ts;
+ struct rtc_time cur_rtc_tm;
+ unsigned long cur_rtc_time, diff;
+
+ /* get current RTC time and convert to seconds */
+ get_rtc_time(&cur_rtc_tm);
+ rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time);
+
+ diff = cur_rtc_time - suspend_rtc_time;
+
+ /* adjust time of day by seconds that elapsed while
+ * we were suspended */
+ do_gettimeofday(&tv);
+ ts.tv_sec = tv.tv_sec + diff;
+ ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC;
+ do_settimeofday(&ts);
+
+ return 0;
+}
+
+static int timer_suspend(struct sys_device *dev, pm_message_t state)
+{
+ struct rtc_time suspend_rtc_tm;
+ WARN_ON(!ppc_md.get_rtc_time);
+
+ get_rtc_time(&suspend_rtc_tm);
+ rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time);
+
+ return 0;
+}
+
+static struct sysdev_class timer_sysclass = {
+ .resume = timer_resume,
+ .suspend = timer_suspend,
+ set_kset_name("timer"),
+};
+
+static struct sys_device device_timer = {
+ .id = 0,
+ .cls = &timer_sysclass,
+};
+
+static int time_init_device(void)
+{
+ int error = sysdev_class_register(&timer_sysclass);
+ if (!error)
+ error = sysdev_register(&device_timer);
+ return error;
+}
+
+device_initcall(time_init_device);
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c
index 97f37ef4bbbf..337039ee51e6 100644
--- a/arch/powerpc/sysdev/tsi108_dev.c
+++ b/arch/powerpc/sysdev/tsi108_dev.c
@@ -48,7 +48,7 @@ phys_addr_t get_csrbase(void)
tsi = of_find_node_by_type(NULL, "tsi-bridge");
if (tsi) {
unsigned int size;
- const void *prop = get_property(tsi, "reg", &size);
+ const void *prop = of_get_property(tsi, "reg", &size);
tsi108_csr_base = of_translate_address(tsi, prop);
of_node_put(tsi);
};
@@ -77,10 +77,10 @@ static int __init tsi108_eth_of_init(void)
struct resource r[2];
struct device_node *phy;
hw_info tsi_eth_data;
- unsigned int *id;
- unsigned int *phy_id;
+ const unsigned int *id;
+ const unsigned int *phy_id;
const void *mac_addr;
- phandle *ph;
+ const phandle *ph;
memset(r, 0, sizeof(r));
memset(&tsi_eth_data, 0, sizeof(tsi_eth_data));
@@ -107,10 +107,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);
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index ae249c6bbbcf..58b9e7f8abf2 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -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
index 000000000000..968fb40af9dc
--- /dev/null
+++ b/arch/powerpc/sysdev/uic.c
@@ -0,0 +1,342 @@
+/*
+ * arch/powerpc/sysdev/uic.c
+ *
+ * IBM PowerPC 4xx Universal Interrupt Controller
+ *
+ * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/sysdev.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/dcr.h>
+
+#define NR_UIC_INTS 32
+
+#define UIC_SR 0x0
+#define UIC_ER 0x2
+#define UIC_CR 0x3
+#define UIC_PR 0x4
+#define UIC_TR 0x5
+#define UIC_MSR 0x6
+#define UIC_VR 0x7
+#define UIC_VCR 0x8
+
+#define uic_irq_to_hw(virq) (irq_map[virq].hwirq)
+
+struct uic *primary_uic;
+
+struct uic {
+ int index;
+ int dcrbase;
+
+ spinlock_t lock;
+
+ /* The remapper for this UIC */
+ struct irq_host *irqhost;
+
+ /* For secondary UICs, the cascade interrupt's irqaction */
+ struct irqaction cascade;
+
+ /* The device node of the interrupt controller */
+ struct device_node *of_node;
+};
+
+static void uic_unmask_irq(unsigned int virq)
+{
+ struct uic *uic = get_irq_chip_data(virq);
+ unsigned int src = uic_irq_to_hw(virq);
+ unsigned long flags;
+ u32 er;
+
+ spin_lock_irqsave(&uic->lock, flags);
+ er = mfdcr(uic->dcrbase + UIC_ER);
+ er |= 1 << (31 - src);
+ mtdcr(uic->dcrbase + UIC_ER, er);
+ spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static void uic_mask_irq(unsigned int virq)
+{
+ struct uic *uic = get_irq_chip_data(virq);
+ unsigned int src = uic_irq_to_hw(virq);
+ unsigned long flags;
+ u32 er;
+
+ spin_lock_irqsave(&uic->lock, flags);
+ er = mfdcr(uic->dcrbase + UIC_ER);
+ er &= ~(1 << (31 - src));
+ mtdcr(uic->dcrbase + UIC_ER, er);
+ spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static void uic_ack_irq(unsigned int virq)
+{
+ struct uic *uic = get_irq_chip_data(virq);
+ unsigned int src = uic_irq_to_hw(virq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&uic->lock, flags);
+ mtdcr(uic->dcrbase + UIC_SR, 1 << (31-src));
+ spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
+{
+ struct uic *uic = get_irq_chip_data(virq);
+ unsigned int src = uic_irq_to_hw(virq);
+ struct irq_desc *desc = get_irq_desc(virq);
+ unsigned long flags;
+ int trigger, polarity;
+ u32 tr, pr, mask;
+
+ switch (flow_type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_NONE:
+ uic_mask_irq(virq);
+ return 0;
+
+ case IRQ_TYPE_EDGE_RISING:
+ trigger = 1; polarity = 1;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ trigger = 1; polarity = 0;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ trigger = 0; polarity = 1;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ trigger = 0; polarity = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mask = ~(1 << (31 - src));
+
+ spin_lock_irqsave(&uic->lock, flags);
+ tr = mfdcr(uic->dcrbase + UIC_TR);
+ pr = mfdcr(uic->dcrbase + UIC_PR);
+ tr = (tr & mask) | (trigger << (31-src));
+ pr = (pr & mask) | (polarity << (31-src));
+
+ mtdcr(uic->dcrbase + UIC_PR, pr);
+ mtdcr(uic->dcrbase + UIC_TR, tr);
+
+ desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+ desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+ if (trigger)
+ desc->status |= IRQ_LEVEL;
+
+ spin_unlock_irqrestore(&uic->lock, flags);
+
+ return 0;
+}
+
+static struct irq_chip uic_irq_chip = {
+ .typename = " UIC ",
+ .unmask = uic_unmask_irq,
+ .mask = uic_mask_irq,
+/* .mask_ack = uic_mask_irq_and_ack, */
+ .ack = uic_ack_irq,
+ .set_type = uic_set_irq_type,
+};
+
+static int uic_host_match(struct irq_host *h, struct device_node *node)
+{
+ struct uic *uic = h->host_data;
+ return uic->of_node == node;
+}
+
+static int uic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct uic *uic = h->host_data;
+
+ set_irq_chip_data(virq, uic);
+ /* Despite the name, handle_level_irq() works for both level
+ * and edge irqs on UIC. FIXME: check this is correct */
+ set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq);
+
+ /* Set default irq type */
+ set_irq_type(virq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static int uic_host_xlate(struct irq_host *h, struct device_node *ct,
+ u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
+
+{
+ /* UIC intspecs must have 2 cells */
+ BUG_ON(intsize != 2);
+ *out_hwirq = intspec[0];
+ *out_type = intspec[1];
+ return 0;
+}
+
+static struct irq_host_ops uic_host_ops = {
+ .match = uic_host_match,
+ .map = uic_host_map,
+ .xlate = uic_host_xlate,
+};
+
+irqreturn_t uic_cascade(int virq, void *data)
+{
+ struct uic *uic = data;
+ u32 msr;
+ int src;
+ int subvirq;
+
+ msr = mfdcr(uic->dcrbase + UIC_MSR);
+ src = 32 - ffs(msr);
+
+ subvirq = irq_linear_revmap(uic->irqhost, src);
+ generic_handle_irq(subvirq);
+
+ return IRQ_HANDLED;
+}
+
+static struct uic * __init uic_init_one(struct device_node *node)
+{
+ struct uic *uic;
+ const u32 *indexp, *dcrreg;
+ int len;
+
+ BUG_ON(! device_is_compatible(node, "ibm,uic"));
+
+ uic = alloc_bootmem(sizeof(*uic));
+ if (! uic)
+ return NULL; /* FIXME: panic? */
+
+ memset(uic, 0, sizeof(*uic));
+ spin_lock_init(&uic->lock);
+ uic->of_node = of_node_get(node);
+ indexp = of_get_property(node, "cell-index", &len);
+ if (!indexp || (len != sizeof(u32))) {
+ printk(KERN_ERR "uic: Device node %s has missing or invalid "
+ "cell-index property\n", node->full_name);
+ return NULL;
+ }
+ uic->index = *indexp;
+
+ dcrreg = of_get_property(node, "dcr-reg", &len);
+ if (!dcrreg || (len != 2*sizeof(u32))) {
+ printk(KERN_ERR "uic: Device node %s has missing or invalid "
+ "dcr-reg property\n", node->full_name);
+ return NULL;
+ }
+ uic->dcrbase = *dcrreg;
+
+ uic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_UIC_INTS,
+ &uic_host_ops, -1);
+ if (! uic->irqhost) {
+ of_node_put(node);
+ return NULL; /* FIXME: panic? */
+ }
+
+ uic->irqhost->host_data = uic;
+
+ /* Start with all interrupts disabled, level and non-critical */
+ mtdcr(uic->dcrbase + UIC_ER, 0);
+ mtdcr(uic->dcrbase + UIC_CR, 0);
+ mtdcr(uic->dcrbase + UIC_TR, 0);
+ /* Clear any pending interrupts, in case the firmware left some */
+ mtdcr(uic->dcrbase + UIC_SR, 0xffffffff);
+
+ printk ("UIC%d (%d IRQ sources) at DCR 0x%x\n", uic->index,
+ NR_UIC_INTS, uic->dcrbase);
+
+ return uic;
+}
+
+void __init uic_init_tree(void)
+{
+ struct device_node *np;
+ struct uic *uic;
+ const u32 *interrupts;
+
+ /* First locate and initialize the top-level UIC */
+
+ np = of_find_compatible_node(NULL, NULL, "ibm,uic");
+ while (np) {
+ interrupts = of_get_property(np, "interrupts", NULL);
+ if (! interrupts)
+ break;
+
+ np = of_find_compatible_node(np, NULL, "ibm,uic");
+ }
+
+ BUG_ON(!np); /* uic_init_tree() assumes there's a UIC as the
+ * top-level interrupt controller */
+ primary_uic = uic_init_one(np);
+ if (! primary_uic)
+ panic("Unable to initialize primary UIC %s\n", np->full_name);
+
+ irq_set_default_host(primary_uic->irqhost);
+ of_node_put(np);
+
+ /* The scan again for cascaded UICs */
+ np = of_find_compatible_node(NULL, NULL, "ibm,uic");
+ while (np) {
+ interrupts = of_get_property(np, "interrupts", NULL);
+ if (interrupts) {
+ /* Secondary UIC */
+ int cascade_virq;
+ int ret;
+
+ uic = uic_init_one(np);
+ if (! uic)
+ panic("Unable to initialize a secondary UIC %s\n",
+ np->full_name);
+
+ cascade_virq = irq_of_parse_and_map(np, 0);
+
+ uic->cascade.handler = uic_cascade;
+ uic->cascade.name = "UIC cascade";
+ uic->cascade.dev_id = uic;
+
+ ret = setup_irq(cascade_virq, &uic->cascade);
+ if (ret)
+ printk(KERN_ERR "Failed to setup_irq(%d) for "
+ "UIC%d cascade\n", cascade_virq,
+ uic->index);
+
+ /* FIXME: setup critical cascade?? */
+ }
+
+ np = of_find_compatible_node(np, NULL, "ibm,uic");
+ }
+}
+
+/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+unsigned int uic_get_irq(void)
+{
+ u32 msr;
+ int src;
+
+ BUG_ON(! primary_uic);
+
+ msr = mfdcr(primary_uic->dcrbase + UIC_MSR);
+ src = 32 - ffs(msr);
+
+ return irq_linear_revmap(primary_uic->irqhost, src);
+}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index bf299b66f3fc..b481db1dacb4 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -330,18 +330,17 @@ static void release_output_lock(void)
static int xmon_core(struct pt_regs *regs, int fromipi)
{
int cmd = 0;
- unsigned long msr;
struct bpt *bp;
long recurse_jmp[JMP_BUF_LEN];
unsigned long offset;
+ unsigned long flags;
#ifdef CONFIG_SMP
int cpu;
int secondary;
unsigned long timeout;
#endif
- msr = mfmsr();
- mtmsr(msr & ~MSR_EE); /* disable interrupts */
+ local_irq_save(flags);
bp = in_breakpoint_table(regs->nip, &offset);
if (bp != NULL) {
@@ -516,7 +515,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
insert_cpu_bpts();
- mtmsr(msr); /* restore interrupt enable */
+ local_irq_restore(flags);
return cmd != 'X' && cmd != EOF;
}
@@ -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)
diff --git a/arch/ppc/8xx_io/Kconfig b/arch/ppc/8xx_io/Kconfig
index 57dacf978532..c623e44f01ad 100644
--- a/arch/ppc/8xx_io/Kconfig
+++ b/arch/ppc/8xx_io/Kconfig
@@ -74,10 +74,6 @@ config ENET_BIG_BUFFERS
Allocate large buffers for MPC8xx Ethernet. Increases throughput
and decreases the likelihood of dropped packets, but costs memory.
-config HTDMSOUND
- bool "Embedded Planet HIOX Audio"
- depends on SOUND=y
-
# This doesn't really belong here, but it is convenient to ask
# 8xx specific questions.
comment "Generic MPC8xx Options"
diff --git a/arch/ppc/8xx_io/Makefile b/arch/ppc/8xx_io/Makefile
index d8760181fe99..1051a06df7e0 100644
--- a/arch/ppc/8xx_io/Makefile
+++ b/arch/ppc/8xx_io/Makefile
@@ -7,4 +7,3 @@ obj-y := commproc.o
obj-$(CONFIG_FEC_ENET) += fec.o
obj-$(CONFIG_SCC_ENET) += enet.o
obj-$(CONFIG_UCODE_PATCH) += micropatch.o
-obj-$(CONFIG_HTDMSOUND) += cs4218_tdm.o
diff --git a/arch/ppc/8xx_io/cs4218.h b/arch/ppc/8xx_io/cs4218.h
deleted file mode 100644
index e5f943045afa..000000000000
--- a/arch/ppc/8xx_io/cs4218.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef _cs4218_h_
-/*
- * Hacked version of linux/drivers/sound/dmasound/dmasound.h
- *
- *
- * Minor numbers for the sound driver.
- *
- * Unfortunately Creative called the codec chip of SB as a DSP. For this
- * reason the /dev/dsp is reserved for digitized audio use. There is a
- * device for true DSP processors but it will be called something else.
- * In v3.0 it's /dev/sndproc but this could be a temporary solution.
- */
-#define _cs4218_h_
-
-#include <linux/types.h>
-
-#define SND_NDEVS 256 /* Number of supported devices */
-#define SND_DEV_CTL 0 /* Control port /dev/mixer */
-#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
- synthesizer and MIDI output) */
-#define SND_DEV_MIDIN 2 /* Raw midi access */
-#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
-#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
-#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS 6 /* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
-#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
-#define SND_DEV_PSS SND_DEV_SNDPROC
-
-/* switch on various prinks */
-#define DEBUG_DMASOUND 1
-
-#define MAX_AUDIO_DEV 5
-#define MAX_MIXER_DEV 4
-#define MAX_SYNTH_DEV 3
-#define MAX_MIDI_DEV 6
-#define MAX_TIMER_DEV 3
-
-#define MAX_CATCH_RADIUS 10
-
-#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
- do { int error = get_user(ret, (int *)(arg)); \
- if (error) return error; \
- } while (0)
-#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
-
-static inline int ioctl_return(int *addr, int value)
-{
- return value < 0 ? value : put_user(value, addr);
-}
-
-#define HAS_RECORD
-
- /*
- * Initialization
- */
-
-/* description of the set-up applies to either hard or soft settings */
-
-typedef struct {
- int format; /* AFMT_* */
- int stereo; /* 0 = mono, 1 = stereo */
- int size; /* 8/16 bit*/
- int speed; /* speed */
-} SETTINGS;
-
- /*
- * Machine definitions
- */
-
-typedef struct {
- const char *name;
- const char *name2;
- void (*open)(void);
- void (*release)(void);
- void *(*dma_alloc)(unsigned int, gfp_t);
- void (*dma_free)(void *, unsigned int);
- int (*irqinit)(void);
-#ifdef MODULE
- void (*irqcleanup)(void);
-#endif
- void (*init)(void);
- void (*silence)(void);
- int (*setFormat)(int);
- int (*setVolume)(int);
- int (*setBass)(int);
- int (*setTreble)(int);
- int (*setGain)(int);
- void (*play)(void);
- void (*record)(void); /* optional */
- void (*mixer_init)(void); /* optional */
- int (*mixer_ioctl)(u_int, u_long); /* optional */
- int (*write_sq_setup)(void); /* optional */
- int (*read_sq_setup)(void); /* optional */
- int (*sq_open)(mode_t); /* optional */
- int (*state_info)(char *, size_t); /* optional */
- void (*abort_read)(void); /* optional */
- int min_dsp_speed;
- int max_dsp_speed;
- int version ;
- int hardware_afmts ; /* OSS says we only return h'ware info */
- /* when queried via SNDCTL_DSP_GETFMTS */
- int capabilities ; /* low-level reply to SNDCTL_DSP_GETCAPS */
- SETTINGS default_hard ; /* open() or init() should set something valid */
- SETTINGS default_soft ; /* you can make it look like old OSS, if you want to */
-} MACHINE;
-
- /*
- * Low level stuff
- */
-
-typedef struct {
- ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-} TRANS;
-
-
- /*
- * Sound queue stuff, the heart of the driver
- */
-
-struct sound_queue {
- /* buffers allocated for this queue */
- int numBufs; /* real limits on what the user can have */
- int bufSize; /* in bytes */
- char **buffers;
-
- /* current parameters */
- int locked ; /* params cannot be modified when != 0 */
- int user_frags ; /* user requests this many */
- int user_frag_size ; /* of this size */
- int max_count; /* actual # fragments <= numBufs */
- int block_size; /* internal block size in bytes */
- int max_active; /* in-use fragments <= max_count */
-
- /* it shouldn't be necessary to declare any of these volatile */
- int front, rear, count;
- int rear_size;
- /*
- * The use of the playing field depends on the hardware
- *
- * Atari, PMac: The number of frames that are loaded/playing
- *
- * Amiga: Bit 0 is set: a frame is loaded
- * Bit 1 is set: a frame is playing
- */
- int active;
- wait_queue_head_t action_queue, open_queue, sync_queue;
- int open_mode;
- int busy, syncing, xruns, died;
-};
-
-#define SLEEP(queue) interruptible_sleep_on_timeout(&queue, HZ)
-#define WAKE_UP(queue) (wake_up_interruptible(&queue))
-
-#endif /* _cs4218_h_ */
diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
deleted file mode 100644
index a956f28ab162..000000000000
--- a/arch/ppc/8xx_io/cs4218_tdm.c
+++ /dev/null
@@ -1,2833 +0,0 @@
-
-/* This is a modified version of linux/drivers/sound/dmasound.c to
- * support the CS4218 codec on the 8xx TDM port. Thanks to everyone
- * that contributed to the dmasound software (which includes me :-).
- *
- * The CS4218 is configured in Mode 4, sub-mode 0. This provides
- * left/right data only on the TDM port, as a 32-bit word, per frame
- * pulse. The control of the CS4218 is provided by some other means,
- * like the SPI port.
- * Dan Malek (dmalek@jlc.net)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/sound.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-/* Should probably do something different with this path name.....
- * Actually, I should just stop using it...
- */
-#include "cs4218.h"
-#include <linux/soundcard.h>
-
-#include <asm/mpc8xx.h>
-#include <asm/8xx_immap.h>
-#include <asm/commproc.h>
-
-#define DMASND_CS4218 5
-
-#define MAX_CATCH_RADIUS 10
-#define MIN_BUFFERS 4
-#define MIN_BUFSIZE 4
-#define MAX_BUFSIZE 128
-
-#define HAS_8BIT_TABLES
-
-static int sq_unit = -1;
-static int mixer_unit = -1;
-static int state_unit = -1;
-static int irq_installed = 0;
-static char **sound_buffers = NULL;
-static char **sound_read_buffers = NULL;
-
-static DEFINE_SPINLOCK(cs4218_lock);
-
-/* Local copies of things we put in the control register. Output
- * volume, like most codecs is really attenuation.
- */
-static int cs4218_rate_index;
-
-/*
- * Stuff for outputting a beep. The values range from -327 to +327
- * so we can multiply by an amplitude in the range 0..100 to get a
- * signed short value to put in the output buffer.
- */
-static short beep_wform[256] = {
- 0, 40, 79, 117, 153, 187, 218, 245,
- 269, 288, 304, 316, 323, 327, 327, 324,
- 318, 310, 299, 288, 275, 262, 249, 236,
- 224, 213, 204, 196, 190, 186, 183, 182,
- 182, 183, 186, 189, 192, 196, 200, 203,
- 206, 208, 209, 209, 209, 207, 204, 201,
- 197, 193, 188, 183, 179, 174, 170, 166,
- 163, 161, 160, 159, 159, 160, 161, 162,
- 164, 166, 168, 169, 171, 171, 171, 170,
- 169, 167, 163, 159, 155, 150, 144, 139,
- 133, 128, 122, 117, 113, 110, 107, 105,
- 103, 103, 103, 103, 104, 104, 105, 105,
- 105, 103, 101, 97, 92, 86, 78, 68,
- 58, 45, 32, 18, 3, -11, -26, -41,
- -55, -68, -79, -88, -95, -100, -102, -102,
- -99, -93, -85, -75, -62, -48, -33, -16,
- 0, 16, 33, 48, 62, 75, 85, 93,
- 99, 102, 102, 100, 95, 88, 79, 68,
- 55, 41, 26, 11, -3, -18, -32, -45,
- -58, -68, -78, -86, -92, -97, -101, -103,
- -105, -105, -105, -104, -104, -103, -103, -103,
- -103, -105, -107, -110, -113, -117, -122, -128,
- -133, -139, -144, -150, -155, -159, -163, -167,
- -169, -170, -171, -171, -171, -169, -168, -166,
- -164, -162, -161, -160, -159, -159, -160, -161,
- -163, -166, -170, -174, -179, -183, -188, -193,
- -197, -201, -204, -207, -209, -209, -209, -208,
- -206, -203, -200, -196, -192, -189, -186, -183,
- -182, -182, -183, -186, -190, -196, -204, -213,
- -224, -236, -249, -262, -275, -288, -299, -310,
- -318, -324, -327, -327, -323, -316, -304, -288,
- -269, -245, -218, -187, -153, -117, -79, -40,
-};
-
-#define BEEP_SPEED 5 /* 22050 Hz sample rate */
-#define BEEP_BUFLEN 512
-#define BEEP_VOLUME 15 /* 0 - 100 */
-
-static int beep_volume = BEEP_VOLUME;
-static int beep_playing = 0;
-static int beep_state = 0;
-static short *beep_buf;
-static void (*orig_mksound)(unsigned int, unsigned int);
-
-/* This is found someplace else......I guess in the keyboard driver
- * we don't include.
- */
-static void (*kd_mksound)(unsigned int, unsigned int);
-
-static int catchRadius = 0;
-static int numBufs = 4, bufSize = 32;
-static int numReadBufs = 4, readbufSize = 32;
-
-
-/* TDM/Serial transmit and receive buffer descriptors.
-*/
-static volatile cbd_t *rx_base, *rx_cur, *tx_base, *tx_cur;
-
-module_param(catchRadius, int, 0);
-module_param(numBufs, int, 0);
-module_param(bufSize, int, 0);
-module_param(numreadBufs, int, 0);
-module_param(readbufSize, int, 0);
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
- do { int error = get_user(ret, (int *)(arg)); \
- if (error) return error; \
- } while (0)
-#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
-
-/* CS4218 serial port control in mode 4.
-*/
-#define CS_INTMASK ((uint)0x40000000)
-#define CS_DO1 ((uint)0x20000000)
-#define CS_LATTEN ((uint)0x1f000000)
-#define CS_RATTEN ((uint)0x00f80000)
-#define CS_MUTE ((uint)0x00040000)
-#define CS_ISL ((uint)0x00020000)
-#define CS_ISR ((uint)0x00010000)
-#define CS_LGAIN ((uint)0x0000f000)
-#define CS_RGAIN ((uint)0x00000f00)
-
-#define CS_LATTEN_SET(X) (((X) & 0x1f) << 24)
-#define CS_RATTEN_SET(X) (((X) & 0x1f) << 19)
-#define CS_LGAIN_SET(X) (((X) & 0x0f) << 12)
-#define CS_RGAIN_SET(X) (((X) & 0x0f) << 8)
-
-#define CS_LATTEN_GET(X) (((X) >> 24) & 0x1f)
-#define CS_RATTEN_GET(X) (((X) >> 19) & 0x1f)
-#define CS_LGAIN_GET(X) (((X) >> 12) & 0x0f)
-#define CS_RGAIN_GET(X) (((X) >> 8) & 0x0f)
-
-/* The control register is effectively write only. We have to keep a copy
- * of what we write.
- */
-static uint cs4218_control;
-
-/* A place to store expanding information.
-*/
-static int expand_bal;
-static int expand_data;
-
-/* Since I can't make the microcode patch work for the SPI, I just
- * clock the bits using software.
- */
-static void sw_spi_init(void);
-static void sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt);
-static uint cs4218_ctl_write(uint ctlreg);
-
-/*** Some low level helpers **************************************************/
-
-/* 16 bit mu-law */
-
-static short ulaw2dma16[] = {
- -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
- -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
- -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
- -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
- -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
- -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
- -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
- -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
- -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
- -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
- -876, -844, -812, -780, -748, -716, -684, -652,
- -620, -588, -556, -524, -492, -460, -428, -396,
- -372, -356, -340, -324, -308, -292, -276, -260,
- -244, -228, -212, -196, -180, -164, -148, -132,
- -120, -112, -104, -96, -88, -80, -72, -64,
- -56, -48, -40, -32, -24, -16, -8, 0,
- 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
- 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
- 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
- 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
- 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
- 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
- 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
- 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
- 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
- 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
- 876, 844, 812, 780, 748, 716, 684, 652,
- 620, 588, 556, 524, 492, 460, 428, 396,
- 372, 356, 340, 324, 308, 292, 276, 260,
- 244, 228, 212, 196, 180, 164, 148, 132,
- 120, 112, 104, 96, 88, 80, 72, 64,
- 56, 48, 40, 32, 24, 16, 8, 0,
-};
-
-/* 16 bit A-law */
-
-static short alaw2dma16[] = {
- -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
- -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
- -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
- -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
- -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
- -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
- -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
- -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
- -344, -328, -376, -360, -280, -264, -312, -296,
- -472, -456, -504, -488, -408, -392, -440, -424,
- -88, -72, -120, -104, -24, -8, -56, -40,
- -216, -200, -248, -232, -152, -136, -184, -168,
- -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
- -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
- -688, -656, -752, -720, -560, -528, -624, -592,
- -944, -912, -1008, -976, -816, -784, -880, -848,
- 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
- 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
- 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
- 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
- 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
- 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
- 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
- 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
- 344, 328, 376, 360, 280, 264, 312, 296,
- 472, 456, 504, 488, 408, 392, 440, 424,
- 88, 72, 120, 104, 24, 8, 56, 40,
- 216, 200, 248, 232, 152, 136, 184, 168,
- 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
- 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
- 688, 656, 752, 720, 560, 528, 624, 592,
- 944, 912, 1008, 976, 816, 784, 880, 848,
-};
-
-
-/*** Translations ************************************************************/
-
-
-static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-
-
-/*** Low level stuff *********************************************************/
-
-struct cs_sound_settings {
- MACHINE mach; /* machine dependent things */
- SETTINGS hard; /* hardware settings */
- SETTINGS soft; /* software settings */
- SETTINGS dsp; /* /dev/dsp default settings */
- TRANS *trans_write; /* supported translations for playback */
- TRANS *trans_read; /* supported translations for record */
- int volume_left; /* volume (range is machine dependent) */
- int volume_right;
- int bass; /* tone (range is machine dependent) */
- int treble;
- int gain;
- int minDev; /* minor device number currently open */
-};
-
-static struct cs_sound_settings sound;
-
-static void *CS_Alloc(unsigned int size, gfp_t flags);
-static void CS_Free(void *ptr, unsigned int size);
-static int CS_IrqInit(void);
-#ifdef MODULE
-static void CS_IrqCleanup(void);
-#endif /* MODULE */
-static void CS_Silence(void);
-static void CS_Init(void);
-static void CS_Play(void);
-static void CS_Record(void);
-static int CS_SetFormat(int format);
-static int CS_SetVolume(int volume);
-static void cs4218_tdm_tx_intr(void *devid);
-static void cs4218_tdm_rx_intr(void *devid);
-static void cs4218_intr(void *devid);
-static int cs_get_volume(uint reg);
-static int cs_volume_setter(int volume, int mute);
-static int cs_get_gain(uint reg);
-static int cs_set_gain(int gain);
-static void cs_mksound(unsigned int hz, unsigned int ticks);
-static void cs_nosound(unsigned long xx);
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void);
-static void sound_init(void);
-static int sound_set_format(int format);
-static int sound_set_speed(int speed);
-static int sound_set_stereo(int stereo);
-static int sound_set_volume(int volume);
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-
-
-/*
- * /dev/mixer abstraction
- */
-
-struct sound_mixer {
- int busy;
- int modify_counter;
-};
-
-static struct sound_mixer mixer;
-
-static struct sound_queue sq;
-static struct sound_queue read_sq;
-
-#define sq_block_address(i) (sq.buffers[i])
-#define SIGNAL_RECEIVED (signal_pending(current))
-#define NON_BLOCKING(open_mode) (open_mode & O_NONBLOCK)
-#define ONE_SECOND HZ /* in jiffies (100ths of a second) */
-#define NO_TIME_LIMIT 0xffffffff
-
-/*
- * /dev/sndstat
- */
-
-struct sound_state {
- int busy;
- char buf[512];
- int len, ptr;
-};
-
-static struct sound_state state;
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig);
-
-/*** Config & Setup **********************************************************/
-
-void dmasound_setup(char *str, int *ints);
-
-/*** Translations ************************************************************/
-
-
-/* ++TeSche: radically changed for new expanding purposes...
- *
- * These two routines now deal with copying/expanding/translating the samples
- * from user space into our buffer at the right frequency. They take care about
- * how much data there's actually to read, how much buffer space there is and
- * to convert samples into the right frequency/encoding. They will only work on
- * complete samples so it may happen they leave some bytes in the input stream
- * if the user didn't write a multiple of the current sample size. They both
- * return the number of bytes they've used from both streams so you may detect
- * such a situation. Luckily all programs should be able to cope with that.
- *
- * I think I've optimized anything as far as one can do in plain C, all
- * variables should fit in registers and the loops are really short. There's
- * one loop for every possible situation. Writing a more generalized and thus
- * parameterized loop would only produce slower code. Feel free to optimize
- * this in assembler if you like. :)
- *
- * I think these routines belong here because they're not yet really hardware
- * independent, especially the fact that the Falcon can play 16bit samples
- * only in stereo is hardcoded in both of them!
- *
- * ++geert: split in even more functions (one per format)
- */
-
-static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = table[data];
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = table[data];
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = data << 8;
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = data << 8;
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = (data ^ 0x80) << 8;
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = (data ^ 0x80) << 8;
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-/* This is the default format of the codec. Signed, 16-bit stereo
- * generated by an application shouldn't have to be copied at all.
- * We should just get the phsical address of the buffers and update
- * the TDM BDs directly.
- */
-static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- if (!stereo) {
- short *up = (short *) userPtr;
- while (count > 0) {
- short data;
- if (get_user(data, up++))
- return -EFAULT;
- *fp++ = data;
- *fp++ = data;
- count--;
- }
- } else {
- if (copy_from_user(fp, userPtr, count * 4))
- return -EFAULT;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short *up = (short *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- int data;
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- *fp++ = data;
- if (stereo) {
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- }
- *fp++ = data;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-
-static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned short *table = (unsigned short *)
- (sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
- unsigned int data = expand_data;
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- int bal = expand_bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int utotal, ftotal;
- int stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = table[c];
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + table[c];
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- int bal = expand_bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = c << 8;
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + (c << 8);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- int bal = expand_bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (c ^ 0x80) << 8;
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + ((c ^ 0x80) << 8);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- unsigned short *up = (unsigned short *) userPtr;
- int bal = expand_bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- unsigned short c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(data, up++))
- return -EFAULT;
- if (stereo) {
- if (get_user(c, up++))
- return -EFAULT;
- data = (data << 16) + c;
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-
-static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- unsigned short *up = (unsigned short *) userPtr;
- int bal = expand_bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- unsigned short c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- if (stereo) {
- if (get_user(c, up++))
- return -EFAULT;
- data = (data << 16) + (c ^ mask);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-static ssize_t cs4218_ct_s8_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
-
- val = *p++;
- data = val >> 8;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- if (stereo) {
- val = *p;
- data = val >> 8;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- }
- p++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_u8_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
-
- val = *p++;
- data = (val >> 8) ^ 0x80;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- if (stereo) {
- val = *p;
- data = (val >> 8) ^ 0x80;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- }
- p++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- if (!stereo) {
- short *up = (short *) userPtr;
- while (count > 0) {
- short data;
- data = *fp;
- if (put_user(data, up++))
- return -EFAULT;
- fp+=2;
- count--;
- }
- } else {
- if (copy_to_user((u_char *)userPtr, fp, count * 4))
- return -EFAULT;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short *up = (short *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- int data;
-
- data = *fp++;
- data ^= mask;
- if (put_user(data, up++))
- return -EFAULT;
- if (stereo) {
- data = *fp;
- data ^= mask;
- if (put_user(data, up++))
- return -EFAULT;
- }
- fp++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static TRANS transCSNormal = {
- cs4218_ct_law, cs4218_ct_law, cs4218_ct_s8, cs4218_ct_u8,
- cs4218_ct_s16, cs4218_ct_u16, cs4218_ct_s16, cs4218_ct_u16
-};
-
-static TRANS transCSExpand = {
- cs4218_ctx_law, cs4218_ctx_law, cs4218_ctx_s8, cs4218_ctx_u8,
- cs4218_ctx_s16, cs4218_ctx_u16, cs4218_ctx_s16, cs4218_ctx_u16
-};
-
-static TRANS transCSNormalRead = {
- NULL, NULL, cs4218_ct_s8_read, cs4218_ct_u8_read,
- cs4218_ct_s16_read, cs4218_ct_u16_read,
- cs4218_ct_s16_read, cs4218_ct_u16_read
-};
-
-/*** Low level stuff *********************************************************/
-
-static void *CS_Alloc(unsigned int size, gfp_t flags)
-{
- int order;
-
- size >>= 13;
- for (order=0; order < 5; order++) {
- if (size == 0)
- break;
- size >>= 1;
- }
- return (void *)__get_free_pages(flags, order);
-}
-
-static void CS_Free(void *ptr, unsigned int size)
-{
- int order;
-
- size >>= 13;
- for (order=0; order < 5; order++) {
- if (size == 0)
- break;
- size >>= 1;
- }
- free_pages((ulong)ptr, order);
-}
-
-static int __init CS_IrqInit(void)
-{
- cpm_install_handler(CPMVEC_SMC2, cs4218_intr, NULL);
- return 1;
-}
-
-#ifdef MODULE
-static void CS_IrqCleanup(void)
-{
- volatile smc_t *sp;
- volatile cpm8xx_t *cp;
-
- /* First disable transmitter and receiver.
- */
- sp = &cpmp->cp_smc[1];
- sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-
- /* And now shut down the SMC.
- */
- cp = cpmp; /* Get pointer to Communication Processor */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
- CPM_CR_STOP_TX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
-
- /* Release the interrupt handler.
- */
- cpm_free_handler(CPMVEC_SMC2);
-
- kfree(beep_buf);
- kd_mksound = orig_mksound;
-}
-#endif /* MODULE */
-
-static void CS_Silence(void)
-{
- volatile smc_t *sp;
-
- /* Disable transmitter.
- */
- sp = &cpmp->cp_smc[1];
- sp->smc_smcmr &= ~SMCMR_TEN;
-}
-
-/* Frequencies depend upon external oscillator. There are two
- * choices, 12.288 and 11.2896 MHz. The RPCG audio supports both through
- * and external control register selection bit.
- */
-static int cs4218_freqs[] = {
- /* 12.288 11.2896 */
- 48000, 44100,
- 32000, 29400,
- 24000, 22050,
- 19200, 17640,
- 16000, 14700,
- 12000, 11025,
- 9600, 8820,
- 8000, 7350
-};
-
-static void CS_Init(void)
-{
- int i, tolerance;
-
- switch (sound.soft.format) {
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- sound.hard.format = AFMT_S16_LE;
- break;
- default:
- sound.hard.format = AFMT_S16_BE;
- break;
- }
- sound.hard.stereo = 1;
- sound.hard.size = 16;
-
- /*
- * If we have a sample rate which is within catchRadius percent
- * of the requested value, we don't have to expand the samples.
- * Otherwise choose the next higher rate.
- */
- i = (sizeof(cs4218_freqs) / sizeof(int));
- do {
- tolerance = catchRadius * cs4218_freqs[--i] / 100;
- } while (sound.soft.speed > cs4218_freqs[i] + tolerance && i > 0);
- if (sound.soft.speed >= cs4218_freqs[i] - tolerance)
- sound.trans_write = &transCSNormal;
- else
- sound.trans_write = &transCSExpand;
- sound.trans_read = &transCSNormalRead;
- sound.hard.speed = cs4218_freqs[i];
- cs4218_rate_index = i;
-
- /* The CS4218 has seven selectable clock dividers for the sample
- * clock. The HIOX then provides one of two external rates.
- * An even numbered frequency table index uses the high external
- * clock rate.
- */
- *(uint *)HIOX_CSR4_ADDR &= ~(HIOX_CSR4_AUDCLKHI | HIOX_CSR4_AUDCLKSEL);
- if ((i & 1) == 0)
- *(uint *)HIOX_CSR4_ADDR |= HIOX_CSR4_AUDCLKHI;
- i >>= 1;
- *(uint *)HIOX_CSR4_ADDR |= (i & HIOX_CSR4_AUDCLKSEL);
-
- expand_bal = -sound.soft.speed;
-}
-
-static int CS_SetFormat(int format)
-{
- int size;
-
- switch (format) {
- case AFMT_QUERY:
- return sound.soft.format;
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_BE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- size = 16;
- break;
- default: /* :-) */
- printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
- format);
- size = 8;
- format = AFMT_U8;
- }
-
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = size;
- }
-
- CS_Init();
-
- return format;
-}
-
-/* Volume is the amount of attenuation we tell the codec to impose
- * on the outputs. There are 32 levels, with 0 the "loudest".
- */
-#define CS_VOLUME_TO_MASK(x) (31 - ((((x) - 1) * 31) / 99))
-#define CS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 31))
-
-static int cs_get_volume(uint reg)
-{
- int volume;
-
- volume = CS_MASK_TO_VOLUME(CS_LATTEN_GET(reg));
- volume |= CS_MASK_TO_VOLUME(CS_RATTEN_GET(reg)) << 8;
- return volume;
-}
-
-static int cs_volume_setter(int volume, int mute)
-{
- uint tempctl;
-
- if (mute && volume == 0) {
- tempctl = cs4218_control | CS_MUTE;
- } else {
- tempctl = cs4218_control & ~CS_MUTE;
- tempctl = tempctl & ~(CS_LATTEN | CS_RATTEN);
- tempctl |= CS_LATTEN_SET(CS_VOLUME_TO_MASK(volume & 0xff));
- tempctl |= CS_RATTEN_SET(CS_VOLUME_TO_MASK((volume >> 8) & 0xff));
- volume = cs_get_volume(tempctl);
- }
- if (tempctl != cs4218_control) {
- cs4218_ctl_write(tempctl);
- }
- return volume;
-}
-
-
-/* Gain has 16 steps from 0 to 15. These are in 1.5dB increments from
- * 0 (no gain) to 22.5 dB.
- */
-#define CS_RECLEVEL_TO_GAIN(v) \
- ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
-#define CS_GAIN_TO_RECLEVEL(v) (((v) * 20 + 2) / 3)
-
-static int cs_get_gain(uint reg)
-{
- int gain;
-
- gain = CS_GAIN_TO_RECLEVEL(CS_LGAIN_GET(reg));
- gain |= CS_GAIN_TO_RECLEVEL(CS_RGAIN_GET(reg)) << 8;
- return gain;
-}
-
-static int cs_set_gain(int gain)
-{
- uint tempctl;
-
- tempctl = cs4218_control & ~(CS_LGAIN | CS_RGAIN);
- tempctl |= CS_LGAIN_SET(CS_RECLEVEL_TO_GAIN(gain & 0xff));
- tempctl |= CS_RGAIN_SET(CS_RECLEVEL_TO_GAIN((gain >> 8) & 0xff));
- gain = cs_get_gain(tempctl);
-
- if (tempctl != cs4218_control) {
- cs4218_ctl_write(tempctl);
- }
- return gain;
-}
-
-static int CS_SetVolume(int volume)
-{
- return cs_volume_setter(volume, CS_MUTE);
-}
-
-static void CS_Play(void)
-{
- int i, count;
- unsigned long flags;
- volatile cbd_t *bdp;
- volatile cpm8xx_t *cp;
-
- /* Protect buffer */
- spin_lock_irqsave(&cs4218_lock, flags);
-#if 0
- if (awacs_beep_state) {
- /* sound takes precedence over beeps */
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | (awacs_rate_index << 8));
- out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count])));
-
- beep_playing = 0;
- awacs_beep_state = 0;
- }
-#endif
- i = sq.front + sq.active;
- if (i >= sq.max_count)
- i -= sq.max_count;
- while (sq.active < 2 && sq.active < sq.count) {
- count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size;
- if (count < sq.block_size && !sq.syncing)
- /* last block not yet filled, and we're not syncing. */
- break;
-
- bdp = &tx_base[i];
- bdp->cbd_datlen = count;
-
- flush_dcache_range((ulong)sound_buffers[i],
- (ulong)(sound_buffers[i] + count));
-
- if (++i >= sq.max_count)
- i = 0;
-
- if (sq.active == 0) {
- /* The SMC does not load its fifo until the first
- * TDM frame pulse, so the transmit data gets shifted
- * by one word. To compensate for this, we incorrectly
- * transmit the first buffer and shorten it by one
- * word. Subsequent buffers are then aligned properly.
- */
- bdp->cbd_datlen -= 2;
-
- /* Start up the SMC Transmitter.
- */
- cp = cpmp;
- cp->cp_smc[1].smc_smcmr |= SMCMR_TEN;
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
- CPM_CR_RESTART_TX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
- }
-
- /* Buffer is ready now.
- */
- bdp->cbd_sc |= BD_SC_READY;
-
- ++sq.active;
- }
- spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-
-static void CS_Record(void)
-{
- unsigned long flags;
- volatile smc_t *sp;
-
- if (read_sq.active)
- return;
-
- /* Protect buffer */
- spin_lock_irqsave(&cs4218_lock, flags);
-
- /* This is all we have to do......Just start it up.
- */
- sp = &cpmp->cp_smc[1];
- sp->smc_smcmr |= SMCMR_REN;
-
- read_sq.active = 1;
-
- spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-
-static void
-cs4218_tdm_tx_intr(void *devid)
-{
- int i = sq.front;
- volatile cbd_t *bdp;
-
- while (sq.active > 0) {
- bdp = &tx_base[i];
- if (bdp->cbd_sc & BD_SC_READY)
- break; /* this frame is still going */
- --sq.count;
- --sq.active;
- if (++i >= sq.max_count)
- i = 0;
- }
- if (i != sq.front)
- WAKE_UP(sq.action_queue);
- sq.front = i;
-
- CS_Play();
-
- if (!sq.active)
- WAKE_UP(sq.sync_queue);
-}
-
-
-static void
-cs4218_tdm_rx_intr(void *devid)
-{
-
- /* We want to blow 'em off when shutting down.
- */
- if (read_sq.active == 0)
- return;
-
- /* Check multiple buffers in case we were held off from
- * interrupt processing for a long time. Geeze, I really hope
- * this doesn't happen.
- */
- while ((rx_base[read_sq.rear].cbd_sc & BD_SC_EMPTY) == 0) {
-
- /* Invalidate the data cache range for this buffer.
- */
- invalidate_dcache_range(
- (uint)(sound_read_buffers[read_sq.rear]),
- (uint)(sound_read_buffers[read_sq.rear] + read_sq.block_size));
-
- /* Make buffer available again and move on.
- */
- rx_base[read_sq.rear].cbd_sc |= BD_SC_EMPTY;
- read_sq.rear++;
-
- /* Wrap the buffer ring.
- */
- if (read_sq.rear >= read_sq.max_active)
- read_sq.rear = 0;
-
- /* If we have caught up to the front buffer, bump it.
- * This will cause weird (but not fatal) results if the
- * read loop is currently using this buffer. The user is
- * behind in this case anyway, so weird things are going
- * to happen.
- */
- if (read_sq.rear == read_sq.front) {
- read_sq.front++;
- if (read_sq.front >= read_sq.max_active)
- read_sq.front = 0;
- }
- }
-
- WAKE_UP(read_sq.action_queue);
-}
-
-static void cs_nosound(unsigned long xx)
-{
- unsigned long flags;
-
- /* not sure if this is needed, since hardware command is #if 0'd */
- spin_lock_irqsave(&cs4218_lock, flags);
- if (beep_playing) {
-#if 0
- st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
-#endif
- beep_playing = 0;
- }
- spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-static DEFINE_TIMER(beep_timer, cs_nosound, 0, 0);
-
-static void cs_mksound(unsigned int hz, unsigned int ticks)
-{
- unsigned long flags;
- int beep_speed = BEEP_SPEED;
- int srate = cs4218_freqs[beep_speed];
- int period, ncycles, nsamples;
- int i, j, f;
- short *p;
- static int beep_hz_cache;
- static int beep_nsamples_cache;
- static int beep_volume_cache;
-
- if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
-#if 1
- /* this is a hack for broken X server code */
- hz = 750;
- ticks = 12;
-#else
- /* cancel beep currently playing */
- awacs_nosound(0);
- return;
-#endif
- }
- /* lock while modifying beep_timer */
- spin_lock_irqsave(&cs4218_lock, flags);
- del_timer(&beep_timer);
- if (ticks) {
- beep_timer.expires = jiffies + ticks;
- add_timer(&beep_timer);
- }
- if (beep_playing || sq.active || beep_buf == NULL) {
- spin_unlock_irqrestore(&cs4218_lock, flags);
- return; /* too hard, sorry :-( */
- }
- beep_playing = 1;
-#if 0
- st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
-#endif
- spin_unlock_irqrestore(&cs4218_lock, flags);
-
- if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
- nsamples = beep_nsamples_cache;
- } else {
- period = srate * 256 / hz; /* fixed point */
- ncycles = BEEP_BUFLEN * 256 / period;
- nsamples = (period * ncycles) >> 8;
- f = ncycles * 65536 / nsamples;
- j = 0;
- p = beep_buf;
- for (i = 0; i < nsamples; ++i, p += 2) {
- p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
- j = (j + f) & 0xffff;
- }
- beep_hz_cache = hz;
- beep_volume_cache = beep_volume;
- beep_nsamples_cache = nsamples;
- }
-
-#if 0
- st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
- st_le16(&beep_dbdma_cmd->xfer_status, 0);
- st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
- st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
- awacs_beep_state = 1;
-
- spin_lock_irqsave(&cs4218_lock, flags);
- if (beep_playing) { /* i.e. haven't been terminated already */
- out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | (beep_speed << 8));
- out_le32(&awacs->byteswap, 0);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
- out_le32(&awacs_txdma->control, RUN | (RUN << 16));
- }
- spin_unlock_irqrestore(&cs4218_lock, flags);
-#endif
-}
-
-static MACHINE mach_cs4218 = {
- .owner = THIS_MODULE,
- .name = "HIOX CS4218",
- .name2 = "Built-in Sound",
- .dma_alloc = CS_Alloc,
- .dma_free = CS_Free,
- .irqinit = CS_IrqInit,
-#ifdef MODULE
- .irqcleanup = CS_IrqCleanup,
-#endif /* MODULE */
- .init = CS_Init,
- .silence = CS_Silence,
- .setFormat = CS_SetFormat,
- .setVolume = CS_SetVolume,
- .play = CS_Play
-};
-
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void)
-{
- /* update hardware settings one more */
- (*sound.mach.init)();
-
- (*sound.mach.silence)();
-}
-
-
-static void sound_init(void)
-{
- (*sound.mach.init)();
-}
-
-
-static int sound_set_format(int format)
-{
- return(*sound.mach.setFormat)(format);
-}
-
-
-static int sound_set_speed(int speed)
-{
- if (speed < 0)
- return(sound.soft.speed);
-
- sound.soft.speed = speed;
- (*sound.mach.init)();
- if (sound.minDev == SND_DEV_DSP)
- sound.dsp.speed = sound.soft.speed;
-
- return(sound.soft.speed);
-}
-
-
-static int sound_set_stereo(int stereo)
-{
- if (stereo < 0)
- return(sound.soft.stereo);
-
- stereo = !!stereo; /* should be 0 or 1 now */
-
- sound.soft.stereo = stereo;
- if (sound.minDev == SND_DEV_DSP)
- sound.dsp.stereo = stereo;
- (*sound.mach.init)();
-
- return(stereo);
-}
-
-
-static int sound_set_volume(int volume)
-{
- return(*sound.mach.setVolume)(volume);
-}
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- ct_func = sound.trans_write->ct_ulaw;
- break;
- case AFMT_A_LAW:
- ct_func = sound.trans_write->ct_alaw;
- break;
- case AFMT_S8:
- ct_func = sound.trans_write->ct_s8;
- break;
- case AFMT_U8:
- ct_func = sound.trans_write->ct_u8;
- break;
- case AFMT_S16_BE:
- ct_func = sound.trans_write->ct_s16be;
- break;
- case AFMT_U16_BE:
- ct_func = sound.trans_write->ct_u16be;
- break;
- case AFMT_S16_LE:
- ct_func = sound.trans_write->ct_s16le;
- break;
- case AFMT_U16_LE:
- ct_func = sound.trans_write->ct_u16le;
- break;
- }
- if (ct_func)
- return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
- else
- return 0;
-}
-
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- ct_func = sound.trans_read->ct_ulaw;
- break;
- case AFMT_A_LAW:
- ct_func = sound.trans_read->ct_alaw;
- break;
- case AFMT_S8:
- ct_func = sound.trans_read->ct_s8;
- break;
- case AFMT_U8:
- ct_func = sound.trans_read->ct_u8;
- break;
- case AFMT_S16_BE:
- ct_func = sound.trans_read->ct_s16be;
- break;
- case AFMT_U16_BE:
- ct_func = sound.trans_read->ct_u16be;
- break;
- case AFMT_S16_LE:
- ct_func = sound.trans_read->ct_s16le;
- break;
- case AFMT_U16_LE:
- ct_func = sound.trans_read->ct_u16le;
- break;
- }
- if (ct_func)
- return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
- else
- return 0;
-}
-
-
-/*
- * /dev/mixer abstraction
- */
-
-static int mixer_open(struct inode *inode, struct file *file)
-{
- mixer.busy = 1;
- return nonseekable_open(inode, file);
-}
-
-
-static int mixer_release(struct inode *inode, struct file *file)
-{
- mixer.busy = 0;
- return 0;
-}
-
-
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
-{
- int data;
- uint tmpcs;
-
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- mixer.modify_counter++;
- if (cmd == OSS_GETVERSION)
- return IOCTL_OUT(arg, SOUND_VERSION);
- switch (cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strlcpy(info.id, "CS4218_TDM", sizeof(info.id));
- strlcpy(info.name, "CS4218_TDM", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- if (copy_to_user((int *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- data = SOUND_MASK_VOLUME | SOUND_MASK_LINE
- | SOUND_MASK_MIC | SOUND_MASK_RECLEV
- | SOUND_MASK_ALTPCM;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECMASK:
- data = SOUND_MASK_LINE | SOUND_MASK_MIC;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECSRC:
- if (cs4218_control & CS_DO1)
- data = SOUND_MASK_LINE;
- else
- data = SOUND_MASK_MIC;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data &= (SOUND_MASK_LINE | SOUND_MASK_MIC);
- if (data & SOUND_MASK_LINE)
- tmpcs = cs4218_control |
- (CS_ISL | CS_ISR | CS_DO1);
- if (data & SOUND_MASK_MIC)
- tmpcs = cs4218_control &
- ~(CS_ISL | CS_ISR | CS_DO1);
- if (tmpcs != cs4218_control)
- cs4218_ctl_write(tmpcs);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_STEREODEVS:
- data = SOUND_MASK_VOLUME | SOUND_MASK_RECLEV;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_CAPS:
- return IOCTL_OUT(arg, 0);
- case SOUND_MIXER_READ_VOLUME:
- data = (cs4218_control & CS_MUTE)? 0:
- cs_get_volume(cs4218_control);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_volume(data));
- case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
- IOCTL_IN(arg, data);
- beep_volume = data & 0xff;
- /* fall through */
- case SOUND_MIXER_READ_ALTPCM:
- return IOCTL_OUT(arg, beep_volume);
- case SOUND_MIXER_WRITE_RECLEV:
- IOCTL_IN(arg, data);
- data = cs_set_gain(data);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECLEV:
- data = cs_get_gain(cs4218_control);
- return IOCTL_OUT(arg, data);
- }
-
- return -EINVAL;
-}
-
-
-static const struct file_operations mixer_fops =
-{
- .owner = THIS_MODULE,
- .llseek = sound_lseek,
- .ioctl = mixer_ioctl,
- .open = mixer_open,
- .release = mixer_release,
-};
-
-
-static void __init mixer_init(void)
-{
- mixer_unit = register_sound_mixer(&mixer_fops, -1);
- if (mixer_unit < 0)
- return;
-
- mixer.busy = 0;
- sound.treble = 0;
- sound.bass = 0;
-
- /* Set Line input, no gain, no attenuation.
- */
- cs4218_control = CS_ISL | CS_ISR | CS_DO1;
- cs4218_control |= CS_LGAIN_SET(0) | CS_RGAIN_SET(0);
- cs4218_control |= CS_LATTEN_SET(0) | CS_RATTEN_SET(0);
- cs4218_ctl_write(cs4218_control);
-}
-
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-
-static int sq_allocate_buffers(void)
-{
- int i;
-
- if (sound_buffers)
- return 0;
- sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
- if (!sound_buffers)
- return -ENOMEM;
- for (i = 0; i < numBufs; i++) {
- sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
- if (!sound_buffers[i]) {
- while (i--)
- sound.mach.dma_free (sound_buffers[i], bufSize << 10);
- kfree (sound_buffers);
- sound_buffers = 0;
- return -ENOMEM;
- }
- }
- return 0;
-}
-
-
-static void sq_release_buffers(void)
-{
- int i;
-
- if (sound_buffers) {
- for (i = 0; i < numBufs; i++)
- sound.mach.dma_free (sound_buffers[i], bufSize << 10);
- kfree (sound_buffers);
- sound_buffers = 0;
- }
-}
-
-
-static int sq_allocate_read_buffers(void)
-{
- int i;
-
- if (sound_read_buffers)
- return 0;
- sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL);
- if (!sound_read_buffers)
- return -ENOMEM;
- for (i = 0; i < numBufs; i++) {
- sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10,
- GFP_KERNEL);
- if (!sound_read_buffers[i]) {
- while (i--)
- sound.mach.dma_free (sound_read_buffers[i],
- readbufSize << 10);
- kfree (sound_read_buffers);
- sound_read_buffers = 0;
- return -ENOMEM;
- }
- }
- return 0;
-}
-
-static void sq_release_read_buffers(void)
-{
- int i;
-
- if (sound_read_buffers) {
- cpmp->cp_smc[1].smc_smcmr &= ~SMCMR_REN;
- for (i = 0; i < numReadBufs; i++)
- sound.mach.dma_free (sound_read_buffers[i],
- bufSize << 10);
- kfree (sound_read_buffers);
- sound_read_buffers = 0;
- }
-}
-
-
-static void sq_setup(int numBufs, int bufSize, char **write_buffers)
-{
- int i;
- volatile cbd_t *bdp;
- volatile cpm8xx_t *cp;
- volatile smc_t *sp;
-
- /* Make sure the SMC transmit is shut down.
- */
- cp = cpmp;
- sp = &cpmp->cp_smc[1];
- sp->smc_smcmr &= ~SMCMR_TEN;
-
- sq.max_count = numBufs;
- sq.max_active = numBufs;
- sq.block_size = bufSize;
- sq.buffers = write_buffers;
-
- sq.front = sq.count = 0;
- sq.rear = -1;
- sq.syncing = 0;
- sq.active = 0;
-
- bdp = tx_base;
- for (i=0; i<numBufs; i++) {
- bdp->cbd_bufaddr = virt_to_bus(write_buffers[i]);
- bdp++;
- }
-
- /* This causes the SMC to sync up with the first buffer again.
- */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_TX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
-}
-
-static void read_sq_setup(int numBufs, int bufSize, char **read_buffers)
-{
- int i;
- volatile cbd_t *bdp;
- volatile cpm8xx_t *cp;
- volatile smc_t *sp;
-
- /* Make sure the SMC receive is shut down.
- */
- cp = cpmp;
- sp = &cpmp->cp_smc[1];
- sp->smc_smcmr &= ~SMCMR_REN;
-
- read_sq.max_count = numBufs;
- read_sq.max_active = numBufs;
- read_sq.block_size = bufSize;
- read_sq.buffers = read_buffers;
-
- read_sq.front = read_sq.count = 0;
- read_sq.rear = 0;
- read_sq.rear_size = 0;
- read_sq.syncing = 0;
- read_sq.active = 0;
-
- bdp = rx_base;
- for (i=0; i<numReadBufs; i++) {
- bdp->cbd_bufaddr = virt_to_bus(read_buffers[i]);
- bdp->cbd_datlen = read_sq.block_size;
- bdp++;
- }
-
- /* This causes the SMC to sync up with the first buffer again.
- */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_RX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
-}
-
-
-static void sq_play(void)
-{
- (*sound.mach.play)();
-}
-
-
-/* ++TeSche: radically changed this one too */
-
-static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
- loff_t *ppos)
-{
- ssize_t uWritten = 0;
- u_char *dest;
- ssize_t uUsed, bUsed, bLeft;
-
- /* ++TeSche: Is something like this necessary?
- * Hey, that's an honest question! Or does any other part of the
- * filesystem already checks this situation? I really don't know.
- */
- if (uLeft == 0)
- return 0;
-
- /* The interrupt doesn't start to play the last, incomplete frame.
- * Thus we can append to it without disabling the interrupts! (Note
- * also that sq.rear isn't affected by the interrupt.)
- */
-
- if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
- dest = sq_block_address(sq.rear);
- bUsed = sq.rear_size;
- uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
- if (uUsed <= 0)
- return uUsed;
- src += uUsed;
- uWritten += uUsed;
- uLeft -= uUsed;
- sq.rear_size = bUsed;
- }
-
- do {
- while (sq.count == sq.max_active) {
- sq_play();
- if (NON_BLOCKING(sq.open_mode))
- return uWritten > 0 ? uWritten : -EAGAIN;
- SLEEP(sq.action_queue);
- if (SIGNAL_RECEIVED)
- return uWritten > 0 ? uWritten : -EINTR;
- }
-
- /* Here, we can avoid disabling the interrupt by first
- * copying and translating the data, and then updating
- * the sq variables. Until this is done, the interrupt
- * won't see the new frame and we can work on it
- * undisturbed.
- */
-
- dest = sq_block_address((sq.rear+1) % sq.max_count);
- bUsed = 0;
- bLeft = sq.block_size;
- uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
- if (uUsed <= 0)
- break;
- src += uUsed;
- uWritten += uUsed;
- uLeft -= uUsed;
- if (bUsed) {
- sq.rear = (sq.rear+1) % sq.max_count;
- sq.rear_size = bUsed;
- sq.count++;
- }
- } while (bUsed); /* uUsed may have been 0 */
-
- sq_play();
-
- return uUsed < 0? uUsed: uWritten;
-}
-
-
-/***********/
-
-/* Here is how the values are used for reading.
- * The value 'active' simply indicates the DMA is running. This is
- * done so the driver semantics are DMA starts when the first read is
- * posted. The value 'front' indicates the buffer we should next
- * send to the user. The value 'rear' indicates the buffer the DMA is
- * currently filling. When 'front' == 'rear' the buffer "ring" is
- * empty (we always have an empty available). The 'rear_size' is used
- * to track partial offsets into the current buffer. Right now, I just keep
- * The DMA running. If the reader can't keep up, the interrupt tosses
- * the oldest buffer. We could also shut down the DMA in this case.
- */
-static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
- loff_t *ppos)
-{
-
- ssize_t uRead, bLeft, bUsed, uUsed;
-
- if (uLeft == 0)
- return 0;
-
- if (!read_sq.active)
- CS_Record(); /* Kick off the record process. */
-
- uRead = 0;
-
- /* Move what the user requests, depending upon other options.
- */
- while (uLeft > 0) {
-
- /* When front == rear, the DMA is not done yet.
- */
- while (read_sq.front == read_sq.rear) {
- if (NON_BLOCKING(read_sq.open_mode)) {
- return uRead > 0 ? uRead : -EAGAIN;
- }
- SLEEP(read_sq.action_queue);
- if (SIGNAL_RECEIVED)
- return uRead > 0 ? uRead : -EINTR;
- }
-
- /* The amount we move is either what is left in the
- * current buffer or what the user wants.
- */
- bLeft = read_sq.block_size - read_sq.rear_size;
- bUsed = read_sq.rear_size;
- uUsed = sound_copy_translate_read(dst, uLeft,
- read_sq.buffers[read_sq.front], &bUsed, bLeft);
- if (uUsed <= 0)
- return uUsed;
- dst += uUsed;
- uRead += uUsed;
- uLeft -= uUsed;
- read_sq.rear_size += bUsed;
- if (read_sq.rear_size >= read_sq.block_size) {
- read_sq.rear_size = 0;
- read_sq.front++;
- if (read_sq.front >= read_sq.max_active)
- read_sq.front = 0;
- }
- }
- return uRead;
-}
-
-static int sq_open(struct inode *inode, struct file *file)
-{
- int rc = 0;
-
- if (file->f_mode & FMODE_WRITE) {
- if (sq.busy) {
- rc = -EBUSY;
- if (NON_BLOCKING(file->f_flags))
- goto err_out;
- rc = -EINTR;
- while (sq.busy) {
- SLEEP(sq.open_queue);
- if (SIGNAL_RECEIVED)
- goto err_out;
- }
- }
- sq.busy = 1; /* Let's play spot-the-race-condition */
-
- if (sq_allocate_buffers()) goto err_out_nobusy;
-
- sq_setup(numBufs, bufSize<<10,sound_buffers);
- sq.open_mode = file->f_mode;
- }
-
-
- if (file->f_mode & FMODE_READ) {
- if (read_sq.busy) {
- rc = -EBUSY;
- if (NON_BLOCKING(file->f_flags))
- goto err_out;
- rc = -EINTR;
- while (read_sq.busy) {
- SLEEP(read_sq.open_queue);
- if (SIGNAL_RECEIVED)
- goto err_out;
- }
- rc = 0;
- }
- read_sq.busy = 1;
- if (sq_allocate_read_buffers()) goto err_out_nobusy;
-
- read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers);
- read_sq.open_mode = file->f_mode;
- }
-
- /* Start up the 4218 by:
- * Reset.
- * Enable, unreset.
- */
- *((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_RSTAUDIO;
- eieio();
- *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_ENAUDIO;
- mdelay(50);
- *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO;
-
- /* We need to send the current control word in case someone
- * opened /dev/mixer and changed things while we were shut
- * down. Chances are good the initialization that follows
- * would have done this, but it is still possible it wouldn't.
- */
- cs4218_ctl_write(cs4218_control);
-
- sound.minDev = iminor(inode) & 0x0f;
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
- sound_init();
- if ((iminor(inode) & 0x0f) == SND_DEV_AUDIO) {
- sound_set_speed(8000);
- sound_set_stereo(0);
- sound_set_format(AFMT_MU_LAW);
- }
-
- return nonseekable_open(inode, file);
-
-err_out_nobusy:
- if (file->f_mode & FMODE_WRITE) {
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
- }
- if (file->f_mode & FMODE_READ) {
- read_sq.busy = 0;
- WAKE_UP(read_sq.open_queue);
- }
-err_out:
- return rc;
-}
-
-
-static void sq_reset(void)
-{
- sound_silence();
- sq.active = 0;
- sq.count = 0;
- sq.front = (sq.rear+1) % sq.max_count;
-#if 0
- init_tdm_buffers();
-#endif
-}
-
-
-static int sq_fsync(struct file *filp, struct dentry *dentry)
-{
- int rc = 0;
-
- sq.syncing = 1;
- sq_play(); /* there may be an incomplete frame waiting */
-
- while (sq.active) {
- SLEEP(sq.sync_queue);
- if (SIGNAL_RECEIVED) {
- /* While waiting for audio output to drain, an
- * interrupt occurred. Stop audio output immediately
- * and clear the queue. */
- sq_reset();
- rc = -EINTR;
- break;
- }
- }
-
- sq.syncing = 0;
- return rc;
-}
-
-static int sq_release(struct inode *inode, struct file *file)
-{
- int rc = 0;
-
- if (sq.busy)
- rc = sq_fsync(file, file->f_path.dentry);
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
- sound_silence();
-
- sq_release_read_buffers();
- sq_release_buffers();
-
- if (file->f_mode & FMODE_READ) {
- read_sq.busy = 0;
- WAKE_UP(read_sq.open_queue);
- }
-
- if (file->f_mode & FMODE_WRITE) {
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
- }
-
- /* Shut down the SMC.
- */
- cpmp->cp_smc[1].smc_smcmr &= ~(SMCMR_TEN | SMCMR_REN);
-
- /* Shut down the codec.
- */
- *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO;
- eieio();
- *((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_ENAUDIO;
-
- /* Wake up a process waiting for the queue being released.
- * Note: There may be several processes waiting for a call
- * to open() returning. */
-
- return rc;
-}
-
-
-static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
-{
- u_long fmt;
- int data;
-#if 0
- int size, nbufs;
-#else
- int size;
-#endif
-
- switch (cmd) {
- case SNDCTL_DSP_RESET:
- sq_reset();
- return 0;
- case SNDCTL_DSP_POST:
- case SNDCTL_DSP_SYNC:
- return sq_fsync(file, file->f_path.dentry);
-
- /* ++TeSche: before changing any of these it's
- * probably wise to wait until sound playing has
- * settled down. */
- case SNDCTL_DSP_SPEED:
- sq_fsync(file, file->f_path.dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_speed(data));
- case SNDCTL_DSP_STEREO:
- sq_fsync(file, file->f_path.dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_stereo(data));
- case SOUND_PCM_WRITE_CHANNELS:
- sq_fsync(file, file->f_path.dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
- case SNDCTL_DSP_SETFMT:
- sq_fsync(file, file->f_path.dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_format(data));
- case SNDCTL_DSP_GETFMTS:
- fmt = 0;
- if (sound.trans_write) {
- if (sound.trans_write->ct_ulaw)
- fmt |= AFMT_MU_LAW;
- if (sound.trans_write->ct_alaw)
- fmt |= AFMT_A_LAW;
- if (sound.trans_write->ct_s8)
- fmt |= AFMT_S8;
- if (sound.trans_write->ct_u8)
- fmt |= AFMT_U8;
- if (sound.trans_write->ct_s16be)
- fmt |= AFMT_S16_BE;
- if (sound.trans_write->ct_u16be)
- fmt |= AFMT_U16_BE;
- if (sound.trans_write->ct_s16le)
- fmt |= AFMT_S16_LE;
- if (sound.trans_write->ct_u16le)
- fmt |= AFMT_U16_LE;
- }
- return IOCTL_OUT(arg, fmt);
- case SNDCTL_DSP_GETBLKSIZE:
- size = sq.block_size
- * sound.soft.size * (sound.soft.stereo + 1)
- / (sound.hard.size * (sound.hard.stereo + 1));
- return IOCTL_OUT(arg, size);
- case SNDCTL_DSP_SUBDIVIDE:
- break;
-#if 0 /* Sorry can't do this at the moment. The CPM allocated buffers
- * long ago that can't be changed.
- */
- case SNDCTL_DSP_SETFRAGMENT:
- if (sq.count || sq.active || sq.syncing)
- return -EINVAL;
- IOCTL_IN(arg, size);
- nbufs = size >> 16;
- if (nbufs < 2 || nbufs > numBufs)
- nbufs = numBufs;
- size &= 0xffff;
- if (size >= 8 && size <= 30) {
- size = 1 << size;
- size *= sound.hard.size * (sound.hard.stereo + 1);
- size /= sound.soft.size * (sound.soft.stereo + 1);
- if (size > (bufSize << 10))
- size = bufSize << 10;
- } else
- size = bufSize << 10;
- sq_setup(numBufs, size, sound_buffers);
- sq.max_active = nbufs;
- return 0;
-#endif
-
- default:
- return mixer_ioctl(inode, file, cmd, arg);
- }
- return -EINVAL;
-}
-
-
-
-static const struct file_operations sq_fops =
-{
- .owner = THIS_MODULE,
- .llseek = sound_lseek,
- .read = sq_read, /* sq_read */
- .write = sq_write,
- .ioctl = sq_ioctl,
- .open = sq_open,
- .release = sq_release,
-};
-
-
-static void __init sq_init(void)
-{
- sq_unit = register_sound_dsp(&sq_fops, -1);
- if (sq_unit < 0)
- return;
-
- init_waitqueue_head(&sq.action_queue);
- init_waitqueue_head(&sq.open_queue);
- init_waitqueue_head(&sq.sync_queue);
- init_waitqueue_head(&read_sq.action_queue);
- init_waitqueue_head(&read_sq.open_queue);
- init_waitqueue_head(&read_sq.sync_queue);
-
- sq.busy = 0;
- read_sq.busy = 0;
-
- /* whatever you like as startup mode for /dev/dsp,
- * (/dev/audio hasn't got a startup mode). note that
- * once changed a new open() will *not* restore these!
- */
- sound.dsp.format = AFMT_S16_BE;
- sound.dsp.stereo = 1;
- sound.dsp.size = 16;
-
- /* set minimum rate possible without expanding */
- sound.dsp.speed = 8000;
-
- /* before the first open to /dev/dsp this wouldn't be set */
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
-
- sound_silence();
-}
-
-/*
- * /dev/sndstat
- */
-
-
-/* state.buf should not overflow! */
-
-static int state_open(struct inode *inode, struct file *file)
-{
- char *buffer = state.buf, *mach = "", cs4218_buf[50];
- int len = 0;
-
- if (state.busy)
- return -EBUSY;
-
- state.ptr = 0;
- state.busy = 1;
-
- sprintf(cs4218_buf, "Crystal CS4218 on TDM, ");
- mach = cs4218_buf;
-
- len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
-
- len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- len += sprintf(buffer+len, " (mu-law)");
- break;
- case AFMT_A_LAW:
- len += sprintf(buffer+len, " (A-law)");
- break;
- case AFMT_U8:
- len += sprintf(buffer+len, " (unsigned 8 bit)");
- break;
- case AFMT_S8:
- len += sprintf(buffer+len, " (signed 8 bit)");
- break;
- case AFMT_S16_BE:
- len += sprintf(buffer+len, " (signed 16 bit big)");
- break;
- case AFMT_U16_BE:
- len += sprintf(buffer+len, " (unsigned 16 bit big)");
- break;
- case AFMT_S16_LE:
- len += sprintf(buffer+len, " (signed 16 bit little)");
- break;
- case AFMT_U16_LE:
- len += sprintf(buffer+len, " (unsigned 16 bit little)");
- break;
- }
- len += sprintf(buffer+len, "\n");
- len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
- sound.soft.speed, sound.hard.speed);
- len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
- sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
- len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
- " sq.max_active = %d\n",
- sq.block_size, sq.max_count, sq.max_active);
- len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
- sq.rear_size);
- len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
- sq.active, sq.syncing);
- state.len = len;
- return nonseekable_open(inode, file);
-}
-
-
-static int state_release(struct inode *inode, struct file *file)
-{
- state.busy = 0;
- return 0;
-}
-
-
-static ssize_t state_read(struct file *file, char *buf, size_t count,
- loff_t *ppos)
-{
- int n = state.len - state.ptr;
- if (n > count)
- n = count;
- if (n <= 0)
- return 0;
- if (copy_to_user(buf, &state.buf[state.ptr], n))
- return -EFAULT;
- state.ptr += n;
- return n;
-}
-
-
-static const struct file_operations state_fops =
-{
- .owner = THIS_MODULE,
- .llseek = sound_lseek,
- .read = state_read,
- .open = state_open,
- .release = state_release,
-};
-
-
-static void __init state_init(void)
-{
- state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
- if (state_unit < 0)
- return;
- state.busy = 0;
-}
-
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig)
-{
- return -ESPIPE;
-}
-
-
-/*** Config & Setup **********************************************************/
-
-
-int __init tdm8xx_sound_init(void)
-{
- int i, has_sound;
- uint dp_offset;
- volatile uint *sirp;
- volatile cbd_t *bdp;
- volatile cpm8xx_t *cp;
- volatile smc_t *sp;
- volatile smc_uart_t *up;
- volatile immap_t *immap;
-
- has_sound = 0;
-
- /* Program the SI/TSA to use TDMa, connected to SMC2, for 4 bytes.
- */
- cp = cpmp; /* Get pointer to Communication Processor */
- immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
-
- /* Set all TDMa control bits to zero. This enables most features
- * we want.
- */
- cp->cp_simode &= ~0x00000fff;
-
- /* Enable common receive/transmit clock pins, use IDL format.
- * Sync on falling edge, transmit rising clock, receive falling
- * clock, delay 1 bit on both Tx and Rx. Common Tx/Rx clocks and
- * sync.
- * Connect SMC2 to TSA.
- */
- cp->cp_simode |= 0x80000141;
-
- /* Configure port A pins for TDMa operation.
- * The RPX-Lite (MPC850/823) loses SMC2 when TDM is used.
- */
- immap->im_ioport.iop_papar |= 0x01c0; /* Enable TDMa functions */
- immap->im_ioport.iop_padir |= 0x00c0; /* Enable TDMa Tx/Rx */
- immap->im_ioport.iop_padir &= ~0x0100; /* Enable L1RCLKa */
-
- immap->im_ioport.iop_pcpar |= 0x0800; /* Enable L1RSYNCa */
- immap->im_ioport.iop_pcdir &= ~0x0800;
-
- /* Initialize the SI TDM routing table. We use TDMa only.
- * The receive table and transmit table each have only one
- * entry, to capture/send four bytes after each frame pulse.
- * The 16-bit ram entry is 0000 0001 1000 1111. (SMC2)
- */
- cp->cp_sigmr = 0;
- sirp = (uint *)cp->cp_siram;
-
- *sirp = 0x018f0000; /* Receive entry */
- sirp += 64;
- *sirp = 0x018f0000; /* Tramsmit entry */
-
- /* Enable single TDMa routing.
- */
- cp->cp_sigmr = 0x04;
-
- /* Initialize the SMC for transparent operation.
- */
- sp = &cpmp->cp_smc[1];
- up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC2];
-
- /* We need to allocate a transmit and receive buffer
- * descriptors from dual port ram.
- */
- dp_addr = cpm_dpalloc(sizeof(cbd_t) * numReadBufs, 8);
-
- /* Set the physical address of the host memory
- * buffers in the buffer descriptors, and the
- * virtual address for us to work with.
- */
- bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
- up->smc_rbase = dp_offset;
- rx_cur = rx_base = (cbd_t *)bdp;
-
- for (i=0; i<(numReadBufs-1); i++) {
- bdp->cbd_bufaddr = 0;
- bdp->cbd_datlen = 0;
- bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
- bdp++;
- }
- bdp->cbd_bufaddr = 0;
- bdp->cbd_datlen = 0;
- bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
-
- /* Now, do the same for the transmit buffers.
- */
- dp_offset = cpm_dpalloc(sizeof(cbd_t) * numBufs, 8);
-
- bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
- up->smc_tbase = dp_offset;
- tx_cur = tx_base = (cbd_t *)bdp;
-
- for (i=0; i<(numBufs-1); i++) {
- bdp->cbd_bufaddr = 0;
- bdp->cbd_datlen = 0;
- bdp->cbd_sc = BD_SC_INTRPT;
- bdp++;
- }
- bdp->cbd_bufaddr = 0;
- bdp->cbd_datlen = 0;
- bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
-
- /* Set transparent SMC mode.
- * A few things are specific to our application. The codec interface
- * is MSB first, hence the REVD selection. The CD/CTS pulse are
- * used by the TSA to indicate the frame start to the SMC.
- */
- up->smc_rfcr = SCC_EB;
- up->smc_tfcr = SCC_EB;
- up->smc_mrblr = readbufSize * 1024;
-
- /* Set 16-bit reversed data, transparent mode.
- */
- sp->smc_smcmr = smcr_mk_clen(15) |
- SMCMR_SM_TRANS | SMCMR_REVD | SMCMR_BS;
-
- /* Enable and clear events.
- * Because of FIFO delays, all we need is the receive interrupt
- * and we can process both the current receive and current
- * transmit interrupt within a few microseconds of the transmit.
- */
- sp->smc_smce = 0xff;
- sp->smc_smcm = SMCM_TXE | SMCM_TX | SMCM_RX;
-
- /* Send the CPM an initialize command.
- */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
- CPM_CR_INIT_TRX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
-
- sound.mach = mach_cs4218;
- has_sound = 1;
-
- /* Initialize beep stuff */
- orig_mksound = kd_mksound;
- kd_mksound = cs_mksound;
- beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
- if (beep_buf == NULL)
- printk(KERN_WARNING "dmasound: no memory for "
- "beep buffer\n");
-
- if (!has_sound)
- return -ENODEV;
-
- /* Initialize the software SPI.
- */
- sw_spi_init();
-
- /* Set up sound queue, /dev/audio and /dev/dsp. */
-
- /* Set default settings. */
- sq_init();
-
- /* Set up /dev/sndstat. */
- state_init();
-
- /* Set up /dev/mixer. */
- mixer_init();
-
- if (!sound.mach.irqinit()) {
- printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
- return -ENODEV;
- }
-#ifdef MODULE
- irq_installed = 1;
-#endif
-
- printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
- numBufs, bufSize);
-
- return 0;
-}
-
-/* Due to FIFOs and bit delays, the transmit interrupt occurs a few
- * microseconds ahead of the receive interrupt.
- * When we get an interrupt, we service the transmit first, then
- * check for a receive to prevent the overhead of returning through
- * the interrupt handler only to get back here right away during
- * full duplex operation.
- */
-static void
-cs4218_intr(void *dev_id)
-{
- volatile smc_t *sp;
- volatile cpm8xx_t *cp;
-
- sp = &cpmp->cp_smc[1];
-
- if (sp->smc_smce & SCCM_TX) {
- sp->smc_smce = SCCM_TX;
- cs4218_tdm_tx_intr((void *)sp);
- }
-
- if (sp->smc_smce & SCCM_RX) {
- sp->smc_smce = SCCM_RX;
- cs4218_tdm_rx_intr((void *)sp);
- }
-
- if (sp->smc_smce & SCCM_TXE) {
- /* Transmit underrun. This happens with the application
- * didn't keep up sending buffers. We tell the SMC to
- * restart, which will cause it to poll the current (next)
- * BD. If the user supplied data since this occurred,
- * we just start running again. If they didn't, the SMC
- * will poll the descriptor until data is placed there.
- */
- sp->smc_smce = SCCM_TXE;
- cp = cpmp; /* Get pointer to Communication Processor */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
- CPM_CR_RESTART_TX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
- }
-}
-
-
-#define MAXARGS 8 /* Should be sufficient for now */
-
-void __init dmasound_setup(char *str, int *ints)
-{
- /* check the bootstrap parameter for "dmasound=" */
-
- switch (ints[0]) {
- case 3:
- if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
- printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
- else
- catchRadius = ints[3];
- /* fall through */
- case 2:
- if (ints[1] < MIN_BUFFERS)
- printk("dmasound_setup: invalid number of buffers, using default = %d\n", numBufs);
- else
- numBufs = ints[1];
- if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
- printk("dmasound_setup: invalid buffer size, using default = %d\n", bufSize);
- else
- bufSize = ints[2];
- break;
- case 0:
- break;
- default:
- printk("dmasound_setup: invalid number of arguments\n");
- }
-}
-
-/* Software SPI functions.
- * These are on Port B.
- */
-#define PB_SPICLK ((uint)0x00000002)
-#define PB_SPIMOSI ((uint)0x00000004)
-#define PB_SPIMISO ((uint)0x00000008)
-
-static
-void sw_spi_init(void)
-{
- volatile cpm8xx_t *cp;
- volatile uint *hcsr4;
-
- hcsr4 = (volatile uint *)HIOX_CSR4_ADDR;
- cp = cpmp; /* Get pointer to Communication Processor */
-
- *hcsr4 &= ~HIOX_CSR4_AUDSPISEL; /* Disable SPI select */
-
- /* Make these Port B signals general purpose I/O.
- * First, make sure the clock is low.
- */
- cp->cp_pbdat &= ~PB_SPICLK;
- cp->cp_pbpar &= ~(PB_SPICLK | PB_SPIMOSI | PB_SPIMISO);
-
- /* Clock and Master Output are outputs.
- */
- cp->cp_pbdir |= (PB_SPICLK | PB_SPIMOSI);
-
- /* Master Input.
- */
- cp->cp_pbdir &= ~PB_SPIMISO;
-
-}
-
-/* Write the CS4218 control word out the SPI port. While the
- * the control word is going out, the status word is arriving.
- */
-static
-uint cs4218_ctl_write(uint ctlreg)
-{
- uint status;
-
- sw_spi_io((u_char *)&ctlreg, (u_char *)&status, 4);
-
- /* Shadow the control register.....I guess we could do
- * the same for the status, but for now we just return it
- * and let the caller decide.
- */
- cs4218_control = ctlreg;
- return status;
-}
-
-static
-void sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt)
-{
- int bits, i;
- u_char outbyte, inbyte;
- volatile cpm8xx_t *cp;
- volatile uint *hcsr4;
-
- hcsr4 = (volatile uint *)HIOX_CSR4_ADDR;
- cp = cpmp; /* Get pointer to Communication Processor */
-
- /* The timing on the bus is pretty slow. Code inefficiency
- * and eieio() is our friend here :-).
- */
- cp->cp_pbdat &= ~PB_SPICLK;
- *hcsr4 |= HIOX_CSR4_AUDSPISEL; /* Enable SPI select */
- eieio();
-
- /* Clock in/out the bytes. Data is valid on the falling edge
- * of the clock. Data is MSB first.
- */
- for (i=0; i<bcnt; i++) {
- outbyte = *obuf++;
- inbyte = 0;
- for (bits=0; bits<8; bits++) {
- eieio();
- cp->cp_pbdat |= PB_SPICLK;
- eieio();
- if (outbyte & 0x80)
- cp->cp_pbdat |= PB_SPIMOSI;
- else
- cp->cp_pbdat &= ~PB_SPIMOSI;
- eieio();
- cp->cp_pbdat &= ~PB_SPICLK;
- eieio();
- outbyte <<= 1;
- inbyte <<= 1;
- if (cp->cp_pbdat & PB_SPIMISO)
- inbyte |= 1;
- }
- *ibuf++ = inbyte;
- }
-
- *hcsr4 &= ~HIOX_CSR4_AUDSPISEL; /* Disable SPI select */
- eieio();
-}
-
-void cleanup_module(void)
-{
- if (irq_installed) {
- sound_silence();
-#ifdef MODULE
- sound.mach.irqcleanup();
-#endif
- }
-
- sq_release_read_buffers();
- sq_release_buffers();
-
- if (mixer_unit >= 0)
- unregister_sound_mixer(mixer_unit);
- if (state_unit >= 0)
- unregister_sound_special(state_unit);
- if (sq_unit >= 0)
- unregister_sound_dsp(sq_unit);
-}
-
-module_init(tdm8xx_sound_init);
-module_exit(cleanup_module);
-
diff --git a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c
index 8e1fccd96fc0..9589969cec72 100644
--- a/arch/ppc/boot/common/misc-common.c
+++ b/arch/ppc/boot/common/misc-common.c
@@ -57,7 +57,8 @@ unsigned char *ISA_io = NULL;
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
extern unsigned long com_port;
extern int serial_tstc(unsigned long com_port);
@@ -80,7 +81,8 @@ int tstc(void)
{
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
if(keyb_present)
return (CRT_tstc() || serial_tstc(com_port));
else
@@ -95,7 +97,8 @@ int getc(void)
while (1) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
if (serial_tstc(com_port))
return (serial_getc(com_port));
#endif /* serial console */
@@ -112,7 +115,8 @@ putc(const char c)
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' )
serial_putc(com_port, '\r');
@@ -161,7 +165,8 @@ void puts(const char *s)
while ( ( c = *s++ ) != '\0' ) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' ) serial_putc(com_port, '\r');
#endif /* serial console */
diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
index bcfb6cde70c4..5b877792d14f 100644
--- a/arch/ppc/boot/simple/Makefile
+++ b/arch/ppc/boot/simple/Makefile
@@ -201,6 +201,7 @@ boot-$(CONFIG_8260) += m8260_tty.o
endif
boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o
boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
+boot-$(CONFIG_SERIAL_UARTLITE_CONSOLE) += uartlite_tty.o
LIBS := $(common)/lib.a $(bootlib)/lib.a
ifeq ($(CONFIG_PPC_PREP),y)
diff --git a/arch/ppc/boot/simple/uartlite_tty.c b/arch/ppc/boot/simple/uartlite_tty.c
new file mode 100644
index 000000000000..0eae1eab38d4
--- /dev/null
+++ b/arch/ppc/boot/simple/uartlite_tty.c
@@ -0,0 +1,37 @@
+/*
+ * Xilinx UARTLITE bootloader driver
+ *
+ * Copyright (c) 2007 Secret Lab Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+#define UARTLITE_BASEADDR ((void*)(XPAR_UARTLITE_0_BASEADDR))
+
+void
+serial_putc(unsigned long com_port, unsigned char c)
+{
+ while ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x08) != 0); /* spin */
+ out_be32(UARTLITE_BASEADDR + 0x4, c);
+}
+
+unsigned char
+serial_getc(unsigned long com_port)
+{
+ while ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x01) == 0); /* spin */
+ return in_be32(UARTLITE_BASEADDR);
+}
+
+int
+serial_tstc(unsigned long com_port)
+{
+ return ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x01) != 0);
+}
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
index 1f91eca2f3d7..c5850a272650 100644
--- a/arch/ppc/kernel/asm-offsets.c
+++ b/arch/ppc/kernel/asm-offsets.c
@@ -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]));
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index a9d455369dc6..ab64256110bd 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -191,7 +191,6 @@ stack_ovf:
0:
_GLOBAL(DoSyscall)
- stw r0,THREAD+LAST_SYSCALL(r2)
stw r3,ORIG_GPR3(r1)
li r12,0
stw r12,RESULT(r1)
diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig
index 705ae56016f0..76551b679030 100644
--- a/arch/ppc/platforms/4xx/Kconfig
+++ b/arch/ppc/platforms/4xx/Kconfig
@@ -29,6 +29,7 @@ config CPCI405
config EP405
bool "EP405/EP405PC"
+ select EMBEDDEDBOOT
help
This option enables support for the EP405/EP405PC boards.
@@ -54,11 +55,15 @@ config WALNUT
config XILINX_ML300
bool "Xilinx-ML300"
+ select XILINX_VIRTEX_II_PRO
+ select EMBEDDEDBOOT
help
This option enables support for the Xilinx ML300 evaluation board.
config XILINX_ML403
bool "Xilinx-ML403"
+ select XILINX_VIRTEX_4_FX
+ select EMBEDDEDBOOT
help
This option enables support for the Xilinx ML403 evaluation board.
endchoice
@@ -215,18 +220,14 @@ config 405GPR
config XILINX_VIRTEX_II_PRO
bool
- depends on XILINX_ML300
- default y
+ select XILINX_VIRTEX
config XILINX_VIRTEX_4_FX
bool
- depends on XILINX_ML403
- default y
+ select XILINX_VIRTEX
config XILINX_VIRTEX
bool
- depends on XILINX_VIRTEX_II_PRO || XILINX_VIRTEX_4_FX
- default y
config STB03xxx
bool
@@ -235,8 +236,6 @@ config STB03xxx
config EMBEDDEDBOOT
bool
- depends on EP405 || XILINX_ML300 || XILINX_ML403
- default y
config IBM_OPENBIOS
bool
diff --git a/arch/ppc/platforms/4xx/Makefile b/arch/ppc/platforms/4xx/Makefile
index fa6610bccaf9..723ad7985cc6 100644
--- a/arch/ppc/platforms/4xx/Makefile
+++ b/arch/ppc/platforms/4xx/Makefile
@@ -28,5 +28,4 @@ obj-$(CONFIG_440SP) += ibm440sp.o
obj-$(CONFIG_440SPE) += ppc440spe.o
obj-$(CONFIG_405EP) += ibm405ep.o
obj-$(CONFIG_405GPR) += ibm405gpr.o
-obj-$(CONFIG_XILINX_VIRTEX) += virtex.o
diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
index 84e999d9a7bb..5e994e146ba8 100644
--- a/arch/ppc/platforms/4xx/ocotea.c
+++ b/arch/ppc/platforms/4xx/ocotea.c
@@ -178,7 +178,7 @@ ocotea_setup_pcix(void)
/* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
- PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+ PCIX_WRITEL(0x80000007, PCIX0_PIM0SA);
eieio();
}
@@ -289,7 +289,7 @@ ocotea_setup_arch(void)
* from FPGA, because it can be changed by on-board switches
* --ebs
*/
- ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200);
+ ibm440gx_get_clocks(&clocks, 33300000, 6 * 1843200);
ocp_sys_info.opb_bus_freq = clocks.opb;
/* Setup TODC access */
diff --git a/arch/ppc/platforms/4xx/taishan.c b/arch/ppc/platforms/4xx/taishan.c
index bb0253eef45a..5d9af8ddb155 100644
--- a/arch/ppc/platforms/4xx/taishan.c
+++ b/arch/ppc/platforms/4xx/taishan.c
@@ -235,7 +235,7 @@ taishan_setup_pcix(void)
/* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
- PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+ PCIX_WRITEL(0x80000007, PCIX0_PIM0SA);
PCIX_WRITEL(0xffffffff, PCIX0_PIM0SAH);
iounmap(pcix_reg_base);
diff --git a/arch/ppc/platforms/4xx/virtex.c b/arch/ppc/platforms/4xx/virtex.c
deleted file mode 100644
index 133a83147199..000000000000
--- a/arch/ppc/platforms/4xx/virtex.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Virtex-II Pro & Virtex-4 FX common infrastructure
- *
- * Maintainer: Grant Likely <grant.likely@secretlab.ca>
- *
- * Copyright 2005 Secret Lab Technologies Ltd.
- * Copyright 2005 General Dynamics Canada Ltd.
- * Copyright 2005 Freescale Semiconductor Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/serial_8250.h>
-#include <asm/ppc_sys.h>
-#include <platforms/4xx/virtex.h>
-#include <platforms/4xx/xparameters/xparameters.h>
-
-#define XPAR_UART(num) { \
- .mapbase = XPAR_UARTNS550_##num##_BASEADDR + 3, \
- .irq = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
- .iotype = UPIO_MEM, \
- .uartclk = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \
- .flags = UPF_BOOT_AUTOCONF, \
- .regshift = 2, \
- }
-
-struct plat_serial8250_port serial_platform_data[] = {
-#ifdef XPAR_UARTNS550_0_BASEADDR
- XPAR_UART(0),
-#endif
-#ifdef XPAR_UARTNS550_1_BASEADDR
- XPAR_UART(1),
-#endif
-#ifdef XPAR_UARTNS550_2_BASEADDR
- XPAR_UART(2),
-#endif
-#ifdef XPAR_UARTNS550_3_BASEADDR
- XPAR_UART(3),
-#endif
- { }, /* terminated by empty record */
-};
-
-struct platform_device ppc_sys_platform_devices[] = {
- [VIRTEX_UART] = {
- .name = "serial8250",
- .id = 0,
- .dev.platform_data = serial_platform_data,
- },
-};
-
diff --git a/arch/ppc/platforms/4xx/virtex.h b/arch/ppc/platforms/4xx/virtex.h
index c14325dfd7b1..738280420be5 100644
--- a/arch/ppc/platforms/4xx/virtex.h
+++ b/arch/ppc/platforms/4xx/virtex.h
@@ -1,35 +1,35 @@
/*
- * arch/ppc/platforms/4xx/virtex.h
+ * Basic Virtex platform defines, included by <asm/ibm4xx.h>
*
- * Include file that defines the Xilinx Virtex-II Pro processor
+ * 2005-2007 (c) Secret Lab Technologies Ltd.
+ * 2002-2004 (c) MontaVista Software, Inc.
*
- * Author: MontaVista Software, Inc.
- * source@mvista.com
- *
- * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under the
- * terms of the GNU General Public License version 2. This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
*/
#ifdef __KERNEL__
#ifndef __ASM_VIRTEX_H__
#define __ASM_VIRTEX_H__
-/* serial defines */
-
#include <asm/ibm405.h>
+#include <asm/ppcboot.h>
/* Ugly, ugly, ugly! BASE_BAUD defined here to keep 8250.c happy. */
#if !defined(BASE_BAUD)
#define BASE_BAUD (0) /* dummy value; not used */
#endif
-
-/* Device type enumeration for platform bus definitions */
+
#ifndef __ASSEMBLY__
-enum ppc_sys_devices {
- VIRTEX_UART, NUM_PPC_SYS_DEVS,
-};
-#endif
-
+extern const char* virtex_machine_name;
+#define PPC4xx_MACHINE_NAME (virtex_machine_name)
+#endif /* !__ASSEMBLY__ */
+
+/* We don't need anything mapped. Size of zero will accomplish that. */
+#define PPC4xx_ONB_IO_PADDR 0u
+#define PPC4xx_ONB_IO_VADDR 0u
+#define PPC4xx_ONB_IO_SIZE 0u
+
#endif /* __ASM_VIRTEX_H__ */
#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.c b/arch/ppc/platforms/4xx/xilinx_ml300.c
index fb5f0b5e13d1..6e522fefc26f 100644
--- a/arch/ppc/platforms/4xx/xilinx_ml300.c
+++ b/arch/ppc/platforms/4xx/xilinx_ml300.c
@@ -18,9 +18,9 @@
#include <linux/serialP.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/ppc_sys.h>
#include <syslib/gen550.h>
+#include <syslib/virtex_devices.h>
#include <platforms/4xx/xparameters/xparameters.h>
/*
@@ -53,24 +53,9 @@
* ppc4xx_pic_init arch/ppc/syslib/xilinx_pic.c
*/
-/* Board specifications structures */
-struct ppc_sys_spec *cur_ppc_sys_spec;
-struct ppc_sys_spec ppc_sys_specs[] = {
- {
- /* Only one entry, always assume the same design */
- .ppc_sys_name = "Xilinx ML300 Reference Design",
- .mask = 0x00000000,
- .value = 0x00000000,
- .num_devices = 1,
- .device_list = (enum ppc_sys_devices[])
- {
- VIRTEX_UART,
- },
- },
-};
+const char* virtex_machine_name = "ML300 Reference Design";
#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
-
static volatile unsigned *powerdown_base =
(volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
@@ -95,52 +80,14 @@ ml300_map_io(void)
#endif
}
-/* Early serial support functions */
-static void __init
-ml300_early_serial_init(int num, struct plat_serial8250_port *pdata)
-{
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
- struct uart_port serial_req;
-
- memset(&serial_req, 0, sizeof(serial_req));
- serial_req.mapbase = pdata->mapbase;
- serial_req.membase = pdata->membase;
- serial_req.irq = pdata->irq;
- serial_req.uartclk = pdata->uartclk;
- serial_req.regshift = pdata->regshift;
- serial_req.iotype = pdata->iotype;
- serial_req.flags = pdata->flags;
- gen550_init(num, &serial_req);
-#endif
-}
-
-void __init
-ml300_early_serial_map(void)
-{
-#ifdef CONFIG_SERIAL_8250
- struct plat_serial8250_port *pdata;
- int i = 0;
-
- pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART);
- while(pdata && pdata->flags)
- {
- pdata->membase = ioremap(pdata->mapbase, 0x100);
- ml300_early_serial_init(i, pdata);
- pdata++;
- i++;
- }
-#endif /* CONFIG_SERIAL_8250 */
-}
-
void __init
ml300_setup_arch(void)
{
- ml300_early_serial_map();
+ virtex_early_serial_map();
ppc4xx_setup_arch(); /* calls ppc4xx_find_bridges() */
/* Identify the system */
- printk(KERN_INFO "Xilinx Virtex-II Pro port\n");
- printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+ printk(KERN_INFO "Xilinx ML300 Reference System (Virtex-II Pro)\n");
}
/* Called after board_setup_irq from ppc4xx_init_IRQ(). */
@@ -156,8 +103,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
{
ppc4xx_init(r3, r4, r5, r6, r7);
- identify_ppc_sys_by_id(mfspr(SPRN_PVR));
-
ppc_md.setup_arch = ml300_setup_arch;
ppc_md.setup_io_mappings = ml300_map_io;
ppc_md.init_IRQ = ml300_init_irq;
@@ -167,7 +112,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
#endif
#ifdef CONFIG_KGDB
- ppc_md.early_serial_map = ml300_early_serial_map;
+ ppc_md.early_serial_map = virtex_early_serial_map;
#endif
}
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.h b/arch/ppc/platforms/4xx/xilinx_ml300.h
deleted file mode 100644
index 3d57332ba820..000000000000
--- a/arch/ppc/platforms/4xx/xilinx_ml300.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Include file that defines the Xilinx ML300 evaluation board
- *
- * Author: MontaVista Software, Inc.
- * source@mvista.com
- *
- * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under the
- * terms of the GNU General Public License version 2. This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_XILINX_ML300_H__
-#define __ASM_XILINX_ML300_H__
-
-/* ML300 has a Xilinx Virtex-II Pro processor */
-#include <platforms/4xx/virtex.h>
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-typedef struct board_info {
- unsigned int bi_memsize; /* DRAM installed, in bytes */
- unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */
- unsigned int bi_intfreq; /* Processor speed, in Hz */
- unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
- unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-#endif /* !__ASSEMBLY__ */
-
-/* We don't need anything mapped. Size of zero will accomplish that. */
-#define PPC4xx_ONB_IO_PADDR 0u
-#define PPC4xx_ONB_IO_VADDR 0u
-#define PPC4xx_ONB_IO_SIZE 0u
-
-#define PPC4xx_MACHINE_NAME "Xilinx ML300 Reference System"
-
-#endif /* __ASM_XILINX_ML300_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xilinx_ml403.c b/arch/ppc/platforms/4xx/xilinx_ml403.c
index cb3bf7a2bcbe..bc3ace3762e7 100644
--- a/arch/ppc/platforms/4xx/xilinx_ml403.c
+++ b/arch/ppc/platforms/4xx/xilinx_ml403.c
@@ -1,11 +1,9 @@
/*
- * arch/ppc/platforms/4xx/xilinx_ml403.c
- *
* Xilinx ML403 evaluation board initialization
*
* Author: Grant Likely <grant.likely@secretlab.ca>
*
- * 2005 (c) Secret Lab Technologies Ltd.
+ * 2005-2007 (c) Secret Lab Technologies Ltd.
* 2002-2004 (c) MontaVista Software, Inc.
*
* This file is licensed under the terms of the GNU General Public License
@@ -22,9 +20,9 @@
#include <linux/serialP.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/ppc_sys.h>
#include <syslib/gen550.h>
+#include <syslib/virtex_devices.h>
#include <platforms/4xx/xparameters/xparameters.h>
/*
@@ -57,24 +55,9 @@
* ppc4xx_pic_init arch/ppc/syslib/xilinx_pic.c
*/
-/* Board specifications structures */
-struct ppc_sys_spec *cur_ppc_sys_spec;
-struct ppc_sys_spec ppc_sys_specs[] = {
- {
- /* Only one entry, always assume the same design */
- .ppc_sys_name = "Xilinx ML403 Reference Design",
- .mask = 0x00000000,
- .value = 0x00000000,
- .num_devices = 1,
- .device_list = (enum ppc_sys_devices[])
- {
- VIRTEX_UART,
- },
- },
-};
+const char* virtex_machine_name = "ML403 Reference Design";
#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
-
static volatile unsigned *powerdown_base =
(volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
@@ -99,47 +82,10 @@ ml403_map_io(void)
#endif
}
-/* Early serial support functions */
-static void __init
-ml403_early_serial_init(int num, struct plat_serial8250_port *pdata)
-{
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
- struct uart_port serial_req;
-
- memset(&serial_req, 0, sizeof(serial_req));
- serial_req.mapbase = pdata->mapbase;
- serial_req.membase = pdata->membase;
- serial_req.irq = pdata->irq;
- serial_req.uartclk = pdata->uartclk;
- serial_req.regshift = pdata->regshift;
- serial_req.iotype = pdata->iotype;
- serial_req.flags = pdata->flags;
- gen550_init(num, &serial_req);
-#endif
-}
-
-void __init
-ml403_early_serial_map(void)
-{
-#ifdef CONFIG_SERIAL_8250
- struct plat_serial8250_port *pdata;
- int i = 0;
-
- pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART);
- while(pdata && pdata->flags)
- {
- pdata->membase = ioremap(pdata->mapbase, 0x100);
- ml403_early_serial_init(i, pdata);
- pdata++;
- i++;
- }
-#endif /* CONFIG_SERIAL_8250 */
-}
-
void __init
ml403_setup_arch(void)
{
- ml403_early_serial_map();
+ virtex_early_serial_map();
ppc4xx_setup_arch(); /* calls ppc4xx_find_bridges() */
/* Identify the system */
@@ -159,8 +105,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
{
ppc4xx_init(r3, r4, r5, r6, r7);
- identify_ppc_sys_by_id(mfspr(SPRN_PVR));
-
ppc_md.setup_arch = ml403_setup_arch;
ppc_md.setup_io_mappings = ml403_map_io;
ppc_md.init_IRQ = ml403_init_irq;
@@ -170,7 +114,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
#endif
#ifdef CONFIG_KGDB
- ppc_md.early_serial_map = ml403_early_serial_map;
+ ppc_md.early_serial_map = virtex_early_serial_map;
#endif
}
diff --git a/arch/ppc/platforms/4xx/xilinx_ml403.h b/arch/ppc/platforms/4xx/xilinx_ml403.h
deleted file mode 100644
index 473596959902..000000000000
--- a/arch/ppc/platforms/4xx/xilinx_ml403.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * arch/ppc/platforms/4xx/xilinx_ml403.h
- *
- * Include file that defines the Xilinx ML403 reference design
- *
- * Author: Grant Likely <grant.likely@secretlab.ca>
- *
- * 2005 (c) Secret Lab Technologies Ltd.
- * 2002-2004 (c) MontaVista Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_XILINX_ML403_H__
-#define __ASM_XILINX_ML403_H__
-
-/* ML403 has a Xilinx Virtex-4 FPGA with a PPC405 hard core */
-#include <platforms/4xx/virtex.h>
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-typedef struct board_info {
- unsigned int bi_memsize; /* DRAM installed, in bytes */
- unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */
- unsigned int bi_intfreq; /* Processor speed, in Hz */
- unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
- unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-#endif /* !__ASSEMBLY__ */
-
-/* We don't need anything mapped. Size of zero will accomplish that. */
-#define PPC4xx_ONB_IO_PADDR 0u
-#define PPC4xx_ONB_IO_VADDR 0u
-#define PPC4xx_ONB_IO_SIZE 0u
-
-#define PPC4xx_MACHINE_NAME "Xilinx ML403 Reference Design"
-
-#endif /* __ASM_XILINX_ML403_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xparameters/xparameters.h b/arch/ppc/platforms/4xx/xparameters/xparameters.h
index 66ec5f35f306..01aa043ff381 100644
--- a/arch/ppc/platforms/4xx/xparameters/xparameters.h
+++ b/arch/ppc/platforms/4xx/xparameters/xparameters.h
@@ -34,3 +34,63 @@
.io_type = SERIAL_IO_MEM, \
},
#endif
+
+/*
+ * A few reasonable defaults for the #defines which could be missing depending
+ * on the IP version or variant (e.g. OPB vs PLB)
+ */
+
+#ifndef XPAR_EMAC_0_CAM_EXIST
+#define XPAR_EMAC_0_CAM_EXIST 0
+#endif
+#ifndef XPAR_EMAC_0_JUMBO_EXIST
+#define XPAR_EMAC_0_JUMBO_EXIST 0
+#endif
+#ifndef XPAR_EMAC_0_TX_DRE_TYPE
+#define XPAR_EMAC_0_TX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_0_RX_DRE_TYPE
+#define XPAR_EMAC_0_RX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_0_TX_INCLUDE_CSUM
+#define XPAR_EMAC_0_TX_INCLUDE_CSUM 0
+#endif
+#ifndef XPAR_EMAC_0_RX_INCLUDE_CSUM
+#define XPAR_EMAC_0_RX_INCLUDE_CSUM 0
+#endif
+
+#ifndef XPAR_EMAC_1_CAM_EXIST
+#define XPAR_EMAC_1_CAM_EXIST 0
+#endif
+#ifndef XPAR_EMAC_1_JUMBO_EXIST
+#define XPAR_EMAC_1_JUMBO_EXIST 0
+#endif
+#ifndef XPAR_EMAC_1_TX_DRE_TYPE
+#define XPAR_EMAC_1_TX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_1_RX_DRE_TYPE
+#define XPAR_EMAC_1_RX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_1_TX_INCLUDE_CSUM
+#define XPAR_EMAC_1_TX_INCLUDE_CSUM 0
+#endif
+#ifndef XPAR_EMAC_1_RX_INCLUDE_CSUM
+#define XPAR_EMAC_1_RX_INCLUDE_CSUM 0
+#endif
+
+#ifndef XPAR_GPIO_0_IS_DUAL
+#define XPAR_GPIO_0_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_1_IS_DUAL
+#define XPAR_GPIO_1_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_2_IS_DUAL
+#define XPAR_GPIO_2_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_3_IS_DUAL
+#define XPAR_GPIO_3_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_4_IS_DUAL
+#define XPAR_GPIO_4_IS_DUAL 0
+#endif
+
diff --git a/arch/ppc/platforms/rpxclassic.h b/arch/ppc/platforms/rpxclassic.h
index 57a2a55dab8c..a3c1118e5b09 100644
--- a/arch/ppc/platforms/rpxclassic.h
+++ b/arch/ppc/platforms/rpxclassic.h
@@ -69,10 +69,6 @@ extern bd_t m8xx_board_info;
#define BCSR2_QSPACESEL ((uint)0x00004000)
#define BCSR2_FETHLEDMODE ((uint)0x00000800) /* CLLF */
-#if defined(CONFIG_HTDMSOUND)
-#include <platforms/rpxhiox.h>
-#endif
-
/* define IO_BASE for pcmcia, CLLF only */
#if !defined(CONFIG_PCI)
#define _IO_BASE 0x80000000
diff --git a/arch/ppc/platforms/rpxhiox.h b/arch/ppc/platforms/rpxhiox.h
deleted file mode 100644
index c3fa5a653762..000000000000
--- a/arch/ppc/platforms/rpxhiox.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * The Embedded Planet HIOX expansion card definitions.
- * There were a few different versions of these cards, but only
- * the one that escaped real production is defined here.
- *
- * Copyright (c) 2000 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_RPX_HIOX_DEFS
-#define __MACH_RPX_HIOX_DEFS
-
-#define HIOX_CSR_ADDR ((uint)0xfac00000)
-#define HIOX_CSR_SIZE ((uint)(4 * 1024))
-#define HIOX_CSR0_ADDR HIOX_CSR_ADDR
-#define HIOX_CSR4_ADDR ((uint)0xfac00004)
-
-#define HIOX_CSR0_DEFAULT ((uint)0x380f3c00)
-#define HIOX_CSR0_ENSCC2 ((uint)0x80000000)
-#define HIOX_CSR0_ENSMC2 ((uint)0x04000000)
-#define HIOX_CSR0_ENVDOCLK ((uint)0x02000000)
-#define HIOX_CSR0_VDORST_HL ((uint)0x01000000)
-#define HIOX_CSR0_RS232SEL ((uint)0x0000c000)
-#define HIOX_CSR0_SCC3SEL ((uint)0x0000c000)
-#define HIOX_CSR0_SMC1SEL ((uint)0x00008000)
-#define HIOX_CSR0_SCC1SEL ((uint)0x00004000)
-#define HIOX_CSR0_ENTOUCH ((uint)0x00000080)
-#define HIOX_CSR0_PDOWN100 ((uint)0x00000060)
-#define HIOX_CSR0_PDOWN10 ((uint)0x00000040)
-#define HIOX_CSR0_PDOWN1 ((uint)0x00000020)
-#define HIOX_CSR0_TSELSPI ((uint)0x00000010)
-#define HIOX_CSR0_TIRQSTAT ((uint)0x00000008)
-#define HIOX_CSR4_DEFAULT ((uint)0x00000000)
-#define HIOX_CSR4_ENTIRQ2 ((uint)0x20000000)
-#define HIOX_CSR4_ENTIRQ3 ((uint)0x10000000)
-#define HIOX_CSR4_ENAUDIO ((uint)0x00000080)
-#define HIOX_CSR4_RSTAUDIO ((uint)0x00000040) /* 0 == reset */
-#define HIOX_CSR4_AUDCLKHI ((uint)0x00000020)
-#define HIOX_CSR4_AUDSPISEL ((uint)0x00000010)
-#define HIOX_CSR4_AUDIRQSTAT ((uint)0x00000008)
-#define HIOX_CSR4_AUDCLKSEL ((uint)0x00000007)
-
-#endif
diff --git a/arch/ppc/platforms/rpxlite.h b/arch/ppc/platforms/rpxlite.h
index 719780646270..b615501d55fc 100644
--- a/arch/ppc/platforms/rpxlite.h
+++ b/arch/ppc/platforms/rpxlite.h
@@ -57,10 +57,6 @@ extern bd_t m8xx_board_info;
#define BCSR1_PCVCTL6 ((uint)0x00020000)
#define BCSR1_PCVCTL7 ((uint)0x00010000)
-#if defined(CONFIG_HTDMSOUND)
-#include <platforms/rpxhiox.h>
-#endif
-
/* define IO_BASE for pcmcia */
#define _IO_BASE 0x80000000
#define _IO_BASE_SIZE 0x1000
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 09911118c675..95694159b226 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -18,7 +18,8 @@ obj-$(CONFIG_440SP) += ibm440gx_common.o ibm440sp_common.o
obj-$(CONFIG_440SPE) += ibm440gx_common.o ibm440sp_common.o ppc440spe_pcie.o
ifeq ($(CONFIG_4xx),y)
ifeq ($(CONFIG_XILINX_VIRTEX),y)
-obj-$(CONFIG_40x) += xilinx_pic.o ppc_sys.o
+obj-$(CONFIG_40x) += xilinx_pic.o
+obj-y += virtex_devices.o
else
ifeq ($(CONFIG_403),y)
obj-$(CONFIG_40x) += ppc403_pic.o
diff --git a/arch/ppc/syslib/cpc710.h b/arch/ppc/syslib/cpc710.h
deleted file mode 100644
index 5299bf8b5d01..000000000000
--- a/arch/ppc/syslib/cpc710.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Definitions for the IBM CPC710 PCI Host Bridge
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __PPC_PLATFORMS_CPC710_H
-#define __PPC_PLATFORMS_CPC710_H
-
-/* General bridge and memory controller registers */
-#define PIDR 0xff000008
-#define CNFR 0xff00000c
-#define RSTR 0xff000010
-#define UCTL 0xff001000
-#define MPSR 0xff001010
-#define SIOC 0xff001020
-#define ABCNTL 0xff001030
-#define SRST 0xff001040
-#define ERRC 0xff001050
-#define SESR 0xff001060
-#define SEAR 0xff001070
-#define SIOC1 0xff001090
-#define PGCHP 0xff001100
-#define GPDIR 0xff001130
-#define GPOUT 0xff001150
-#define ATAS 0xff001160
-#define AVDG 0xff001170
-#define MCCR 0xff001200
-#define MESR 0xff001220
-#define MEAR 0xff001230
-#define MCER0 0xff001300
-#define MCER1 0xff001310
-#define MCER2 0xff001320
-#define MCER3 0xff001330
-#define MCER4 0xff001340
-#define MCER5 0xff001350
-#define MCER6 0xff001360
-#define MCER7 0xff001370
-
-/*
- * PCI32/64 configuration registers
- * Given as offsets from their
- * respective physical segment BAR
- */
-#define PIBAR 0x000f7800
-#define PMBAR 0x000f7810
-#define MSIZE 0x000f7f40
-#define IOSIZE 0x000f7f60
-#define SMBAR 0x000f7f80
-#define SIBAR 0x000f7fc0
-#define PSSIZE 0x000f8100
-#define PPSIZE 0x000f8110
-#define BARPS 0x000f8120
-#define BARPP 0x000f8130
-#define PSBAR 0x000f8140
-#define PPBAR 0x000f8150
-#define BPMDLK 0x000f8200 /* Bottom of Peripheral Memory Space */
-#define TPMDLK 0x000f8210 /* Top of Peripheral Memory Space */
-#define BIODLK 0x000f8220 /* Bottom of Peripheral I/O Space */
-#define TIODLK 0x000f8230 /* Top of Perioheral I/O Space */
-#define DLKCTRL 0x000f8240 /* Deadlock control */
-#define DLKDEV 0x000f8250 /* Deadlock device */
-
-/* System standard configuration registers space */
-#define DCR 0xff200000
-#define DID 0xff200004
-#define BAR 0xff200018
-
-/* Device specific configuration space */
-#define PCIENB 0xff201000
-
-/* Configuration space registers */
-#define CPC710_BUS_NUMBER 0x40
-#define CPC710_SUB_BUS_NUMBER 0x41
-
-#endif /* __PPC_PLATFORMS_CPC710_H */
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index 01e48d88f22d..9caf850c9b38 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -413,7 +413,7 @@ m8xx_map_io(void)
io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
#endif
#endif
-#if defined(CONFIG_HTDMSOUND) || defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
+#if defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO);
#endif
#ifdef CONFIG_FADS
diff --git a/arch/ppc/syslib/ppc4xx_sgdma.c b/arch/ppc/syslib/ppc4xx_sgdma.c
index 2f83e162971f..939abe3c1f45 100644
--- a/arch/ppc/syslib/ppc4xx_sgdma.c
+++ b/arch/ppc/syslib/ppc4xx_sgdma.c
@@ -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
index 000000000000..16546788e23b
--- /dev/null
+++ b/arch/ppc/syslib/virtex_devices.c
@@ -0,0 +1,233 @@
+/*
+ * Virtex hard ppc405 core common device listing
+ *
+ * Copyright 2005-2007 Secret Lab Technologies Ltd.
+ * Copyright 2005 Freescale Semiconductor Inc.
+ * Copyright 2002-2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <syslib/virtex_devices.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+#include <asm/io.h>
+
+/*
+ * UARTLITE: shortcut macro for single instance
+ */
+#define XPAR_UARTLITE(num) { \
+ .name = "uartlite", \
+ .id = num, \
+ .num_resources = 2, \
+ .resource = (struct resource[]) { \
+ { \
+ .start = XPAR_UARTLITE_##num##_BASEADDR + 3, \
+ .end = XPAR_UARTLITE_##num##_HIGHADDR, \
+ .flags = IORESOURCE_MEM, \
+ }, \
+ { \
+ .start = XPAR_INTC_0_UARTLITE_##num##_VEC_ID, \
+ .flags = IORESOURCE_IRQ, \
+ }, \
+ }, \
+}
+
+/*
+ * Full UART: shortcut macro for single instance + platform data structure
+ */
+#define XPAR_UART(num) { \
+ .mapbase = XPAR_UARTNS550_##num##_BASEADDR + 3, \
+ .irq = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
+ .iotype = UPIO_MEM, \
+ .uartclk = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \
+ .flags = UPF_BOOT_AUTOCONF, \
+ .regshift = 2, \
+}
+
+/*
+ * SystemACE: shortcut macro for single instance
+ */
+#define XPAR_SYSACE(num) { \
+ .name = "xsysace", \
+ .id = XPAR_SYSACE_##num##_DEVICE_ID, \
+ .num_resources = 2, \
+ .resource = (struct resource[]) { \
+ { \
+ .start = XPAR_SYSACE_##num##_BASEADDR, \
+ .end = XPAR_SYSACE_##num##_HIGHADDR, \
+ .flags = IORESOURCE_MEM, \
+ }, \
+ { \
+ .start = XPAR_INTC_0_SYSACE_##num##_VEC_ID, \
+ .flags = IORESOURCE_IRQ, \
+ }, \
+ }, \
+}
+
+
+/* UART 8250 driver platform data table */
+struct plat_serial8250_port virtex_serial_platform_data[] = {
+#if defined(XPAR_UARTNS550_0_BASEADDR)
+ XPAR_UART(0),
+#endif
+#if defined(XPAR_UARTNS550_1_BASEADDR)
+ XPAR_UART(1),
+#endif
+#if defined(XPAR_UARTNS550_2_BASEADDR)
+ XPAR_UART(2),
+#endif
+#if defined(XPAR_UARTNS550_3_BASEADDR)
+ XPAR_UART(3),
+#endif
+#if defined(XPAR_UARTNS550_4_BASEADDR)
+ XPAR_UART(4),
+#endif
+#if defined(XPAR_UARTNS550_5_BASEADDR)
+ XPAR_UART(5),
+#endif
+#if defined(XPAR_UARTNS550_6_BASEADDR)
+ XPAR_UART(6),
+#endif
+#if defined(XPAR_UARTNS550_7_BASEADDR)
+ XPAR_UART(7),
+#endif
+ { }, /* terminated by empty record */
+};
+
+
+struct platform_device virtex_platform_devices[] = {
+ /* UARTLITE instances */
+#if defined(XPAR_UARTLITE_0_BASEADDR)
+ XPAR_UARTLITE(0),
+#endif
+#if defined(XPAR_UARTLITE_1_BASEADDR)
+ XPAR_UARTLITE(1),
+#endif
+#if defined(XPAR_UARTLITE_2_BASEADDR)
+ XPAR_UARTLITE(2),
+#endif
+#if defined(XPAR_UARTLITE_3_BASEADDR)
+ XPAR_UARTLITE(3),
+#endif
+#if defined(XPAR_UARTLITE_4_BASEADDR)
+ XPAR_UARTLITE(4),
+#endif
+#if defined(XPAR_UARTLITE_5_BASEADDR)
+ XPAR_UARTLITE(5),
+#endif
+#if defined(XPAR_UARTLITE_6_BASEADDR)
+ XPAR_UARTLITE(6),
+#endif
+#if defined(XPAR_UARTLITE_7_BASEADDR)
+ XPAR_UARTLITE(7),
+#endif
+
+ /* Full UART instances */
+#if defined(XPAR_UARTNS550_0_BASEADDR)
+ {
+ .name = "serial8250",
+ .id = 0,
+ .dev.platform_data = virtex_serial_platform_data,
+ },
+#endif
+
+ /* SystemACE instances */
+#if defined(XPAR_SYSACE_0_BASEADDR)
+ XPAR_SYSACE(0),
+#endif
+#if defined(XPAR_SYSACE_1_BASEADDR)
+ XPAR_SYSACE(1),
+#endif
+
+ /* ML300/403 reference design framebuffer */
+#if defined(XPAR_TFT_0_BASEADDR)
+ {
+ .name = "xilinxfb",
+ .id = 0,
+ .num_resources = 1,
+ .resource = (struct resource[]) {
+ {
+ .start = XPAR_TFT_0_BASEADDR,
+ .end = XPAR_TFT_0_BASEADDR+7,
+ .flags = IORESOURCE_IO,
+ },
+ },
+ },
+#endif
+};
+
+/* Early serial support functions */
+static void __init
+virtex_early_serial_init(int num, struct plat_serial8250_port *pdata)
+{
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+ struct uart_port serial_req;
+
+ memset(&serial_req, 0, sizeof(serial_req));
+ serial_req.mapbase = pdata->mapbase;
+ serial_req.membase = pdata->membase;
+ serial_req.irq = pdata->irq;
+ serial_req.uartclk = pdata->uartclk;
+ serial_req.regshift = pdata->regshift;
+ serial_req.iotype = pdata->iotype;
+ serial_req.flags = pdata->flags;
+ gen550_init(num, &serial_req);
+#endif
+}
+
+void __init
+virtex_early_serial_map(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct plat_serial8250_port *pdata;
+ int i = 0;
+
+ pdata = virtex_serial_platform_data;
+ while(pdata && pdata->flags) {
+ pdata->membase = ioremap(pdata->mapbase, 0x100);
+ virtex_early_serial_init(i, pdata);
+ pdata++;
+ i++;
+ }
+#endif /* CONFIG_SERIAL_8250 */
+}
+
+/*
+ * default fixup routine; do nothing and return success.
+ *
+ * Reimplement this routine in your custom board support file to
+ * override the default behaviour
+ */
+int __attribute__ ((weak))
+virtex_device_fixup(struct platform_device *dev)
+{
+ return 0;
+}
+
+static int __init virtex_init(void)
+{
+ struct platform_device *index = virtex_platform_devices;
+ unsigned int ret = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(virtex_platform_devices); i++, index++) {
+ if (virtex_device_fixup(index) != 0)
+ continue;
+
+ if (platform_device_register(index)) {
+ ret = 1;
+ printk(KERN_ERR "cannot register dev %s:%d\n",
+ index->name, index->id);
+ }
+ }
+ return ret;
+}
+
+subsys_initcall(virtex_init);
diff --git a/arch/ppc/syslib/virtex_devices.h b/arch/ppc/syslib/virtex_devices.h
new file mode 100644
index 000000000000..4a17dd3927c1
--- /dev/null
+++ b/arch/ppc/syslib/virtex_devices.h
@@ -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__ */
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 7a1e251e333d..b26378815b91 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -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
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index f92ba2a869b4..64df3fa303b0 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/elevator.h>
-#include <linux/hash.h>
#include <linux/rbtree.h>
#include <linux/ioprio.h>
@@ -26,19 +25,17 @@ static int cfq_slice_async = HZ / 25;
static const int cfq_slice_async_rq = 2;
static int cfq_slice_idle = HZ / 125;
+/*
+ * grace period before allowing idle class to get disk access
+ */
#define CFQ_IDLE_GRACE (HZ / 10)
-#define CFQ_SLICE_SCALE (5)
-
-#define CFQ_KEY_ASYNC (0)
/*
- * for the hash of cfqq inside the cfqd
+ * below this threshold, we consider thinktime immediate
*/
-#define CFQ_QHASH_SHIFT 6
-#define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT)
-#define list_entry_qhash(entry) hlist_entry((entry), struct cfq_queue, cfq_hash)
+#define CFQ_MIN_TT (2)
-#define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list)
+#define CFQ_SLICE_SCALE (5)
#define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private)
#define RQ_CFQQ(rq) ((rq)->elevator_private2)
@@ -56,17 +53,21 @@ static struct completion *ioc_gone;
#define ASYNC (0)
#define SYNC (1)
-#define cfq_cfqq_dispatched(cfqq) \
- ((cfqq)->on_dispatch[ASYNC] + (cfqq)->on_dispatch[SYNC])
-
-#define cfq_cfqq_class_sync(cfqq) ((cfqq)->key != CFQ_KEY_ASYNC)
-
-#define cfq_cfqq_sync(cfqq) \
- (cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC])
-
#define sample_valid(samples) ((samples) > 80)
/*
+ * Most of our rbtree usage is for sorting with min extraction, so
+ * if we cache the leftmost node we don't have to walk down the tree
+ * to find it. Idea borrowed from Ingo Molnars CFS scheduler. We should
+ * move this into the elevator for the rq sorting as well.
+ */
+struct cfq_rb_root {
+ struct rb_root rb;
+ struct rb_node *left;
+};
+#define CFQ_RB_ROOT (struct cfq_rb_root) { RB_ROOT, NULL, }
+
+/*
* Per block device queue structure
*/
struct cfq_data {
@@ -75,18 +76,11 @@ struct cfq_data {
/*
* rr list of queues with requests and the count of them
*/
- struct list_head rr_list[CFQ_PRIO_LISTS];
- struct list_head busy_rr;
- struct list_head cur_rr;
- struct list_head idle_rr;
+ struct cfq_rb_root service_tree;
unsigned int busy_queues;
- /*
- * cfqq lookup hash
- */
- struct hlist_head *cfq_hash;
-
int rq_in_driver;
+ int sync_flight;
int hw_tag;
/*
@@ -97,12 +91,10 @@ struct cfq_data {
struct cfq_queue *active_queue;
struct cfq_io_context *active_cic;
- int cur_prio, cur_end_prio;
- unsigned int dispatch_slice;
struct timer_list idle_class_timer;
- sector_t last_sector;
+ sector_t last_position;
unsigned long last_end_request;
/*
@@ -117,6 +109,9 @@ struct cfq_data {
unsigned int cfq_slice_idle;
struct list_head cic_list;
+
+ sector_t new_seek_mean;
+ u64 new_seek_total;
};
/*
@@ -127,12 +122,10 @@ struct cfq_queue {
atomic_t ref;
/* parent cfq_data */
struct cfq_data *cfqd;
- /* cfqq lookup hash */
- struct hlist_node cfq_hash;
- /* hash key */
- unsigned int key;
- /* member of the rr/busy/cur/idle cfqd list */
- struct list_head cfq_list;
+ /* service_tree member */
+ struct rb_node rb_node;
+ /* service_tree key */
+ unsigned long rb_key;
/* sorted list of pending requests */
struct rb_root sort_list;
/* if fifo isn't expired, next request to serve */
@@ -147,11 +140,10 @@ struct cfq_queue {
struct list_head fifo;
unsigned long slice_end;
- unsigned long service_last;
long slice_resid;
- /* number of requests that are on the dispatch list */
- int on_dispatch[2];
+ /* number of requests that are on the dispatch list or inside driver */
+ int dispatched;
/* io prio of this group */
unsigned short ioprio, org_ioprio;
@@ -159,6 +151,8 @@ struct cfq_queue {
/* various state flags, see below */
unsigned int flags;
+
+ sector_t last_request_pos;
};
enum cfqq_state_flags {
@@ -172,6 +166,7 @@ enum cfqq_state_flags {
CFQ_CFQQ_FLAG_prio_changed, /* task priority has changed */
CFQ_CFQQ_FLAG_queue_new, /* queue never been serviced */
CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */
+ CFQ_CFQQ_FLAG_sync, /* synchronous queue */
};
#define CFQ_CFQQ_FNS(name) \
@@ -198,11 +193,38 @@ CFQ_CFQQ_FNS(idle_window);
CFQ_CFQQ_FNS(prio_changed);
CFQ_CFQQ_FNS(queue_new);
CFQ_CFQQ_FNS(slice_new);
+CFQ_CFQQ_FNS(sync);
#undef CFQ_CFQQ_FNS
-static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
static void cfq_dispatch_insert(request_queue_t *, struct request *);
-static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask);
+static struct cfq_queue *cfq_get_queue(struct cfq_data *, int,
+ struct task_struct *, gfp_t);
+static struct cfq_io_context *cfq_cic_rb_lookup(struct cfq_data *,
+ struct io_context *);
+
+static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
+ int is_sync)
+{
+ return cic->cfqq[!!is_sync];
+}
+
+static inline void cic_set_cfqq(struct cfq_io_context *cic,
+ struct cfq_queue *cfqq, int is_sync)
+{
+ cic->cfqq[!!is_sync] = cfqq;
+}
+
+/*
+ * We regard a request as SYNC, if it's either a read or has the SYNC bit
+ * set (in which case it could also be direct WRITE).
+ */
+static inline int cfq_bio_sync(struct bio *bio)
+{
+ if (bio_data_dir(bio) == READ || bio_sync(bio))
+ return 1;
+
+ return 0;
+}
/*
* scheduler run of queue, if there are requests pending and no one in the
@@ -221,44 +243,31 @@ static int cfq_queue_empty(request_queue_t *q)
return !cfqd->busy_queues;
}
-static inline pid_t cfq_queue_pid(struct task_struct *task, int rw, int is_sync)
-{
- /*
- * Use the per-process queue, for read requests and syncronous writes
- */
- if (!(rw & REQ_RW) || is_sync)
- return task->pid;
-
- return CFQ_KEY_ASYNC;
-}
-
/*
* Scale schedule slice based on io priority. Use the sync time slice only
* if a queue is marked sync and has sync io queued. A sync queue with async
* io only, should not get full sync slice length.
*/
-static inline int
-cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+static inline int cfq_prio_slice(struct cfq_data *cfqd, int sync,
+ unsigned short prio)
{
- const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];
+ const int base_slice = cfqd->cfq_slice[sync];
- WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+ WARN_ON(prio >= IOPRIO_BE_NR);
+
+ return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - prio));
+}
- return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio));
+static inline int
+cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ return cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio);
}
static inline void
cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
- cfqq->slice_end += cfqq->slice_resid;
-
- /*
- * Don't carry over residual for more than one slice, we only want
- * to slightly correct the fairness. Carrying over forever would
- * easily introduce oscillations.
- */
- cfqq->slice_resid = 0;
}
/*
@@ -307,7 +316,7 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
s1 = rq1->sector;
s2 = rq2->sector;
- last = cfqd->last_sector;
+ last = cfqd->last_position;
/*
* by definition, 1KiB is 2 sectors
@@ -372,6 +381,26 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
}
/*
+ * The below is leftmost cache rbtree addon
+ */
+static struct rb_node *cfq_rb_first(struct cfq_rb_root *root)
+{
+ if (!root->left)
+ root->left = rb_first(&root->rb);
+
+ return root->left;
+}
+
+static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root)
+{
+ if (root->left == n)
+ root->left = NULL;
+
+ rb_erase(n, &root->rb);
+ RB_CLEAR_NODE(n);
+}
+
+/*
* would be nice to take fifo expire time into account as well
*/
static struct request *
@@ -398,78 +427,96 @@ cfq_find_next_rq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
return cfq_choose_req(cfqd, next, prev);
}
-static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
+static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
+ struct cfq_queue *cfqq)
{
- struct cfq_data *cfqd = cfqq->cfqd;
- struct list_head *list, *n;
- struct cfq_queue *__cfqq;
-
/*
- * Resorting requires the cfqq to be on the RR list already.
+ * just an approximation, should be ok.
*/
- if (!cfq_cfqq_on_rr(cfqq))
- return;
+ return (cfqd->busy_queues - 1) * (cfq_prio_slice(cfqd, 1, 0) -
+ cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio));
+}
- list_del(&cfqq->cfq_list);
+/*
+ * The cfqd->service_tree holds all pending cfq_queue's that have
+ * requests waiting to be processed. It is sorted in the order that
+ * we will service the queues.
+ */
+static void cfq_service_tree_add(struct cfq_data *cfqd,
+ struct cfq_queue *cfqq, int add_front)
+{
+ struct rb_node **p = &cfqd->service_tree.rb.rb_node;
+ struct rb_node *parent = NULL;
+ unsigned long rb_key;
+ int left;
+
+ if (!add_front) {
+ rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies;
+ rb_key += cfqq->slice_resid;
+ cfqq->slice_resid = 0;
+ } else
+ rb_key = 0;
- if (cfq_class_rt(cfqq))
- list = &cfqd->cur_rr;
- else if (cfq_class_idle(cfqq))
- list = &cfqd->idle_rr;
- else {
+ if (!RB_EMPTY_NODE(&cfqq->rb_node)) {
/*
- * if cfqq has requests in flight, don't allow it to be
- * found in cfq_set_active_queue before it has finished them.
- * this is done to increase fairness between a process that
- * has lots of io pending vs one that only generates one
- * sporadically or synchronously
+ * same position, nothing more to do
*/
- if (cfq_cfqq_dispatched(cfqq))
- list = &cfqd->busy_rr;
- else
- list = &cfqd->rr_list[cfqq->ioprio];
+ if (rb_key == cfqq->rb_key)
+ return;
+
+ cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
}
- if (preempted || cfq_cfqq_queue_new(cfqq)) {
- /*
- * If this queue was preempted or is new (never been serviced),
- * let it be added first for fairness but beind other new
- * queues.
- */
- n = list;
- while (n->next != list) {
- __cfqq = list_entry_cfqq(n->next);
- if (!cfq_cfqq_queue_new(__cfqq))
- break;
+ left = 1;
+ while (*p) {
+ struct cfq_queue *__cfqq;
+ struct rb_node **n;
+
+ parent = *p;
+ __cfqq = rb_entry(parent, struct cfq_queue, rb_node);
- n = n->next;
- }
- list_add_tail(&cfqq->cfq_list, n);
- } else if (!cfq_cfqq_class_sync(cfqq)) {
- /*
- * async queue always goes to the end. this wont be overly
- * unfair to writes, as the sort of the sync queue wont be
- * allowed to pass the async queue again.
- */
- list_add_tail(&cfqq->cfq_list, list);
- } else {
/*
- * sort by last service, but don't cross a new or async
- * queue. we don't cross a new queue because it hasn't been
- * service before, and we don't cross an async queue because
- * it gets added to the end on expire.
+ * sort RT queues first, we always want to give
+ * preference to them. IDLE queues goes to the back.
+ * after that, sort on the next service time.
*/
- n = list;
- while ((n = n->prev) != list) {
- struct cfq_queue *__cfqq = list_entry_cfqq(n);
+ if (cfq_class_rt(cfqq) > cfq_class_rt(__cfqq))
+ n = &(*p)->rb_left;
+ else if (cfq_class_rt(cfqq) < cfq_class_rt(__cfqq))
+ n = &(*p)->rb_right;
+ else if (cfq_class_idle(cfqq) < cfq_class_idle(__cfqq))
+ n = &(*p)->rb_left;
+ else if (cfq_class_idle(cfqq) > cfq_class_idle(__cfqq))
+ n = &(*p)->rb_right;
+ else if (rb_key < __cfqq->rb_key)
+ n = &(*p)->rb_left;
+ else
+ n = &(*p)->rb_right;
- if (!cfq_cfqq_class_sync(cfqq) || !__cfqq->service_last)
- break;
- if (time_before(__cfqq->service_last, cfqq->service_last))
- break;
- }
- list_add(&cfqq->cfq_list, n);
+ if (n == &(*p)->rb_right)
+ left = 0;
+
+ p = n;
}
+
+ if (left)
+ cfqd->service_tree.left = &cfqq->rb_node;
+
+ cfqq->rb_key = rb_key;
+ rb_link_node(&cfqq->rb_node, parent, p);
+ rb_insert_color(&cfqq->rb_node, &cfqd->service_tree.rb);
+}
+
+/*
+ * Update cfqq's position in the service tree.
+ */
+static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ /*
+ * Resorting requires the cfqq to be on the RR list already.
+ */
+ if (cfq_cfqq_on_rr(cfqq))
+ cfq_service_tree_add(cfqd, cfqq, 0);
}
/*
@@ -483,15 +530,21 @@ cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
cfq_mark_cfqq_on_rr(cfqq);
cfqd->busy_queues++;
- cfq_resort_rr_list(cfqq, 0);
+ cfq_resort_rr_list(cfqd, cfqq);
}
+/*
+ * Called when the cfqq no longer has requests pending, remove it from
+ * the service tree.
+ */
static inline void
cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
BUG_ON(!cfq_cfqq_on_rr(cfqq));
cfq_clear_cfqq_on_rr(cfqq);
- list_del_init(&cfqq->cfq_list);
+
+ if (!RB_EMPTY_NODE(&cfqq->rb_node))
+ cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
BUG_ON(!cfqd->busy_queues);
cfqd->busy_queues--;
@@ -552,10 +605,14 @@ static struct request *
cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
{
struct task_struct *tsk = current;
- pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio), bio_sync(bio));
+ struct cfq_io_context *cic;
struct cfq_queue *cfqq;
- cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
+ cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+ if (!cic)
+ return NULL;
+
+ cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
if (cfqq) {
sector_t sector = bio->bi_sector + bio_sectors(bio);
@@ -579,6 +636,8 @@ static void cfq_activate_request(request_queue_t *q, struct request *rq)
*/
if (!cfqd->hw_tag && cfqd->rq_in_driver > 4)
cfqd->hw_tag = 1;
+
+ cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors;
}
static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
@@ -605,8 +664,7 @@ static void cfq_remove_request(struct request *rq)
}
}
-static int
-cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
+static int cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct request *__rq;
@@ -648,23 +706,24 @@ static int cfq_allow_merge(request_queue_t *q, struct request *rq,
struct bio *bio)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- const int rw = bio_data_dir(bio);
+ struct cfq_io_context *cic;
struct cfq_queue *cfqq;
- pid_t key;
/*
* Disallow merge of a sync bio into an async request.
*/
- if ((bio_data_dir(bio) == READ || bio_sync(bio)) && !rq_is_sync(rq))
+ if (cfq_bio_sync(bio) && !rq_is_sync(rq))
return 0;
/*
* Lookup the cfqq that this bio will be queued with. Allow
* merge only if rq is queued there.
*/
- key = cfq_queue_pid(current, rw, bio_sync(bio));
- cfqq = cfq_find_cfq_hash(cfqd, key, current->ioprio);
+ cic = cfq_cic_rb_lookup(cfqd, current->io_context);
+ if (!cic)
+ return 0;
+ cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
if (cfqq == RQ_CFQQ(rq))
return 1;
@@ -684,6 +743,7 @@ __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
cfq_clear_cfqq_must_alloc_slice(cfqq);
cfq_clear_cfqq_fifo_expire(cfqq);
cfq_mark_cfqq_slice_new(cfqq);
+ cfq_clear_cfqq_queue_new(cfqq);
}
cfqd->active_queue = cfqq;
@@ -694,23 +754,21 @@ __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
*/
static void
__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
- int preempted, int timed_out)
+ int timed_out)
{
if (cfq_cfqq_wait_request(cfqq))
del_timer(&cfqd->idle_slice_timer);
cfq_clear_cfqq_must_dispatch(cfqq);
cfq_clear_cfqq_wait_request(cfqq);
- cfq_clear_cfqq_queue_new(cfqq);
/*
- * store what was left of this slice, if the queue idled out
- * or was preempted
+ * store what was left of this slice, if the queue idled/timed out
*/
if (timed_out && !cfq_cfqq_slice_new(cfqq))
cfqq->slice_resid = cfqq->slice_end - jiffies;
- cfq_resort_rr_list(cfqq, preempted);
+ cfq_resort_rr_list(cfqd, cfqq);
if (cfqq == cfqd->active_queue)
cfqd->active_queue = NULL;
@@ -719,163 +777,152 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
put_io_context(cfqd->active_cic->ioc);
cfqd->active_cic = NULL;
}
-
- cfqd->dispatch_slice = 0;
}
-static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted,
- int timed_out)
+static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out)
{
struct cfq_queue *cfqq = cfqd->active_queue;
if (cfqq)
- __cfq_slice_expired(cfqd, cfqq, preempted, timed_out);
+ __cfq_slice_expired(cfqd, cfqq, timed_out);
}
/*
- * 0
- * 0,1
- * 0,1,2
- * 0,1,2,3
- * 0,1,2,3,4
- * 0,1,2,3,4,5
- * 0,1,2,3,4,5,6
- * 0,1,2,3,4,5,6,7
+ * Get next queue for service. Unless we have a queue preemption,
+ * we'll simply select the first cfqq in the service tree.
*/
-static int cfq_get_next_prio_level(struct cfq_data *cfqd)
+static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd)
{
- int prio, wrap;
+ struct cfq_queue *cfqq;
+ struct rb_node *n;
- prio = -1;
- wrap = 0;
- do {
- int p;
+ if (RB_EMPTY_ROOT(&cfqd->service_tree.rb))
+ return NULL;
- for (p = cfqd->cur_prio; p <= cfqd->cur_end_prio; p++) {
- if (!list_empty(&cfqd->rr_list[p])) {
- prio = p;
- break;
- }
- }
+ n = cfq_rb_first(&cfqd->service_tree);
+ cfqq = rb_entry(n, struct cfq_queue, rb_node);
- if (prio != -1)
- break;
- cfqd->cur_prio = 0;
- if (++cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
- cfqd->cur_end_prio = 0;
- if (wrap)
- break;
- wrap = 1;
- }
- } while (1);
+ if (cfq_class_idle(cfqq)) {
+ unsigned long end;
- if (unlikely(prio == -1))
- return -1;
+ /*
+ * if we have idle queues and no rt or be queues had
+ * pending requests, either allow immediate service if
+ * the grace period has passed or arm the idle grace
+ * timer
+ */
+ end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+ if (time_before(jiffies, end)) {
+ mod_timer(&cfqd->idle_class_timer, end);
+ cfqq = NULL;
+ }
+ }
- BUG_ON(prio >= CFQ_PRIO_LISTS);
+ return cfqq;
+}
- list_splice_init(&cfqd->rr_list[prio], &cfqd->cur_rr);
+/*
+ * Get and set a new active queue for service.
+ */
+static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+{
+ struct cfq_queue *cfqq;
- cfqd->cur_prio = prio + 1;
- if (cfqd->cur_prio > cfqd->cur_end_prio) {
- cfqd->cur_end_prio = cfqd->cur_prio;
- cfqd->cur_prio = 0;
- }
- if (cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
- cfqd->cur_prio = 0;
- cfqd->cur_end_prio = 0;
- }
+ cfqq = cfq_get_next_queue(cfqd);
+ __cfq_set_active_queue(cfqd, cfqq);
+ return cfqq;
+}
- return prio;
+static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
+ struct request *rq)
+{
+ if (rq->sector >= cfqd->last_position)
+ return rq->sector - cfqd->last_position;
+ else
+ return cfqd->last_position - rq->sector;
}
-static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+static inline int cfq_rq_close(struct cfq_data *cfqd, struct request *rq)
{
- struct cfq_queue *cfqq = NULL;
+ struct cfq_io_context *cic = cfqd->active_cic;
- if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1) {
- /*
- * if current list is non-empty, grab first entry. if it is
- * empty, get next prio level and grab first entry then if any
- * are spliced
- */
- cfqq = list_entry_cfqq(cfqd->cur_rr.next);
- } else if (!list_empty(&cfqd->busy_rr)) {
- /*
- * If no new queues are available, check if the busy list has
- * some before falling back to idle io.
- */
- cfqq = list_entry_cfqq(cfqd->busy_rr.next);
- } else if (!list_empty(&cfqd->idle_rr)) {
- /*
- * if we have idle queues and no rt or be queues had pending
- * requests, either allow immediate service if the grace period
- * has passed or arm the idle grace timer
- */
- unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+ if (!sample_valid(cic->seek_samples))
+ return 0;
- if (time_after_eq(jiffies, end))
- cfqq = list_entry_cfqq(cfqd->idle_rr.next);
- else
- mod_timer(&cfqd->idle_class_timer, end);
- }
+ return cfq_dist_from_last(cfqd, rq) <= cic->seek_mean;
+}
- __cfq_set_active_queue(cfqd, cfqq);
- return cfqq;
+static int cfq_close_cooperator(struct cfq_data *cfq_data,
+ struct cfq_queue *cfqq)
+{
+ /*
+ * We should notice if some of the queues are cooperating, eg
+ * working closely on the same area of the disk. In that case,
+ * we can group them together and don't waste time idling.
+ */
+ return 0;
}
-#define CIC_SEEKY(cic) ((cic)->seek_mean > (128 * 1024))
+#define CIC_SEEKY(cic) ((cic)->seek_mean > (8 * 1024))
-static int cfq_arm_slice_timer(struct cfq_data *cfqd)
+static void cfq_arm_slice_timer(struct cfq_data *cfqd)
{
struct cfq_queue *cfqq = cfqd->active_queue;
struct cfq_io_context *cic;
unsigned long sl;
WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list));
+ WARN_ON(cfq_cfqq_slice_new(cfqq));
/*
* idle is disabled, either manually or by past process history
*/
- if (!cfqd->cfq_slice_idle)
- return 0;
- if (!cfq_cfqq_idle_window(cfqq))
- return 0;
+ if (!cfqd->cfq_slice_idle || !cfq_cfqq_idle_window(cfqq))
+ return;
+
/*
* task has exited, don't wait
*/
cic = cfqd->active_cic;
if (!cic || !cic->ioc->task)
- return 0;
+ return;
+
+ /*
+ * See if this prio level has a good candidate
+ */
+ if (cfq_close_cooperator(cfqd, cfqq) &&
+ (sample_valid(cic->ttime_samples) && cic->ttime_mean > 2))
+ return;
cfq_mark_cfqq_must_dispatch(cfqq);
cfq_mark_cfqq_wait_request(cfqq);
- sl = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
-
/*
* we don't want to idle for seeks, but we do want to allow
* fair distribution of slice time for a process doing back-to-back
* seeks. so allow a little bit of time for him to submit a new rq
*/
+ sl = cfqd->cfq_slice_idle;
if (sample_valid(cic->seek_samples) && CIC_SEEKY(cic))
- sl = min(sl, msecs_to_jiffies(2));
+ sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT));
mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
- return 1;
}
+/*
+ * Move request from internal lists to the request queue dispatch list.
+ */
static void cfq_dispatch_insert(request_queue_t *q, struct request *rq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_queue *cfqq = RQ_CFQQ(rq);
cfq_remove_request(rq);
- cfqq->on_dispatch[rq_is_sync(rq)]++;
+ cfqq->dispatched++;
elv_dispatch_sort(q, rq);
- rq = list_entry(q->queue_head.prev, struct request, queuelist);
- cfqd->last_sector = rq->sector + rq->nr_sectors;
+ if (cfq_cfqq_sync(cfqq))
+ cfqd->sync_flight++;
}
/*
@@ -895,13 +942,13 @@ static inline struct request *cfq_check_fifo(struct cfq_queue *cfqq)
if (list_empty(&cfqq->fifo))
return NULL;
- fifo = cfq_cfqq_class_sync(cfqq);
+ fifo = cfq_cfqq_sync(cfqq);
rq = rq_entry_fifo(cfqq->fifo.next);
- if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo]))
- return rq;
+ if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo]))
+ return NULL;
- return NULL;
+ return rq;
}
static inline int
@@ -915,7 +962,8 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
}
/*
- * get next queue for service
+ * Select a queue for service. If we have a current active queue,
+ * check whether to continue servicing it, or retrieve and set a new one.
*/
static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
{
@@ -926,33 +974,41 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
goto new_queue;
/*
- * slice has expired
+ * The active queue has run out of time, expire it and select new.
*/
- if (!cfq_cfqq_must_dispatch(cfqq) && cfq_slice_used(cfqq))
+ if (cfq_slice_used(cfqq))
goto expire;
/*
- * if queue has requests, dispatch one. if not, check if
- * enough slice is left to wait for one
+ * The active queue has requests and isn't expired, allow it to
+ * dispatch.
*/
if (!RB_EMPTY_ROOT(&cfqq->sort_list))
goto keep_queue;
- else if (cfq_cfqq_slice_new(cfqq) || cfq_cfqq_dispatched(cfqq)) {
+
+ /*
+ * No requests pending. If the active queue still has requests in
+ * flight or is idling for a new request, allow either of these
+ * conditions to happen (or time out) before selecting a new queue.
+ */
+ if (timer_pending(&cfqd->idle_slice_timer) ||
+ (cfqq->dispatched && cfq_cfqq_idle_window(cfqq))) {
cfqq = NULL;
goto keep_queue;
- } else if (cfq_cfqq_class_sync(cfqq)) {
- if (cfq_arm_slice_timer(cfqd))
- return NULL;
}
expire:
- cfq_slice_expired(cfqd, 0, 0);
+ cfq_slice_expired(cfqd, 0);
new_queue:
cfqq = cfq_set_active_queue(cfqd);
keep_queue:
return cfqq;
}
+/*
+ * Dispatch some requests from cfqq, moving them to the request queue
+ * dispatch list.
+ */
static int
__cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
int max_dispatch)
@@ -975,7 +1031,6 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
*/
cfq_dispatch_insert(cfqd->queue, rq);
- cfqd->dispatch_slice++;
dispatched++;
if (!cfqd->active_cic) {
@@ -993,57 +1048,54 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
* queue always expire after 1 dispatch round.
*/
if (cfqd->busy_queues > 1 && ((!cfq_cfqq_sync(cfqq) &&
- cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
+ dispatched >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
cfq_class_idle(cfqq))) {
cfqq->slice_end = jiffies + 1;
- cfq_slice_expired(cfqd, 0, 0);
+ cfq_slice_expired(cfqd, 0);
}
return dispatched;
}
-static int
-cfq_forced_dispatch_cfqqs(struct list_head *list)
+static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
{
- struct cfq_queue *cfqq, *next;
- int dispatched;
+ int dispatched = 0;
- dispatched = 0;
- list_for_each_entry_safe(cfqq, next, list, cfq_list) {
- while (cfqq->next_rq) {
- cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq);
- dispatched++;
- }
- BUG_ON(!list_empty(&cfqq->fifo));
+ while (cfqq->next_rq) {
+ cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq);
+ dispatched++;
}
+ BUG_ON(!list_empty(&cfqq->fifo));
return dispatched;
}
-static int
-cfq_forced_dispatch(struct cfq_data *cfqd)
+/*
+ * Drain our current requests. Used for barriers and when switching
+ * io schedulers on-the-fly.
+ */
+static int cfq_forced_dispatch(struct cfq_data *cfqd)
{
- int i, dispatched = 0;
+ int dispatched = 0;
+ struct rb_node *n;
- for (i = 0; i < CFQ_PRIO_LISTS; i++)
- dispatched += cfq_forced_dispatch_cfqqs(&cfqd->rr_list[i]);
+ while ((n = cfq_rb_first(&cfqd->service_tree)) != NULL) {
+ struct cfq_queue *cfqq = rb_entry(n, struct cfq_queue, rb_node);
- dispatched += cfq_forced_dispatch_cfqqs(&cfqd->busy_rr);
- dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr);
- dispatched += cfq_forced_dispatch_cfqqs(&cfqd->idle_rr);
+ dispatched += __cfq_forced_dispatch_cfqq(cfqq);
+ }
- cfq_slice_expired(cfqd, 0, 0);
+ cfq_slice_expired(cfqd, 0);
BUG_ON(cfqd->busy_queues);
return dispatched;
}
-static int
-cfq_dispatch_requests(request_queue_t *q, int force)
+static int cfq_dispatch_requests(request_queue_t *q, int force)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_queue *cfqq, *prev_cfqq;
+ struct cfq_queue *cfqq;
int dispatched;
if (!cfqd->busy_queues)
@@ -1053,36 +1105,28 @@ cfq_dispatch_requests(request_queue_t *q, int force)
return cfq_forced_dispatch(cfqd);
dispatched = 0;
- prev_cfqq = NULL;
while ((cfqq = cfq_select_queue(cfqd)) != NULL) {
int max_dispatch;
- if (cfqd->busy_queues > 1) {
- /*
- * Don't repeat dispatch from the previous queue.
- */
- if (prev_cfqq == cfqq)
- break;
+ max_dispatch = cfqd->cfq_quantum;
+ if (cfq_class_idle(cfqq))
+ max_dispatch = 1;
- /*
- * So we have dispatched before in this round, if the
- * next queue has idling enabled (must be sync), don't
- * allow it service until the previous have continued.
- */
- if (cfqd->rq_in_driver && cfq_cfqq_idle_window(cfqq))
+ if (cfqq->dispatched >= max_dispatch) {
+ if (cfqd->busy_queues > 1)
+ break;
+ if (cfqq->dispatched >= 4 * max_dispatch)
break;
}
+ if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq))
+ break;
+
cfq_clear_cfqq_must_dispatch(cfqq);
cfq_clear_cfqq_wait_request(cfqq);
del_timer(&cfqd->idle_slice_timer);
- max_dispatch = cfqd->cfq_quantum;
- if (cfq_class_idle(cfqq))
- max_dispatch = 1;
-
dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
- prev_cfqq = cfqq;
}
return dispatched;
@@ -1108,48 +1152,21 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
BUG_ON(cfq_cfqq_on_rr(cfqq));
if (unlikely(cfqd->active_queue == cfqq)) {
- __cfq_slice_expired(cfqd, cfqq, 0, 0);
+ __cfq_slice_expired(cfqd, cfqq, 0);
cfq_schedule_dispatch(cfqd);
}
- /*
- * it's on the empty list and still hashed
- */
- list_del(&cfqq->cfq_list);
- hlist_del(&cfqq->cfq_hash);
kmem_cache_free(cfq_pool, cfqq);
}
-static struct cfq_queue *
-__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
- const int hashval)
-{
- struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
- struct hlist_node *entry;
- struct cfq_queue *__cfqq;
-
- hlist_for_each_entry(__cfqq, entry, hash_list, cfq_hash) {
- const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->org_ioprio_class, __cfqq->org_ioprio);
-
- if (__cfqq->key == key && (__p == prio || !prio))
- return __cfqq;
- }
-
- return NULL;
-}
-
-static struct cfq_queue *
-cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
-{
- return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
-}
-
static void cfq_free_io_context(struct io_context *ioc)
{
struct cfq_io_context *__cic;
struct rb_node *n;
int freed = 0;
+ ioc->ioc_data = NULL;
+
while ((n = rb_first(&ioc->cic_root)) != NULL) {
__cic = rb_entry(n, struct cfq_io_context, rb_node);
rb_erase(&__cic->rb_node, &ioc->cic_root);
@@ -1166,7 +1183,7 @@ static void cfq_free_io_context(struct io_context *ioc)
static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
if (unlikely(cfqq == cfqd->active_queue)) {
- __cfq_slice_expired(cfqd, cfqq, 0, 0);
+ __cfq_slice_expired(cfqd, cfqq, 0);
cfq_schedule_dispatch(cfqd);
}
@@ -1191,10 +1208,6 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
}
}
-
-/*
- * Called with interrupts disabled
- */
static void cfq_exit_single_io_context(struct cfq_io_context *cic)
{
struct cfq_data *cfqd = cic->key;
@@ -1208,15 +1221,20 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic)
}
}
+/*
+ * The process that ioc belongs to has exited, we need to clean up
+ * and put the internal structures we have that belongs to that process.
+ */
static void cfq_exit_io_context(struct io_context *ioc)
{
struct cfq_io_context *__cic;
struct rb_node *n;
+ ioc->ioc_data = NULL;
+
/*
* put the reference this task is holding to the various queues
*/
-
n = rb_first(&ioc->cic_root);
while (n != NULL) {
__cic = rb_entry(n, struct cfq_io_context, rb_node);
@@ -1284,8 +1302,6 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
*/
cfqq->org_ioprio = cfqq->ioprio;
cfqq->org_ioprio_class = cfqq->ioprio_class;
-
- cfq_resort_rr_list(cfqq, 0);
cfq_clear_cfqq_prio_changed(cfqq);
}
@@ -1303,7 +1319,7 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
cfqq = cic->cfqq[ASYNC];
if (cfqq) {
struct cfq_queue *new_cfqq;
- new_cfqq = cfq_get_queue(cfqd, CFQ_KEY_ASYNC, cic->ioc->task,
+ new_cfqq = cfq_get_queue(cfqd, ASYNC, cic->ioc->task,
GFP_ATOMIC);
if (new_cfqq) {
cic->cfqq[ASYNC] = new_cfqq;
@@ -1335,16 +1351,16 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc)
}
static struct cfq_queue *
-cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk,
+cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
gfp_t gfp_mask)
{
- const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
struct cfq_queue *cfqq, *new_cfqq = NULL;
- unsigned short ioprio;
+ struct cfq_io_context *cic;
retry:
- ioprio = tsk->ioprio;
- cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval);
+ cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+ /* cic always exists here */
+ cfqq = cic_to_cfqq(cic, is_sync);
if (!cfqq) {
if (new_cfqq) {
@@ -1369,20 +1385,20 @@ retry:
memset(cfqq, 0, sizeof(*cfqq));
- INIT_HLIST_NODE(&cfqq->cfq_hash);
- INIT_LIST_HEAD(&cfqq->cfq_list);
+ RB_CLEAR_NODE(&cfqq->rb_node);
INIT_LIST_HEAD(&cfqq->fifo);
- cfqq->key = key;
- hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
atomic_set(&cfqq->ref, 0);
cfqq->cfqd = cfqd;
- if (key != CFQ_KEY_ASYNC)
+ if (is_sync) {
cfq_mark_cfqq_idle_window(cfqq);
+ cfq_mark_cfqq_sync(cfqq);
+ }
cfq_mark_cfqq_prio_changed(cfqq);
cfq_mark_cfqq_queue_new(cfqq);
+
cfq_init_prio_data(cfqq);
}
@@ -1395,10 +1411,17 @@ out:
return cfqq;
}
+/*
+ * We drop cfq io contexts lazily, so we may find a dead one.
+ */
static void
cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic)
{
WARN_ON(!list_empty(&cic->queue_list));
+
+ if (ioc->ioc_data == cic)
+ ioc->ioc_data = NULL;
+
rb_erase(&cic->rb_node, &ioc->cic_root);
kmem_cache_free(cfq_ioc_pool, cic);
elv_ioc_count_dec(ioc_count);
@@ -1411,6 +1434,16 @@ cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
struct cfq_io_context *cic;
void *k, *key = cfqd;
+ if (unlikely(!ioc))
+ return NULL;
+
+ /*
+ * we maintain a last-hit cache, to avoid browsing over the tree
+ */
+ cic = ioc->ioc_data;
+ if (cic && cic->key == cfqd)
+ return cic;
+
restart:
n = ioc->cic_root.rb_node;
while (n) {
@@ -1426,8 +1459,10 @@ restart:
n = n->rb_left;
else if (key > k)
n = n->rb_right;
- else
+ else {
+ ioc->ioc_data = cic;
return cic;
+ }
}
return NULL;
@@ -1524,7 +1559,8 @@ cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
}
static void
-cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq)
+cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
+ struct request *rq)
{
sector_t sdist;
u64 total;
@@ -1534,6 +1570,11 @@ cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq)
else
sdist = cic->last_request_pos - rq->sector;
+ if (!cic->seek_samples) {
+ cfqd->new_seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
+ cfqd->new_seek_mean = cfqd->new_seek_total / 256;
+ }
+
/*
* Don't allow the seek distance to get too large from the
* odd fragment, pagein, etc
@@ -1558,7 +1599,12 @@ static void
cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct cfq_io_context *cic)
{
- int enable_idle = cfq_cfqq_idle_window(cfqq);
+ int enable_idle;
+
+ if (!cfq_cfqq_sync(cfqq))
+ return;
+
+ enable_idle = cfq_cfqq_idle_window(cfqq);
if (!cic->ioc->task || !cfqd->cfq_slice_idle ||
(cfqd->hw_tag && CIC_SEEKY(cic)))
@@ -1584,24 +1630,28 @@ static int
cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
struct request *rq)
{
- struct cfq_queue *cfqq = cfqd->active_queue;
+ struct cfq_queue *cfqq;
- if (cfq_class_idle(new_cfqq))
+ cfqq = cfqd->active_queue;
+ if (!cfqq)
return 0;
- if (!cfqq)
+ if (cfq_slice_used(cfqq))
+ return 1;
+
+ if (cfq_class_idle(new_cfqq))
return 0;
if (cfq_class_idle(cfqq))
return 1;
- if (!cfq_cfqq_wait_request(new_cfqq))
- return 0;
+
/*
* if the new request is sync, but the currently running queue is
* not, let the sync request have priority.
*/
if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
return 1;
+
/*
* So both queues are sync. Let the new request get disk time if
* it's a metadata request and the current queue is doing regular IO.
@@ -1609,6 +1659,16 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
if (rq_is_meta(rq) && !cfqq->meta_pending)
return 1;
+ if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq))
+ return 0;
+
+ /*
+ * if this request is as-good as one we would expect from the
+ * current cfqq, let it preempt
+ */
+ if (cfq_rq_close(cfqd, rq))
+ return 1;
+
return 0;
}
@@ -1618,14 +1678,15 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
*/
static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
- cfq_slice_expired(cfqd, 1, 1);
+ cfq_slice_expired(cfqd, 1);
/*
* Put the new queue at the front of the of the current list,
* so we know that it will be selected next.
*/
BUG_ON(!cfq_cfqq_on_rr(cfqq));
- list_move(&cfqq->cfq_list, &cfqd->cur_rr);
+
+ cfq_service_tree_add(cfqd, cfqq, 1);
cfqq->slice_end = 0;
cfq_mark_cfqq_slice_new(cfqq);
@@ -1644,28 +1705,12 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
if (rq_is_meta(rq))
cfqq->meta_pending++;
- /*
- * we never wait for an async request and we don't allow preemption
- * of an async request. so just return early
- */
- if (!rq_is_sync(rq)) {
- /*
- * sync process issued an async request, if it's waiting
- * then expire it and kick rq handling.
- */
- if (cic == cfqd->active_cic &&
- del_timer(&cfqd->idle_slice_timer)) {
- cfq_slice_expired(cfqd, 0, 0);
- blk_start_queueing(cfqd->queue);
- }
- return;
- }
-
cfq_update_io_thinktime(cfqd, cic);
- cfq_update_io_seektime(cic, rq);
+ cfq_update_io_seektime(cfqd, cic, rq);
cfq_update_idle_window(cfqd, cfqq, cic);
cic->last_request_pos = rq->sector + rq->nr_sectors;
+ cfqq->last_request_pos = cic->last_request_pos;
if (cfqq == cfqd->active_queue) {
/*
@@ -1714,16 +1759,16 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
now = jiffies;
WARN_ON(!cfqd->rq_in_driver);
- WARN_ON(!cfqq->on_dispatch[sync]);
+ WARN_ON(!cfqq->dispatched);
cfqd->rq_in_driver--;
- cfqq->on_dispatch[sync]--;
- cfqq->service_last = now;
+ cfqq->dispatched--;
+
+ if (cfq_cfqq_sync(cfqq))
+ cfqd->sync_flight--;
if (!cfq_class_idle(cfqq))
cfqd->last_end_request = now;
- cfq_resort_rr_list(cfqq, 0);
-
if (sync)
RQ_CIC(rq)->last_end_request = now;
@@ -1737,12 +1782,13 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
cfq_clear_cfqq_slice_new(cfqq);
}
if (cfq_slice_used(cfqq))
- cfq_slice_expired(cfqd, 0, 1);
- else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) {
- if (!cfq_arm_slice_timer(cfqd))
- cfq_schedule_dispatch(cfqd);
- }
+ cfq_slice_expired(cfqd, 1);
+ else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list))
+ cfq_arm_slice_timer(cfqd);
}
+
+ if (!cfqd->rq_in_driver)
+ cfq_schedule_dispatch(cfqd);
}
/*
@@ -1751,9 +1797,6 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
*/
static void cfq_prio_boost(struct cfq_queue *cfqq)
{
- const int ioprio_class = cfqq->ioprio_class;
- const int ioprio = cfqq->ioprio;
-
if (has_fs_excl()) {
/*
* boost idle prio on transactions that would lock out other
@@ -1772,12 +1815,6 @@ static void cfq_prio_boost(struct cfq_queue *cfqq)
if (cfqq->ioprio != cfqq->org_ioprio)
cfqq->ioprio = cfqq->org_ioprio;
}
-
- /*
- * refile between round-robin lists if we moved the priority class
- */
- if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio))
- cfq_resort_rr_list(cfqq, 0);
}
static inline int __cfq_may_queue(struct cfq_queue *cfqq)
@@ -1795,10 +1832,8 @@ static int cfq_may_queue(request_queue_t *q, int rw)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct task_struct *tsk = current;
+ struct cfq_io_context *cic;
struct cfq_queue *cfqq;
- unsigned int key;
-
- key = cfq_queue_pid(tsk, rw, rw & REQ_RW_SYNC);
/*
* don't force setup of a queue from here, as a call to may_queue
@@ -1806,7 +1841,11 @@ static int cfq_may_queue(request_queue_t *q, int rw)
* so just lookup a possibly existing queue, or return 'may queue'
* if that fails
*/
- cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
+ cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+ if (!cic)
+ return ELV_MQUEUE_MAY;
+
+ cfqq = cic_to_cfqq(cic, rw & REQ_RW_SYNC);
if (cfqq) {
cfq_init_prio_data(cfqq);
cfq_prio_boost(cfqq);
@@ -1850,7 +1889,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
struct cfq_io_context *cic;
const int rw = rq_data_dir(rq);
const int is_sync = rq_is_sync(rq);
- pid_t key = cfq_queue_pid(tsk, rw, is_sync);
struct cfq_queue *cfqq;
unsigned long flags;
@@ -1863,14 +1901,15 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
if (!cic)
goto queue_fail;
- if (!cic->cfqq[is_sync]) {
- cfqq = cfq_get_queue(cfqd, key, tsk, gfp_mask);
+ cfqq = cic_to_cfqq(cic, is_sync);
+ if (!cfqq) {
+ cfqq = cfq_get_queue(cfqd, is_sync, tsk, gfp_mask);
+
if (!cfqq)
goto queue_fail;
- cic->cfqq[is_sync] = cfqq;
- } else
- cfqq = cic->cfqq[is_sync];
+ cic_set_cfqq(cic, cfqq, is_sync);
+ }
cfqq->allocated[rw]++;
cfq_clear_cfqq_must_alloc(cfqq);
@@ -1940,7 +1979,7 @@ static void cfq_idle_slice_timer(unsigned long data)
}
}
expire:
- cfq_slice_expired(cfqd, 0, timed_out);
+ cfq_slice_expired(cfqd, timed_out);
out_kick:
cfq_schedule_dispatch(cfqd);
out_cont:
@@ -1986,7 +2025,7 @@ static void cfq_exit_queue(elevator_t *e)
spin_lock_irq(q->queue_lock);
if (cfqd->active_queue)
- __cfq_slice_expired(cfqd, cfqd->active_queue, 0, 0);
+ __cfq_slice_expired(cfqd, cfqd->active_queue, 0);
while (!list_empty(&cfqd->cic_list)) {
struct cfq_io_context *cic = list_entry(cfqd->cic_list.next,
@@ -2000,14 +2039,12 @@ static void cfq_exit_queue(elevator_t *e)
cfq_shutdown_timer_wq(cfqd);
- kfree(cfqd->cfq_hash);
kfree(cfqd);
}
static void *cfq_init_queue(request_queue_t *q)
{
struct cfq_data *cfqd;
- int i;
cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node);
if (!cfqd)
@@ -2015,21 +2052,9 @@ static void *cfq_init_queue(request_queue_t *q)
memset(cfqd, 0, sizeof(*cfqd));
- for (i = 0; i < CFQ_PRIO_LISTS; i++)
- INIT_LIST_HEAD(&cfqd->rr_list[i]);
-
- INIT_LIST_HEAD(&cfqd->busy_rr);
- INIT_LIST_HEAD(&cfqd->cur_rr);
- INIT_LIST_HEAD(&cfqd->idle_rr);
+ cfqd->service_tree = CFQ_RB_ROOT;
INIT_LIST_HEAD(&cfqd->cic_list);
- cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node);
- if (!cfqd->cfq_hash)
- goto out_free;
-
- for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
- INIT_HLIST_HEAD(&cfqd->cfq_hash[i]);
-
cfqd->queue = q;
init_timer(&cfqd->idle_slice_timer);
@@ -2053,9 +2078,6 @@ static void *cfq_init_queue(request_queue_t *q)
cfqd->cfq_slice_idle = cfq_slice_idle;
return cfqd;
-out_free:
- kfree(cfqd);
- return NULL;
}
static void cfq_slab_kill(void)
@@ -2087,7 +2109,6 @@ fail:
/*
* sysfs parts below -->
*/
-
static ssize_t
cfq_var_show(unsigned int var, char *page)
{
diff --git a/block/elevator.c b/block/elevator.c
index 96a00c822748..ce866eb75f6a 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -134,13 +134,13 @@ static struct elevator_type *elevator_get(const char *name)
{
struct elevator_type *e;
- spin_lock_irq(&elv_list_lock);
+ spin_lock(&elv_list_lock);
e = elevator_find(name);
if (e && !try_module_get(e->elevator_owner))
e = NULL;
- spin_unlock_irq(&elv_list_lock);
+ spin_unlock(&elv_list_lock);
return e;
}
@@ -965,10 +965,11 @@ void elv_unregister_queue(struct request_queue *q)
int elv_register(struct elevator_type *e)
{
char *def = "";
- spin_lock_irq(&elv_list_lock);
+
+ spin_lock(&elv_list_lock);
BUG_ON(elevator_find(e->elevator_name));
list_add_tail(&e->list, &elv_list);
- spin_unlock_irq(&elv_list_lock);
+ spin_unlock(&elv_list_lock);
if (!strcmp(e->elevator_name, chosen_elevator) ||
(!*chosen_elevator &&
@@ -998,9 +999,9 @@ void elv_unregister(struct elevator_type *e)
read_unlock(&tasklist_lock);
}
- spin_lock_irq(&elv_list_lock);
+ spin_lock(&elv_list_lock);
list_del_init(&e->list);
- spin_unlock_irq(&elv_list_lock);
+ spin_unlock(&elv_list_lock);
}
EXPORT_SYMBOL_GPL(elv_unregister);
@@ -1118,7 +1119,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
struct list_head *entry;
int len = 0;
- spin_lock_irq(&elv_list_lock);
+ spin_lock(&elv_list_lock);
list_for_each(entry, &elv_list) {
struct elevator_type *__e;
@@ -1128,7 +1129,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
else
len += sprintf(name+len, "%s ", __e->elevator_name);
}
- spin_unlock_irq(&elv_list_lock);
+ spin_unlock(&elv_list_lock);
len += sprintf(len+name, "\n");
return len;
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 3de06953ac33..123003a90477 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -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;
diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c
index 094397b48849..9e917b8011b1 100644
--- a/crypto/michael_mic.c
+++ b/crypto/michael_mic.c
@@ -3,7 +3,7 @@
*
* Michael MIC (IEEE 802.11i/TKIP) keyed digest
*
- * Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004 Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -173,4 +173,4 @@ module_exit(michael_mic_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Michael MIC");
-MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>");
+MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index e2ce4a9c1c92..139f41f033d8 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -85,8 +85,8 @@ config ACPI_PROCFS
depends on ACPI
default y
---help---
- Procfs interface for ACPI is made optional for back-compatible.
- As the same functions are duplicated in sysfs interface
+ The Procfs interface for ACPI is made optional for backward compatibility.
+ As the same functions are duplicated in the sysfs interface
and this proc interface will be removed some time later,
it's marked as deprecated.
( /proc/acpi/debug_layer && debug_level are deprecated by
@@ -218,43 +218,6 @@ config ACPI_ASUS
NOTE: This driver is deprecated and will probably be removed soon,
use asus-laptop instead.
-config ACPI_IBM
- tristate "IBM ThinkPad Laptop Extras"
- depends on X86
- select BACKLIGHT_CLASS_DEVICE
- ---help---
- This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
- support for Fn-Fx key combinations, Bluetooth control, video
- output switching, ThinkLight control, UltraBay eject and more.
- For more information about this driver see <file:Documentation/ibm-acpi.txt>
- and <http://ibm-acpi.sf.net/> .
-
- If you have an IBM ThinkPad laptop, say Y or M here.
-
-config ACPI_IBM_DOCK
- bool "Legacy Docking Station Support"
- depends on ACPI_IBM
- depends on ACPI_DOCK=n
- default n
- ---help---
- Allows the ibm_acpi driver to handle docking station events.
- This support is obsoleted by CONFIG_HOTPLUG_PCI_ACPI. It will
- allow locking and removing the laptop from the docking station,
- but will not properly connect PCI devices.
-
- If you are not sure, say N here.
-
-config ACPI_IBM_BAY
- bool "Legacy Removable Bay Support"
- depends on ACPI_IBM
- default y
- ---help---
- Allows the ibm_acpi driver to handle removable bays. It will allow
- disabling the device in the bay, and also generate notifications when
- the bay lever is ejected or inserted.
-
- If you are not sure, say Y here.
-
config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on X86
@@ -388,11 +351,10 @@ config ACPI_HOTPLUG_MEMORY
config ACPI_SBS
tristate "Smart Battery System (EXPERIMENTAL)"
- depends on X86 && I2C
+ depends on X86
depends on EXPERIMENTAL
help
This driver adds support for the Smart Battery System.
- Depends on I2C (Device Drivers ---> I2C support)
A "Smart Battery" is quite old and quite rare compared
to today's ACPI "Control Method" battery.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 5956e9f64a8b..d4336f1730e9 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -1,6 +1,6 @@
#
# Makefile for the Linux ACPI interpreter
-#
+#
export ACPI_CFLAGS
@@ -32,16 +32,17 @@ obj-y += osl.o utils.o \
processor-objs += processor_core.o processor_throttling.o \
processor_idle.o processor_thermal.o
ifdef CONFIG_CPU_FREQ
-processor-objs += processor_perflib.o
+processor-objs += processor_perflib.o
endif
obj-y += sleep/
obj-y += bus.o glue.o
obj-y += scan.o
+# Keep EC driver first. Initialization of others depend on it.
+obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_AC) += ac.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
-obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_DOCK) += dock.o
obj-$(CONFIG_ACPI_BAY) += bay.o
@@ -55,8 +56,7 @@ obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
obj-$(CONFIG_ACPI_DEBUG) += debug.o
obj-$(CONFIG_ACPI_NUMA) += numa.o
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
-obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
obj-y += cm_sbs.o
-obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o
+obj-$(CONFIG_ACPI_SBS) += sbs.o
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index c26172671fd8..e65628a03085 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -44,11 +44,6 @@ MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
MODULE_DESCRIPTION("Hotplug Mem Driver");
MODULE_LICENSE("GPL");
-/* ACPI _STA method values */
-#define ACPI_MEMORY_STA_PRESENT (0x00000001UL)
-#define ACPI_MEMORY_STA_ENABLED (0x00000002UL)
-#define ACPI_MEMORY_STA_FUNCTIONAL (0x00000008UL)
-
/* Memory Device States */
#define MEMORY_INVALID_STATE 0
#define MEMORY_POWER_ON_STATE 1
@@ -204,9 +199,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
* Check for device status. Device should be
* present/enabled/functioning.
*/
- if (!((current_status & ACPI_MEMORY_STA_PRESENT)
- && (current_status & ACPI_MEMORY_STA_ENABLED)
- && (current_status & ACPI_MEMORY_STA_FUNCTIONAL)))
+ if (!((current_status & ACPI_STA_DEVICE_PRESENT)
+ && (current_status & ACPI_STA_DEVICE_ENABLED)
+ && (current_status & ACPI_STA_DEVICE_FUNCTIONING)))
return -ENODEV;
return 0;
@@ -286,7 +281,7 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
return -ENODEV;
/* Check for device status. Device should be disabled */
- if (current_status & ACPI_MEMORY_STA_ENABLED)
+ if (current_status & ACPI_STA_DEVICE_ENABLED)
return -EINVAL;
return 0;
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index dd49ea0d0ed3..e5084ececb6f 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -103,7 +103,9 @@ int acpi_bus_get_status(struct acpi_device *device)
else if (device->parent)
device->status = device->parent->status;
else
- STRUCT_TO_INT(device->status) = 0x0F;
+ STRUCT_TO_INT(device->status) =
+ ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
if (device->status.functional && !device->status.present) {
printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 0930d9413dfa..0dd3bf7c0ed1 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -49,8 +49,6 @@ MODULE_AUTHOR("Anil S Keshavamurthy");
MODULE_DESCRIPTION("ACPI container driver");
MODULE_LICENSE("GPL");
-#define ACPI_STA_PRESENT (0x00000001)
-
static int acpi_container_add(struct acpi_device *device);
static int acpi_container_remove(struct acpi_device *device, int type);
@@ -75,13 +73,13 @@ static int is_device_present(acpi_handle handle)
status = acpi_get_handle(handle, "_STA", &temp);
if (ACPI_FAILURE(status))
- return 1; /* _STA not found, assmue device present */
+ return 1; /* _STA not found, assume device present */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return 0; /* Firmware error */
- return ((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
+ return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
}
/*******************************************************************/
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 54a697f9aa18..4546bf873aea 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -29,6 +29,7 @@
#include <linux/notifier.h>
#include <linux/platform_device.h>
#include <linux/jiffies.h>
+#include <linux/stddef.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -667,6 +668,23 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
}
DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
+/*
+ * show_dock_uid - read method for "uid" file in sysfs
+ */
+static ssize_t show_dock_uid(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long lbuf;
+ acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf);
+ if(ACPI_FAILURE(status)) {
+ return 0;
+ }
+ return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
+}
+DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
+
+
+
/**
* dock_add - add a new dock station
* @handle: the dock station handle
@@ -715,6 +733,13 @@ static int dock_add(acpi_handle handle)
kfree(dock_station);
return ret;
}
+ ret = device_create_file(&dock_device.dev, &dev_attr_uid);
+ if (ret) {
+ printk("Error %d adding sysfs file\n", ret);
+ platform_device_unregister(&dock_device);
+ kfree(dock_station);
+ return ret;
+ }
/* Find dependent devices */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index a802962ff2b4..e08cf98f504f 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1,6 +1,8 @@
/*
- * acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 38 $)
+ * ec.c - ACPI Embedded Controller Driver (v2.0)
*
+ * Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
+ * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -91,9 +93,9 @@ static struct acpi_driver acpi_ec_driver = {
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
+/* External interfaces use first EC only, so remember */
static struct acpi_ec {
acpi_handle handle;
- unsigned long uid;
unsigned long gpe;
unsigned long command_addr;
unsigned long data_addr;
@@ -101,12 +103,8 @@ static struct acpi_ec {
struct mutex lock;
atomic_t query_pending;
atomic_t event_count;
- atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
wait_queue_head_t wait;
-} *ec_ecdt;
-
-/* External interfaces use first EC only, so remember */
-static struct acpi_device *first_ec;
+} *boot_ec, *first_ec;
/* --------------------------------------------------------------------------
Transaction Management
@@ -173,56 +171,6 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
return -ETIME;
}
-#ifdef ACPI_FUTURE_USAGE
-/*
- * Note: samsung nv5000 doesn't work with ec burst mode.
- * http://bugzilla.kernel.org/show_bug.cgi?id=4980
- */
-int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
-{
- u8 tmp = 0;
- u8 status = 0;
-
- status = acpi_ec_read_status(ec);
- if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- if (status)
- goto end;
- acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
- tmp = acpi_ec_read_data(ec);
- if (tmp != 0x90) { /* Burst ACK byte */
- return -EINVAL;
- }
- }
-
- atomic_set(&ec->leaving_burst, 0);
- return 0;
- end:
- ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
- return -1;
-}
-
-int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
-{
- u8 status = 0;
-
- status = acpi_ec_read_status(ec);
- if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) {
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- if (status)
- goto end;
- acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
- acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- }
- atomic_set(&ec->leaving_burst, 1);
- return 0;
- end:
- ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
- return -1;
-}
-#endif /* ACPI_FUTURE_USAGE */
-
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
const u8 * wdata, unsigned wdata_len,
u8 * rdata, unsigned rdata_len)
@@ -312,6 +260,21 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
return status;
}
+/*
+ * Note: samsung nv5000 doesn't work with ec burst mode.
+ * http://bugzilla.kernel.org/show_bug.cgi?id=4980
+ */
+int acpi_ec_burst_enable(struct acpi_ec *ec)
+{
+ u8 d;
+ return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1);
+}
+
+int acpi_ec_burst_disable(struct acpi_ec *ec)
+{
+ return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0);
+}
+
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
{
int result;
@@ -333,18 +296,33 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
/*
* Externally callable EC access functions. For now, assume 1 EC only
*/
+int ec_burst_enable(void)
+{
+ if (!first_ec)
+ return -ENODEV;
+ return acpi_ec_burst_enable(first_ec);
+}
+
+EXPORT_SYMBOL(ec_burst_enable);
+
+int ec_burst_disable(void)
+{
+ if (!first_ec)
+ return -ENODEV;
+ return acpi_ec_burst_disable(first_ec);
+}
+
+EXPORT_SYMBOL(ec_burst_disable);
+
int ec_read(u8 addr, u8 * val)
{
- struct acpi_ec *ec;
int err;
u8 temp_data;
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
-
- err = acpi_ec_read(ec, addr, &temp_data);
+ err = acpi_ec_read(first_ec, addr, &temp_data);
if (!err) {
*val = temp_data;
@@ -357,15 +335,12 @@ EXPORT_SYMBOL(ec_read);
int ec_write(u8 addr, u8 val)
{
- struct acpi_ec *ec;
int err;
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
-
- err = acpi_ec_write(ec, addr, val);
+ err = acpi_ec_write(first_ec, addr, val);
return err;
}
@@ -376,14 +351,10 @@ int ec_transaction(u8 command,
const u8 * wdata, unsigned wdata_len,
u8 * rdata, unsigned rdata_len)
{
- struct acpi_ec *ec;
-
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
-
- return acpi_ec_transaction(ec, command, wdata,
+ return acpi_ec_transaction(first_ec, command, wdata,
wdata_len, rdata, rdata_len);
}
@@ -420,7 +391,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
static void acpi_ec_gpe_query(void *ec_cxt)
{
- struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
+ struct acpi_ec *ec = ec_cxt;
u8 value = 0;
char object_name[8];
@@ -438,8 +409,9 @@ static u32 acpi_ec_gpe_handler(void *data)
{
acpi_status status = AE_OK;
u8 value;
- struct acpi_ec *ec = (struct acpi_ec *)data;
+ struct acpi_ec *ec = data;
atomic_inc(&ec->event_count);
+
if (acpi_ec_mode == EC_INTR) {
wake_up(&ec->wait);
}
@@ -482,7 +454,7 @@ acpi_ec_space_handler(u32 function,
void *handler_context, void *region_context)
{
int result = 0;
- struct acpi_ec *ec = NULL;
+ struct acpi_ec *ec = handler_context;
u64 temp = *value;
acpi_integer f_v = 0;
int i = 0;
@@ -494,8 +466,6 @@ acpi_ec_space_handler(u32 function,
return AE_BAD_PARAMETER;
}
- ec = (struct acpi_ec *)handler_context;
-
next_byte:
switch (function) {
case ACPI_READ:
@@ -551,18 +521,16 @@ static struct proc_dir_entry *acpi_ec_dir;
static int acpi_ec_read_info(struct seq_file *seq, void *offset)
{
- struct acpi_ec *ec = (struct acpi_ec *)seq->private;
+ struct acpi_ec *ec = seq->private;
if (!ec)
goto end;
- seq_printf(seq, "gpe: 0x%02x\n", (u32) ec->gpe);
- seq_printf(seq, "ports: 0x%02x, 0x%02x\n",
- (u32) ec->command_addr, (u32) ec->data_addr);
- seq_printf(seq, "use global lock: %s\n",
+ seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe);
+ seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n",
+ (unsigned)ec->command_addr, (unsigned)ec->data_addr);
+ seq_printf(seq, "use global lock:\t%s\n",
ec->global_lock ? "yes" : "no");
- acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
-
end:
return 0;
}
@@ -619,154 +587,122 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
+static acpi_status
+ec_parse_io_ports(struct acpi_resource *resource, void *context);
+
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
+
+static struct acpi_ec *make_acpi_ec(void)
+{
+ struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ if (!ec)
+ return NULL;
+
+ atomic_set(&ec->query_pending, 1);
+ atomic_set(&ec->event_count, 1);
+ mutex_init(&ec->lock);
+ init_waitqueue_head(&ec->wait);
+
+ return ec;
+}
static int acpi_ec_add(struct acpi_device *device)
{
- int result = 0;
acpi_status status = AE_OK;
struct acpi_ec *ec = NULL;
if (!device)
return -EINVAL;
- ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
- if (!ec)
- return -ENOMEM;
-
- ec->handle = device->handle;
- ec->uid = -1;
- mutex_init(&ec->lock);
- atomic_set(&ec->query_pending, 0);
- atomic_set(&ec->event_count, 1);
- if (acpi_ec_mode == EC_INTR) {
- atomic_set(&ec->leaving_burst, 1);
- init_waitqueue_head(&ec->wait);
- }
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
- acpi_driver_data(device) = ec;
-
- /* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock);
-
- /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
- http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
- if (ec_ecdt) {
- acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler);
- acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
- &acpi_ec_gpe_handler);
+ ec = make_acpi_ec();
+ if (!ec)
+ return -ENOMEM;
- kfree(ec_ecdt);
+ status = ec_parse_device(device->handle, 0, ec, NULL);
+ if (status != AE_CTRL_TERMINATE) {
+ kfree(ec);
+ return -EINVAL;
}
- /* Get GPE bit assignment (EC events). */
- /* TODO: Add support for _GPE returning a package */
- status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Obtaining GPE bit assignment"));
- result = -ENODEV;
- goto end;
- }
+ /* Check if we found the boot EC */
+ if (boot_ec) {
+ if (boot_ec->gpe == ec->gpe) {
+ /* We might have incorrect info for GL at boot time */
+ mutex_lock(&boot_ec->lock);
+ boot_ec->global_lock = ec->global_lock;
+ mutex_unlock(&boot_ec->lock);
+ kfree(ec);
+ ec = boot_ec;
+ }
+ } else
+ first_ec = ec;
+ ec->handle = device->handle;
+ acpi_driver_data(device) = ec;
- result = acpi_ec_add_fs(device);
- if (result)
- goto end;
+ acpi_ec_add_fs(device);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
acpi_device_name(device), acpi_device_bid(device),
(u32) ec->gpe));
- if (!first_ec)
- first_ec = device;
-
- end:
- if (result)
- kfree(ec);
-
- return result;
+ return 0;
}
static int acpi_ec_remove(struct acpi_device *device, int type)
{
- struct acpi_ec *ec = NULL;
+ struct acpi_ec *ec;
if (!device)
return -EINVAL;
ec = acpi_driver_data(device);
-
acpi_ec_remove_fs(device);
+ acpi_driver_data(device) = NULL;
+ if (ec == first_ec)
+ first_ec = NULL;
- kfree(ec);
-
+ /* Don't touch boot EC */
+ if (boot_ec != ec)
+ kfree(ec);
return 0;
}
static acpi_status
-acpi_ec_io_ports(struct acpi_resource *resource, void *context)
+ec_parse_io_ports(struct acpi_resource *resource, void *context)
{
- struct acpi_ec *ec = (struct acpi_ec *)context;
+ struct acpi_ec *ec = context;
- if (resource->type != ACPI_RESOURCE_TYPE_IO) {
+ if (resource->type != ACPI_RESOURCE_TYPE_IO)
return AE_OK;
- }
/*
* The first address region returned is the data port, and
* the second address region returned is the status/command
* port.
*/
- if (ec->data_addr == 0) {
+ if (ec->data_addr == 0)
ec->data_addr = resource->data.io.minimum;
- } else if (ec->command_addr == 0) {
+ else if (ec->command_addr == 0)
ec->command_addr = resource->data.io.minimum;
- } else {
+ else
return AE_CTRL_TERMINATE;
- }
return AE_OK;
}
-static int acpi_ec_start(struct acpi_device *device)
+static int ec_install_handlers(struct acpi_ec *ec)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
-
- if (!device)
- return -EINVAL;
-
- ec = acpi_driver_data(device);
-
- if (!ec)
- return -EINVAL;
-
- /*
- * Get I/O port addresses. Convert to GAS format.
- */
- status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
- acpi_ec_io_ports, ec);
- if (ACPI_FAILURE(status) || ec->command_addr == 0) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Error getting I/O port addresses"));
- return -ENODEV;
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
- ec->gpe, ec->command_addr, ec->data_addr));
-
- /*
- * Install GPE handler
- */
+ acpi_status status;
status = acpi_install_gpe_handler(NULL, ec->gpe,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec);
- if (ACPI_FAILURE(status)) {
+ if (ACPI_FAILURE(status))
return -ENODEV;
- }
+
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
@@ -779,18 +715,49 @@ static int acpi_ec_start(struct acpi_device *device)
return -ENODEV;
}
- return AE_OK;
+ /* EC is fully operational, allow queries */
+ atomic_set(&ec->query_pending, 0);
+
+ return 0;
+}
+
+static int acpi_ec_start(struct acpi_device *device)
+{
+ struct acpi_ec *ec;
+
+ if (!device)
+ return -EINVAL;
+
+ ec = acpi_driver_data(device);
+
+ if (!ec)
+ return -EINVAL;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
+ ec->gpe, ec->command_addr, ec->data_addr));
+
+ /* Boot EC is already working */
+ if (ec == boot_ec)
+ return 0;
+
+ return ec_install_handlers(ec);
}
static int acpi_ec_stop(struct acpi_device *device, int type)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ acpi_status status;
+ struct acpi_ec *ec;
if (!device)
return -EINVAL;
ec = acpi_driver_data(device);
+ if (!ec)
+ return -EINVAL;
+
+ /* Don't touch boot EC */
+ if (ec == boot_ec)
+ return 0;
status = acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
@@ -805,164 +772,67 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
return 0;
}
-static acpi_status __init
-acpi_fake_ecdt_callback(acpi_handle handle,
- u32 Level, void *context, void **retval)
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
{
acpi_status status;
- mutex_init(&ec_ecdt->lock);
- atomic_set(&ec_ecdt->event_count, 1);
- if (acpi_ec_mode == EC_INTR) {
- init_waitqueue_head(&ec_ecdt->wait);
- }
+ struct acpi_ec *ec = context;
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- acpi_ec_io_ports, ec_ecdt);
+ ec_parse_io_ports, ec);
if (ACPI_FAILURE(status))
return status;
- ec_ecdt->uid = -1;
- acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
-
- status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe);
+ /* Get GPE bit assignment (EC events). */
+ /* TODO: Add support for _GPE returning a package */
+ status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
if (ACPI_FAILURE(status))
return status;
- ec_ecdt->global_lock = TRUE;
- ec_ecdt->handle = handle;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
- ec_ecdt->gpe, ec_ecdt->command_addr,
- ec_ecdt->data_addr));
- return AE_CTRL_TERMINATE;
-}
-
-/*
- * Some BIOS (such as some from Gateway laptops) access EC region very early
- * such as in BAT0._INI or EC._INI before an EC device is found and
- * do not provide an ECDT. According to ACPI spec, ECDT isn't mandatorily
- * required, but if EC regison is accessed early, it is required.
- * The routine tries to workaround the BIOS bug by pre-scan EC device
- * It assumes that _CRS, _HID, _GPE, _UID methods of EC don't touch any
- * op region (since _REG isn't invoked yet). The assumption is true for
- * all systems found.
- */
-static int __init acpi_ec_fake_ecdt(void)
-{
- acpi_status status;
- int ret = 0;
+ /* Use the global lock for all EC transactions? */
+ acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
+ ec->handle = handle;
- ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
- if (!ec_ecdt) {
- ret = -ENOMEM;
- goto error;
- }
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
+ ec->gpe, ec->command_addr, ec->data_addr));
- status = acpi_get_devices(ACPI_EC_HID,
- acpi_fake_ecdt_callback, NULL, NULL);
- if (ACPI_FAILURE(status)) {
- kfree(ec_ecdt);
- ec_ecdt = NULL;
- ret = -ENODEV;
- ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
- goto error;
- }
- return 0;
- error:
- return ret;
+ return AE_CTRL_TERMINATE;
}
-static int __init acpi_ec_get_real_ecdt(void)
+int __init acpi_ec_ecdt_probe(void)
{
+ int ret;
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
- status = acpi_get_table(ACPI_SIG_ECDT, 1,
- (struct acpi_table_header **)&ecdt_ptr);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
-
+ boot_ec = make_acpi_ec();
+ if (!boot_ec)
+ return -ENOMEM;
/*
- * Generate a temporary ec context to use until the namespace is scanned
+ * Generate a boot ec context
*/
- ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
- if (!ec_ecdt)
- return -ENOMEM;
- mutex_init(&ec_ecdt->lock);
- atomic_set(&ec_ecdt->event_count, 1);
- if (acpi_ec_mode == EC_INTR) {
- init_waitqueue_head(&ec_ecdt->wait);
- }
- ec_ecdt->command_addr = ecdt_ptr->control.address;
- ec_ecdt->data_addr = ecdt_ptr->data.address;
- ec_ecdt->gpe = ecdt_ptr->gpe;
- /* use the GL just to be safe */
- ec_ecdt->global_lock = TRUE;
- ec_ecdt->uid = ecdt_ptr->uid;
-
- status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
- if (ACPI_FAILURE(status)) {
+ status = acpi_get_table(ACPI_SIG_ECDT, 1,
+ (struct acpi_table_header **)&ecdt_ptr);
+ if (ACPI_FAILURE(status))
goto error;
- }
-
- return 0;
- error:
- ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
- kfree(ec_ecdt);
- ec_ecdt = NULL;
- return -ENODEV;
-}
-
-static int __initdata acpi_fake_ecdt_enabled;
-int __init acpi_ec_ecdt_probe(void)
-{
- acpi_status status;
- int ret;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
- ret = acpi_ec_get_real_ecdt();
- /* Try to make a fake ECDT */
- if (ret && acpi_fake_ecdt_enabled) {
- ret = acpi_ec_fake_ecdt();
- }
+ boot_ec->command_addr = ecdt_ptr->control.address;
+ boot_ec->data_addr = ecdt_ptr->data.address;
+ boot_ec->gpe = ecdt_ptr->gpe;
+ boot_ec->handle = ACPI_ROOT_OBJECT;
- if (ret)
+ ret = ec_install_handlers(boot_ec);
+ if (!ret) {
+ first_ec = boot_ec;
return 0;
-
- /*
- * Install GPE handler
- */
- status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe,
- ACPI_GPE_EDGE_TRIGGERED,
- &acpi_ec_gpe_handler, ec_ecdt);
- if (ACPI_FAILURE(status)) {
- goto error;
}
- acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR);
-
- status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler,
- &acpi_ec_space_setup,
- ec_ecdt);
- if (ACPI_FAILURE(status)) {
- acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
- &acpi_ec_gpe_handler);
- goto error;
- }
-
- return 0;
-
error:
- ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
- kfree(ec_ecdt);
- ec_ecdt = NULL;
+ kfree(boot_ec);
+ boot_ec = NULL;
return -ENODEV;
}
@@ -1003,13 +873,6 @@ static void __exit acpi_ec_exit(void)
}
#endif /* 0 */
-static int __init acpi_fake_ecdt_setup(char *str)
-{
- acpi_fake_ecdt_enabled = 1;
- return 1;
-}
-
-__setup("acpi_fake_ecdt", acpi_fake_ecdt_setup);
static int __init acpi_ec_set_intr_mode(char *str)
{
int intr;
@@ -1017,12 +880,8 @@ static int __init acpi_ec_set_intr_mode(char *str)
if (!get_option(&str, &intr))
return 0;
- if (intr) {
- acpi_ec_mode = EC_INTR;
- } else {
- acpi_ec_mode = EC_POLL;
- }
- acpi_ec_driver.ops.add = acpi_ec_add;
+ acpi_ec_mode = (intr) ? EC_INTR : EC_POLL;
+
printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling");
return 1;
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
deleted file mode 100644
index acab4a481897..000000000000
--- a/drivers/acpi/i2c_ec.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * SMBus driver for ACPI Embedded Controller ($Revision: 1.3 $)
- *
- * Copyright (c) 2002, 2005 Ducrot Bruno
- * Copyright (c) 2005 Rich Townsend (tiny hacks & tweaks)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2.
- */
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/delay.h>
-
-#include "i2c_ec.h"
-
-#define xudelay(t) udelay(t)
-#define xmsleep(t) msleep(t)
-
-#define ACPI_EC_HC_COMPONENT 0x00080000
-#define ACPI_EC_HC_CLASS "ec_hc_smbus"
-#define ACPI_EC_HC_HID "ACPI0001"
-#define ACPI_EC_HC_DEVICE_NAME "EC HC smbus"
-
-#define _COMPONENT ACPI_EC_HC_COMPONENT
-
-ACPI_MODULE_NAME("i2c_ec");
-
-static int acpi_ec_hc_add(struct acpi_device *device);
-static int acpi_ec_hc_remove(struct acpi_device *device, int type);
-
-static struct acpi_driver acpi_ec_hc_driver = {
- .name = "i2c_ec",
- .class = ACPI_EC_HC_CLASS,
- .ids = ACPI_EC_HC_HID,
- .ops = {
- .add = acpi_ec_hc_add,
- .remove = acpi_ec_hc_remove,
- },
-};
-
-/* Various bit mask for EC_SC (R) */
-#define OBF 0x01
-#define IBF 0x02
-#define CMD 0x08
-#define BURST 0x10
-#define SCI_EVT 0x20
-#define SMI_EVT 0x40
-
-/* Commands for EC_SC (W) */
-#define RD_EC 0x80
-#define WR_EC 0x81
-#define BE_EC 0x82
-#define BD_EC 0x83
-#define QR_EC 0x84
-
-/*
- * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
- */
-
-#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */
-#define ACPI_EC_SMB_STS 0x01 /* status */
-#define ACPI_EC_SMB_ADDR 0x02 /* address */
-#define ACPI_EC_SMB_CMD 0x03 /* command */
-#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */
-#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */
-#define ACPI_EC_SMB_ALRM_A 0x25 /* alarm address */
-#define ACPI_EC_SMB_ALRM_D 0x26 /* 2 bytes alarm data */
-
-#define ACPI_EC_SMB_STS_DONE 0x80
-#define ACPI_EC_SMB_STS_ALRM 0x40
-#define ACPI_EC_SMB_STS_RES 0x20
-#define ACPI_EC_SMB_STS_STATUS 0x1f
-
-#define ACPI_EC_SMB_STATUS_OK 0x00
-#define ACPI_EC_SMB_STATUS_FAIL 0x07
-#define ACPI_EC_SMB_STATUS_DNAK 0x10
-#define ACPI_EC_SMB_STATUS_DERR 0x11
-#define ACPI_EC_SMB_STATUS_CMD_DENY 0x12
-#define ACPI_EC_SMB_STATUS_UNKNOWN 0x13
-#define ACPI_EC_SMB_STATUS_ACC_DENY 0x17
-#define ACPI_EC_SMB_STATUS_TIMEOUT 0x18
-#define ACPI_EC_SMB_STATUS_NOTSUP 0x19
-#define ACPI_EC_SMB_STATUS_BUSY 0x1A
-#define ACPI_EC_SMB_STATUS_PEC 0x1F
-
-#define ACPI_EC_SMB_PRTCL_WRITE 0x00
-#define ACPI_EC_SMB_PRTCL_READ 0x01
-#define ACPI_EC_SMB_PRTCL_QUICK 0x02
-#define ACPI_EC_SMB_PRTCL_BYTE 0x04
-#define ACPI_EC_SMB_PRTCL_BYTE_DATA 0x06
-#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08
-#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a
-#define ACPI_EC_SMB_PRTCL_PROC_CALL 0x0c
-#define ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
-#define ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
-#define ACPI_EC_SMB_PRTCL_PEC 0x80
-
-/* Length of pre/post transaction sleep (msec) */
-#define ACPI_EC_SMB_TRANSACTION_SLEEP 1
-#define ACPI_EC_SMB_ACCESS_SLEEP1 1
-#define ACPI_EC_SMB_ACCESS_SLEEP2 10
-
-static int acpi_ec_smb_read(struct acpi_ec_smbus *smbus, u8 address, u8 * data)
-{
- u8 val;
- int err;
-
- err = ec_read(smbus->base + address, &val);
- if (!err) {
- *data = val;
- }
- xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
- return (err);
-}
-
-static int acpi_ec_smb_write(struct acpi_ec_smbus *smbus, u8 address, u8 data)
-{
- int err;
-
- err = ec_write(smbus->base + address, data);
- return (err);
-}
-
-static int
-acpi_ec_smb_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
- char read_write, u8 command, int size,
- union i2c_smbus_data *data)
-{
- struct acpi_ec_smbus *smbus = adap->algo_data;
- unsigned char protocol, len = 0, pec, temp[2] = { 0, 0 };
- int i;
-
- if (read_write == I2C_SMBUS_READ) {
- protocol = ACPI_EC_SMB_PRTCL_READ;
- } else {
- protocol = ACPI_EC_SMB_PRTCL_WRITE;
- }
- pec = (flags & I2C_CLIENT_PEC) ? ACPI_EC_SMB_PRTCL_PEC : 0;
-
- switch (size) {
-
- case I2C_SMBUS_QUICK:
- protocol |= ACPI_EC_SMB_PRTCL_QUICK;
- read_write = I2C_SMBUS_WRITE;
- break;
-
- case I2C_SMBUS_BYTE:
- if (read_write == I2C_SMBUS_WRITE) {
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
- }
- protocol |= ACPI_EC_SMB_PRTCL_BYTE;
- break;
-
- case I2C_SMBUS_BYTE_DATA:
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- if (read_write == I2C_SMBUS_WRITE) {
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
- }
- protocol |= ACPI_EC_SMB_PRTCL_BYTE_DATA;
- break;
-
- case I2C_SMBUS_WORD_DATA:
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- if (read_write == I2C_SMBUS_WRITE) {
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1,
- data->word >> 8);
- }
- protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA | pec;
- break;
-
- case I2C_SMBUS_BLOCK_DATA:
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- if (read_write == I2C_SMBUS_WRITE) {
- len = min_t(u8, data->block[0], 32);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
- for (i = 0; i < len; i++)
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
- data->block[i + 1]);
- }
- protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA | pec;
- break;
-
- case I2C_SMBUS_I2C_BLOCK_DATA:
- len = min_t(u8, data->block[0], 32);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
- if (read_write == I2C_SMBUS_WRITE) {
- for (i = 0; i < len; i++) {
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
- data->block[i + 1]);
- }
- }
- protocol |= ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA;
- break;
-
- case I2C_SMBUS_PROC_CALL:
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, data->word >> 8);
- protocol = ACPI_EC_SMB_PRTCL_PROC_CALL | pec;
- read_write = I2C_SMBUS_READ;
- break;
-
- case I2C_SMBUS_BLOCK_PROC_CALL:
- protocol |= pec;
- len = min_t(u8, data->block[0], 31);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
- for (i = 0; i < len; i++)
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
- data->block[i + 1]);
- protocol = ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL | pec;
- read_write = I2C_SMBUS_READ;
- break;
-
- default:
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "EC SMBus adapter: "
- "Unsupported transaction %d\n", size));
- return (-1);
- }
-
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_ADDR, addr << 1);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_PRTCL, protocol);
-
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
-
- if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
- xudelay(500);
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
- }
- if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
- xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
- }
- if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
- || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
- return (-1);
- }
-
- if (read_write == I2C_SMBUS_WRITE) {
- return (0);
- }
-
- switch (size) {
-
- case I2C_SMBUS_BYTE:
- case I2C_SMBUS_BYTE_DATA:
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, &data->byte);
- break;
-
- case I2C_SMBUS_WORD_DATA:
- case I2C_SMBUS_PROC_CALL:
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, temp + 0);
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + 1, temp + 1);
- data->word = (temp[1] << 8) | temp[0];
- break;
-
- case I2C_SMBUS_BLOCK_DATA:
- case I2C_SMBUS_BLOCK_PROC_CALL:
- len = 0;
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_BCNT, &len);
- len = min_t(u8, len, 32);
- case I2C_SMBUS_I2C_BLOCK_DATA:
- for (i = 0; i < len; i++)
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + i,
- data->block + i + 1);
- data->block[0] = len;
- break;
- }
-
- return (0);
-}
-
-static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)
-{
-
- return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA |
- I2C_FUNC_SMBUS_PROC_CALL |
- I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
- I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);
-}
-
-static const struct i2c_algorithm acpi_ec_smbus_algorithm = {
- .smbus_xfer = acpi_ec_smb_access,
- .functionality = acpi_ec_smb_func,
-};
-
-static int acpi_ec_hc_add(struct acpi_device *device)
-{
- int status;
- unsigned long val;
- struct acpi_ec_hc *ec_hc;
- struct acpi_ec_smbus *smbus;
-
- if (!device) {
- return -EINVAL;
- }
-
- ec_hc = kzalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
- if (!ec_hc) {
- return -ENOMEM;
- }
-
- smbus = kzalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
- if (!smbus) {
- kfree(ec_hc);
- return -ENOMEM;
- }
-
- ec_hc->handle = device->handle;
- strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_EC_HC_CLASS);
- acpi_driver_data(device) = ec_hc;
-
- status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n"));
- kfree(ec_hc);
- kfree(smbus);
- return -EIO;
- }
-
- smbus->ec = acpi_driver_data(device->parent);
- smbus->base = (val & 0xff00ull) >> 8;
- smbus->alert = val & 0xffull;
-
- smbus->adapter.owner = THIS_MODULE;
- smbus->adapter.algo = &acpi_ec_smbus_algorithm;
- smbus->adapter.algo_data = smbus;
- smbus->adapter.dev.parent = &device->dev;
-
- if (i2c_add_adapter(&smbus->adapter)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "EC SMBus adapter: Failed to register adapter\n"));
- kfree(smbus);
- kfree(ec_hc);
- return -EIO;
- }
-
- ec_hc->smbus = smbus;
-
- printk(KERN_INFO PREFIX "%s [%s]\n",
- acpi_device_name(device), acpi_device_bid(device));
-
- return AE_OK;
-}
-
-static int acpi_ec_hc_remove(struct acpi_device *device, int type)
-{
- struct acpi_ec_hc *ec_hc;
-
- if (!device) {
- return -EINVAL;
- }
- ec_hc = acpi_driver_data(device);
-
- i2c_del_adapter(&ec_hc->smbus->adapter);
- kfree(ec_hc->smbus);
- kfree(ec_hc);
-
- return AE_OK;
-}
-
-static int __init acpi_ec_hc_init(void)
-{
- int result;
-
- result = acpi_bus_register_driver(&acpi_ec_hc_driver);
- if (result < 0) {
- return -ENODEV;
- }
- return 0;
-}
-
-static void __exit acpi_ec_hc_exit(void)
-{
- acpi_bus_unregister_driver(&acpi_ec_hc_driver);
-}
-
-struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)
-{
- return acpi_driver_data(device->parent);
-}
-
-EXPORT_SYMBOL(acpi_get_ec_hc);
-
-module_init(acpi_ec_hc_init);
-module_exit(acpi_ec_hc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ducrot Bruno");
-MODULE_DESCRIPTION("ACPI EC SMBus driver");
diff --git a/drivers/acpi/i2c_ec.h b/drivers/acpi/i2c_ec.h
deleted file mode 100644
index 7c53fb732d61..000000000000
--- a/drivers/acpi/i2c_ec.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $)
- *
- * Copyright (c) 2002, 2005 Ducrot Bruno
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2.
- */
-
-struct acpi_ec_smbus {
- struct i2c_adapter adapter;
- union acpi_ec *ec;
- int base;
- int alert;
-};
-
-struct acpi_ec_hc {
- acpi_handle handle;
- struct acpi_ec_smbus *smbus;
-};
-
-struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device);
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
deleted file mode 100644
index dc1096608f43..000000000000
--- a/drivers/acpi/ibm_acpi.c
+++ /dev/null
@@ -1,2798 +0,0 @@
-/*
- * ibm_acpi.c - IBM ThinkPad ACPI Extras
- *
- *
- * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
- * Copyright (C) 2006 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#define IBM_VERSION "0.13"
-
-/*
- * Changelog:
- *
- * 2006-11-22 0.13 new maintainer
- * changelog now lives in git commit history, and will
- * not be updated further in-file.
- *
- * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
- * 2005-03-17 0.11 support for 600e, 770x
- * thanks to Jamie Lentin <lentinj@dial.pipex.com>
- * support for 770e, G41
- * G40 and G41 don't have a thinklight
- * temperatures no longer experimental
- * experimental brightness control
- * experimental volume control
- * experimental fan enable/disable
- * 2005-01-16 0.10 fix module loading on R30, R31
- * 2005-01-16 0.9 support for 570, R30, R31
- * ultrabay support on A22p, A3x
- * limit arg for cmos, led, beep, drop experimental status
- * more capable led control on A21e, A22p, T20-22, X20
- * experimental temperatures and fan speed
- * experimental embedded controller register dump
- * mark more functions as __init, drop incorrect __exit
- * use MODULE_VERSION
- * thanks to Henrik Brix Andersen <brix@gentoo.org>
- * fix parameter passing on module loading
- * thanks to Rusty Russell <rusty@rustcorp.com.au>
- * thanks to Jim Radford <radford@blackbean.org>
- * 2004-11-08 0.8 fix init error case, don't return from a macro
- * thanks to Chris Wright <chrisw@osdl.org>
- * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20
- * fix led control on A21e
- * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device
- * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20
- * proc file format changed
- * video_switch command
- * experimental cmos control
- * experimental led control
- * experimental acpi sounds
- * 2004-09-16 0.4 support for module parameters
- * hotkey mask can be prefixed by 0x
- * video output switching
- * video expansion control
- * ultrabay eject support
- * removed lcd brightness/on/off control, didn't work
- * 2004-08-17 0.3 support for R40
- * lcd off, brightness control
- * thinklight on/off
- * 2004-08-14 0.2 support for T series, X20
- * bluetooth enable/disable
- * hotkey events disabled by default
- * removed fan control, currently useless
- * 2004-08-09 0.1 initial release, support for X series
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/string.h>
-
-#include <linux/proc_fs.h>
-#include <linux/backlight.h>
-#include <linux/fb.h>
-#include <asm/uaccess.h>
-
-#include <linux/dmi.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-
-#include <acpi/acpi_drivers.h>
-#include <acpi/acnamesp.h>
-
-#define IBM_NAME "ibm"
-#define IBM_DESC "IBM ThinkPad ACPI Extras"
-#define IBM_FILE "ibm_acpi"
-#define IBM_URL "http://ibm-acpi.sf.net/"
-
-MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
-MODULE_DESCRIPTION(IBM_DESC);
-MODULE_VERSION(IBM_VERSION);
-MODULE_LICENSE("GPL");
-
-#define IBM_DIR IBM_NAME
-
-#define IBM_LOG IBM_FILE ": "
-#define IBM_ERR KERN_ERR IBM_LOG
-#define IBM_NOTICE KERN_NOTICE IBM_LOG
-#define IBM_INFO KERN_INFO IBM_LOG
-#define IBM_DEBUG KERN_DEBUG IBM_LOG
-
-#define IBM_MAX_ACPI_ARGS 3
-
-#define __unused __attribute__ ((unused))
-
-static int experimental;
-module_param(experimental, int, 0);
-
-static acpi_handle root_handle = NULL;
-
-#define IBM_HANDLE(object, parent, paths...) \
- static acpi_handle object##_handle; \
- static acpi_handle *object##_parent = &parent##_handle; \
- static char *object##_path; \
- static char *object##_paths[] = { paths }
-
-IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
- "\\_SB.PCI.ISA.EC", /* 570 */
- "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
- "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
- "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */
- "\\_SB.PCI0.ICH3.EC0", /* R31 */
- "\\_SB.PCI0.LPC.EC", /* all others */
- );
-
-IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
- "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
- "\\_SB.PCI0.VID0", /* 770e */
- "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
- "\\_SB.PCI0.AGP.VID", /* all others */
- ); /* R30, R31 */
-
-IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
-
-IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */
- "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
- "\\CMS", /* R40, R40e */
- ); /* all others */
-#ifdef CONFIG_ACPI_IBM_DOCK
-IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
- "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
- "\\_SB.PCI0.PCI1.DOCK", /* all others */
- "\\_SB.PCI.ISA.SLCE", /* 570 */
- ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
-IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
- "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
- "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
- "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
- ); /* A21e, R30, R31 */
-
-IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
- "_EJ0", /* all others */
- ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
-
-IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
- "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
- ); /* all others */
-
-IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
- "_EJ0", /* 770x */
- ); /* all others */
-#endif /* CONFIG_ACPI_IBM_BAY */
-
-/* don't list other alternatives as we install a notify handler on the 570 */
-IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
-
-IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
- "^HKEY", /* R30, R31 */
- "HKEY", /* all others */
- ); /* 570 */
-
-IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
-IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
-
-IBM_HANDLE(led, ec, "SLED", /* 570 */
- "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
- "LED", /* all others */
- ); /* R30, R31 */
-
-IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
-IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
-IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
-IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
-
-IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
- "\\FSPD", /* 600e/x, 770e, 770x */
- ); /* all others */
-
-IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
- "JFNS", /* 770x-JL */
- ); /* all others */
-
-#define IBM_HKEY_HID "IBM0068"
-#define IBM_PCI_HID "PNP0A03"
-
-enum thermal_access_mode {
- IBMACPI_THERMAL_NONE = 0, /* No thermal support */
- IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
- IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
- IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
- IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
-};
-
-#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
-struct ibm_thermal_sensors_struct {
- s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
-};
-
-/*
- * FAN ACCESS MODES
- *
- * IBMACPI_FAN_RD_ACPI_GFAN:
- * ACPI GFAN method: returns fan level
- *
- * see IBMACPI_FAN_WR_ACPI_SFAN
- * EC 0x2f not available if GFAN exists
- *
- * IBMACPI_FAN_WR_ACPI_SFAN:
- * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
- *
- * EC 0x2f might be available *for reading*, but never for writing.
- *
- * IBMACPI_FAN_WR_TPEC:
- * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
- * on almost all ThinkPads
- *
- * Fan speed changes of any sort (including those caused by the
- * disengaged mode) are usually done slowly by the firmware as the
- * maximum ammount of fan duty cycle change per second seems to be
- * limited.
- *
- * Reading is not available if GFAN exists.
- * Writing is not available if SFAN exists.
- *
- * Bits
- * 7 automatic mode engaged;
- * (default operation mode of the ThinkPad)
- * fan level is ignored in this mode.
- * 6 disengage mode (takes precedence over bit 7);
- * not available on all thinkpads. May disable
- * the tachometer, and speeds up fan to 100% duty-cycle,
- * which speeds it up far above the standard RPM
- * levels. It is not impossible that it could cause
- * hardware damage.
- * 5-3 unused in some models. Extra bits for fan level
- * in others, but still useless as all values above
- * 7 map to the same speed as level 7 in these models.
- * 2-0 fan level (0..7 usually)
- * 0x00 = stop
- * 0x07 = max (set when temperatures critical)
- * Some ThinkPads may have other levels, see
- * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
- *
- * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
- * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
- * does so, its initial value is meaningless (0x07).
- *
- * For firmware bugs, refer to:
- * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
- *
- * ----
- *
- * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
- * Main fan tachometer reading (in RPM)
- *
- * This register is present on all ThinkPads with a new-style EC, and
- * it is known not to be present on the A21m/e, and T22, as there is
- * something else in offset 0x84 according to the ACPI DSDT. Other
- * ThinkPads from this same time period (and earlier) probably lack the
- * tachometer as well.
- *
- * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
- * was never fixed by IBM to report the EC firmware version string
- * probably support the tachometer (like the early X models), so
- * detecting it is quite hard. We need more data to know for sure.
- *
- * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
- * might result.
- *
- * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
- * register is not invalidated in ThinkPads that disable tachometer
- * readings. Thus, the tachometer readings go stale.
- *
- * For firmware bugs, refer to:
- * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
- *
- * IBMACPI_FAN_WR_ACPI_FANS:
- * ThinkPad X31, X40, X41. Not available in the X60.
- *
- * FANS ACPI handle: takes three arguments: low speed, medium speed,
- * high speed. ACPI DSDT seems to map these three speeds to levels
- * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
- * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
- *
- * The speeds are stored on handles
- * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
- *
- * There are three default speed sets, acessible as handles:
- * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
- *
- * ACPI DSDT switches which set is in use depending on various
- * factors.
- *
- * IBMACPI_FAN_WR_TPEC is also available and should be used to
- * command the fan. The X31/X40/X41 seems to have 8 fan levels,
- * but the ACPI tables just mention level 7.
- */
-
-enum fan_status_access_mode {
- IBMACPI_FAN_NONE = 0, /* No fan status or control */
- IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
- IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
-};
-
-enum fan_control_access_mode {
- IBMACPI_FAN_WR_NONE = 0, /* No fan control */
- IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
- IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
- IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
-};
-
-enum fan_control_commands {
- IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
- IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
- IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
- * and also watchdog cmd */
-};
-
-enum { /* Fan control constants */
- fan_status_offset = 0x2f, /* EC register 0x2f */
- fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
- * 0x84 must be read before 0x85 */
-
- IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer
- * disengaged */
- IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan
- * control */
-};
-
-static char *ibm_thinkpad_ec_found = NULL;
-
-struct ibm_struct {
- char *name;
- char param[32];
-
- char *hid;
- struct acpi_driver *driver;
-
- int (*init) (void);
- int (*read) (char *);
- int (*write) (char *);
- void (*exit) (void);
-
- void (*notify) (struct ibm_struct *, u32);
- acpi_handle *handle;
- int type;
- struct acpi_device *device;
-
- int driver_registered;
- int proc_created;
- int init_called;
- int notify_installed;
-
- int experimental;
-};
-
-static struct proc_dir_entry *proc_dir = NULL;
-
-static struct backlight_device *ibm_backlight_device = NULL;
-
-#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
-#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
-#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
-
-static int acpi_evalf(acpi_handle handle,
- void *res, char *method, char *fmt, ...)
-{
- char *fmt0 = fmt;
- struct acpi_object_list params;
- union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
- struct acpi_buffer result, *resultp;
- union acpi_object out_obj;
- acpi_status status;
- va_list ap;
- char res_type;
- int success;
- int quiet;
-
- if (!*fmt) {
- printk(IBM_ERR "acpi_evalf() called with empty format\n");
- return 0;
- }
-
- if (*fmt == 'q') {
- quiet = 1;
- fmt++;
- } else
- quiet = 0;
-
- res_type = *(fmt++);
-
- params.count = 0;
- params.pointer = &in_objs[0];
-
- va_start(ap, fmt);
- while (*fmt) {
- char c = *(fmt++);
- switch (c) {
- case 'd': /* int */
- in_objs[params.count].integer.value = va_arg(ap, int);
- in_objs[params.count++].type = ACPI_TYPE_INTEGER;
- break;
- /* add more types as needed */
- default:
- printk(IBM_ERR "acpi_evalf() called "
- "with invalid format character '%c'\n", c);
- return 0;
- }
- }
- va_end(ap);
-
- if (res_type != 'v') {
- result.length = sizeof(out_obj);
- result.pointer = &out_obj;
- resultp = &result;
- } else
- resultp = NULL;
-
- status = acpi_evaluate_object(handle, method, &params, resultp);
-
- switch (res_type) {
- case 'd': /* int */
- if (res)
- *(int *)res = out_obj.integer.value;
- success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
- break;
- case 'v': /* void */
- success = status == AE_OK;
- break;
- /* add more types as needed */
- default:
- printk(IBM_ERR "acpi_evalf() called "
- "with invalid format character '%c'\n", res_type);
- return 0;
- }
-
- if (!success && !quiet)
- printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
- method, fmt0, status);
-
- return success;
-}
-
-static void __unused acpi_print_int(acpi_handle handle, char *method)
-{
- int i;
-
- if (acpi_evalf(handle, &i, method, "d"))
- printk(IBM_INFO "%s = 0x%x\n", method, i);
- else
- printk(IBM_ERR "error calling %s\n", method);
-}
-
-static char *next_cmd(char **cmds)
-{
- char *start = *cmds;
- char *end;
-
- while ((end = strchr(start, ',')) && end == start)
- start = end + 1;
-
- if (!end)
- return NULL;
-
- *end = 0;
- *cmds = end + 1;
- return start;
-}
-
-static int ibm_acpi_driver_init(void)
-{
- printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
- printk(IBM_INFO "%s\n", IBM_URL);
-
- if (ibm_thinkpad_ec_found)
- printk(IBM_INFO "ThinkPad EC firmware %s\n",
- ibm_thinkpad_ec_found);
-
- return 0;
-}
-
-static int driver_read(char *p)
-{
- int len = 0;
-
- len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
- len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
-
- return len;
-}
-
-static int hotkey_supported;
-static int hotkey_mask_supported;
-static int hotkey_orig_status;
-static int hotkey_orig_mask;
-
-static int hotkey_get(int *status, int *mask)
-{
- if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
- return 0;
-
- if (hotkey_mask_supported)
- if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
- return 0;
-
- return 1;
-}
-
-static int hotkey_set(int status, int mask)
-{
- int i;
-
- if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
- return 0;
-
- if (hotkey_mask_supported)
- for (i = 0; i < 32; i++) {
- int bit = ((1 << i) & mask) != 0;
- if (!acpi_evalf(hkey_handle,
- NULL, "MHKM", "vdd", i + 1, bit))
- return 0;
- }
-
- return 1;
-}
-
-static int hotkey_init(void)
-{
- /* hotkey not supported on 570 */
- hotkey_supported = hkey_handle != NULL;
-
- if (hotkey_supported) {
- /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
- A30, R30, R31, T20-22, X20-21, X22-24 */
- hotkey_mask_supported =
- acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
-
- if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask))
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int hotkey_read(char *p)
-{
- int status, mask;
- int len = 0;
-
- if (!hotkey_supported) {
- len += sprintf(p + len, "status:\t\tnot supported\n");
- return len;
- }
-
- if (!hotkey_get(&status, &mask))
- return -EIO;
-
- len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
- if (hotkey_mask_supported) {
- len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
- len += sprintf(p + len,
- "commands:\tenable, disable, reset, <mask>\n");
- } else {
- len += sprintf(p + len, "mask:\t\tnot supported\n");
- len += sprintf(p + len, "commands:\tenable, disable, reset\n");
- }
-
- return len;
-}
-
-static int hotkey_write(char *buf)
-{
- int status, mask;
- char *cmd;
- int do_cmd = 0;
-
- if (!hotkey_supported)
- return -ENODEV;
-
- if (!hotkey_get(&status, &mask))
- return -EIO;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "enable") == 0) {
- status = 1;
- } else if (strlencmp(cmd, "disable") == 0) {
- status = 0;
- } else if (strlencmp(cmd, "reset") == 0) {
- status = hotkey_orig_status;
- mask = hotkey_orig_mask;
- } else if (sscanf(cmd, "0x%x", &mask) == 1) {
- /* mask set */
- } else if (sscanf(cmd, "%x", &mask) == 1) {
- /* mask set */
- } else
- return -EINVAL;
- do_cmd = 1;
- }
-
- if (do_cmd && !hotkey_set(status, mask))
- return -EIO;
-
- return 0;
-}
-
-static void hotkey_exit(void)
-{
- if (hotkey_supported)
- hotkey_set(hotkey_orig_status, hotkey_orig_mask);
-}
-
-static void hotkey_notify(struct ibm_struct *ibm, u32 event)
-{
- int hkey;
-
- if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
- acpi_bus_generate_event(ibm->device, event, hkey);
- else {
- printk(IBM_ERR "unknown hotkey event %d\n", event);
- acpi_bus_generate_event(ibm->device, event, 0);
- }
-}
-
-static int bluetooth_supported;
-
-static int bluetooth_init(void)
-{
- /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
- G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
- bluetooth_supported = hkey_handle &&
- acpi_evalf(hkey_handle, NULL, "GBDC", "qv");
-
- return 0;
-}
-
-static int bluetooth_status(void)
-{
- int status;
-
- if (!bluetooth_supported ||
- !acpi_evalf(hkey_handle, &status, "GBDC", "d"))
- status = 0;
-
- return status;
-}
-
-static int bluetooth_read(char *p)
-{
- int len = 0;
- int status = bluetooth_status();
-
- if (!bluetooth_supported)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else if (!(status & 1))
- len += sprintf(p + len, "status:\t\tnot installed\n");
- else {
- len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
- len += sprintf(p + len, "commands:\tenable, disable\n");
- }
-
- return len;
-}
-
-static int bluetooth_write(char *buf)
-{
- int status = bluetooth_status();
- char *cmd;
- int do_cmd = 0;
-
- if (!bluetooth_supported)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "enable") == 0) {
- status |= 2;
- } else if (strlencmp(cmd, "disable") == 0) {
- status &= ~2;
- } else
- return -EINVAL;
- do_cmd = 1;
- }
-
- if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
- return -EIO;
-
- return 0;
-}
-
-static int wan_supported;
-
-static int wan_init(void)
-{
- wan_supported = hkey_handle &&
- acpi_evalf(hkey_handle, NULL, "GWAN", "qv");
-
- return 0;
-}
-
-static int wan_status(void)
-{
- int status;
-
- if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
- status = 0;
-
- return status;
-}
-
-static int wan_read(char *p)
-{
- int len = 0;
- int status = wan_status();
-
- if (!wan_supported)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else if (!(status & 1))
- len += sprintf(p + len, "status:\t\tnot installed\n");
- else {
- len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
- len += sprintf(p + len, "commands:\tenable, disable\n");
- }
-
- return len;
-}
-
-static int wan_write(char *buf)
-{
- int status = wan_status();
- char *cmd;
- int do_cmd = 0;
-
- if (!wan_supported)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "enable") == 0) {
- status |= 2;
- } else if (strlencmp(cmd, "disable") == 0) {
- status &= ~2;
- } else
- return -EINVAL;
- do_cmd = 1;
- }
-
- if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
- return -EIO;
-
- return 0;
-}
-
-enum video_access_mode {
- IBMACPI_VIDEO_NONE = 0,
- IBMACPI_VIDEO_570, /* 570 */
- IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */
- IBMACPI_VIDEO_NEW, /* all others */
-};
-
-static enum video_access_mode video_supported;
-static int video_orig_autosw;
-
-static int video_init(void)
-{
- int ivga;
-
- if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
- /* G41, assume IVGA doesn't change */
- vid_handle = vid2_handle;
-
- if (!vid_handle)
- /* video switching not supported on R30, R31 */
- video_supported = IBMACPI_VIDEO_NONE;
- else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
- /* 570 */
- video_supported = IBMACPI_VIDEO_570;
- else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
- /* 600e/x, 770e, 770x */
- video_supported = IBMACPI_VIDEO_770;
- else
- /* all others */
- video_supported = IBMACPI_VIDEO_NEW;
-
- return 0;
-}
-
-static int video_status(void)
-{
- int status = 0;
- int i;
-
- if (video_supported == IBMACPI_VIDEO_570) {
- if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
- status = i & 3;
- } else if (video_supported == IBMACPI_VIDEO_770) {
- if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
- status |= 0x01 * i;
- if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
- status |= 0x02 * i;
- } else if (video_supported == IBMACPI_VIDEO_NEW) {
- acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
- if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
- status |= 0x02 * i;
-
- acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0);
- if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
- status |= 0x01 * i;
- if (acpi_evalf(NULL, &i, "\\VCDD", "d"))
- status |= 0x08 * i;
- }
-
- return status;
-}
-
-static int video_autosw(void)
-{
- int autosw = 0;
-
- if (video_supported == IBMACPI_VIDEO_570)
- acpi_evalf(vid_handle, &autosw, "SWIT", "d");
- else if (video_supported == IBMACPI_VIDEO_770 ||
- video_supported == IBMACPI_VIDEO_NEW)
- acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
-
- return autosw & 1;
-}
-
-static int video_read(char *p)
-{
- int status = video_status();
- int autosw = video_autosw();
- int len = 0;
-
- if (!video_supported) {
- len += sprintf(p + len, "status:\t\tnot supported\n");
- return len;
- }
-
- len += sprintf(p + len, "status:\t\tsupported\n");
- len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
- len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
- if (video_supported == IBMACPI_VIDEO_NEW)
- len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
- len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
- len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
- len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
- if (video_supported == IBMACPI_VIDEO_NEW)
- len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
- len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
- len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
-
- return len;
-}
-
-static int video_switch(void)
-{
- int autosw = video_autosw();
- int ret;
-
- if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
- return -EIO;
- ret = video_supported == IBMACPI_VIDEO_570 ?
- acpi_evalf(ec_handle, NULL, "_Q16", "v") :
- acpi_evalf(vid_handle, NULL, "VSWT", "v");
- acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
-
- return ret;
-}
-
-static int video_expand(void)
-{
- if (video_supported == IBMACPI_VIDEO_570)
- return acpi_evalf(ec_handle, NULL, "_Q17", "v");
- else if (video_supported == IBMACPI_VIDEO_770)
- return acpi_evalf(vid_handle, NULL, "VEXP", "v");
- else
- return acpi_evalf(NULL, NULL, "\\VEXP", "v");
-}
-
-static int video_switch2(int status)
-{
- int ret;
-
- if (video_supported == IBMACPI_VIDEO_570) {
- ret = acpi_evalf(NULL, NULL,
- "\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
- } else if (video_supported == IBMACPI_VIDEO_770) {
- int autosw = video_autosw();
- if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
- return -EIO;
-
- ret = acpi_evalf(vid_handle, NULL,
- "ASWT", "vdd", status * 0x100, 0);
-
- acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
- } else {
- ret = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
- acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
- }
-
- return ret;
-}
-
-static int video_write(char *buf)
-{
- char *cmd;
- int enable, disable, status;
-
- if (!video_supported)
- return -ENODEV;
-
- enable = disable = 0;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "lcd_enable") == 0) {
- enable |= 0x01;
- } else if (strlencmp(cmd, "lcd_disable") == 0) {
- disable |= 0x01;
- } else if (strlencmp(cmd, "crt_enable") == 0) {
- enable |= 0x02;
- } else if (strlencmp(cmd, "crt_disable") == 0) {
- disable |= 0x02;
- } else if (video_supported == IBMACPI_VIDEO_NEW &&
- strlencmp(cmd, "dvi_enable") == 0) {
- enable |= 0x08;
- } else if (video_supported == IBMACPI_VIDEO_NEW &&
- strlencmp(cmd, "dvi_disable") == 0) {
- disable |= 0x08;
- } else if (strlencmp(cmd, "auto_enable") == 0) {
- if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
- return -EIO;
- } else if (strlencmp(cmd, "auto_disable") == 0) {
- if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0))
- return -EIO;
- } else if (strlencmp(cmd, "video_switch") == 0) {
- if (!video_switch())
- return -EIO;
- } else if (strlencmp(cmd, "expand_toggle") == 0) {
- if (!video_expand())
- return -EIO;
- } else
- return -EINVAL;
- }
-
- if (enable || disable) {
- status = (video_status() & 0x0f & ~disable) | enable;
- if (!video_switch2(status))
- return -EIO;
- }
-
- return 0;
-}
-
-static void video_exit(void)
-{
- acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw);
-}
-
-static int light_supported;
-static int light_status_supported;
-
-static int light_init(void)
-{
- /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
- light_supported = (cmos_handle || lght_handle) && !ledb_handle;
-
- if (light_supported)
- /* light status not supported on
- 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
- light_status_supported = acpi_evalf(ec_handle, NULL,
- "KBLT", "qv");
-
- return 0;
-}
-
-static int light_read(char *p)
-{
- int len = 0;
- int status = 0;
-
- if (!light_supported) {
- len += sprintf(p + len, "status:\t\tnot supported\n");
- } else if (!light_status_supported) {
- len += sprintf(p + len, "status:\t\tunknown\n");
- len += sprintf(p + len, "commands:\ton, off\n");
- } else {
- if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
- return -EIO;
- len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
- len += sprintf(p + len, "commands:\ton, off\n");
- }
-
- return len;
-}
-
-static int light_write(char *buf)
-{
- int cmos_cmd, lght_cmd;
- char *cmd;
- int success;
-
- if (!light_supported)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "on") == 0) {
- cmos_cmd = 0x0c;
- lght_cmd = 1;
- } else if (strlencmp(cmd, "off") == 0) {
- cmos_cmd = 0x0d;
- lght_cmd = 0;
- } else
- return -EINVAL;
-
- success = cmos_handle ?
- acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
- acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
- if (!success)
- return -EIO;
- }
-
- return 0;
-}
-
-#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY)
-static int _sta(acpi_handle handle)
-{
- int status;
-
- if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
- status = 0;
-
- return status;
-}
-#endif
-
-#ifdef CONFIG_ACPI_IBM_DOCK
-#define dock_docked() (_sta(dock_handle) & 1)
-
-static int dock_read(char *p)
-{
- int len = 0;
- int docked = dock_docked();
-
- if (!dock_handle)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else if (!docked)
- len += sprintf(p + len, "status:\t\tundocked\n");
- else {
- len += sprintf(p + len, "status:\t\tdocked\n");
- len += sprintf(p + len, "commands:\tdock, undock\n");
- }
-
- return len;
-}
-
-static int dock_write(char *buf)
-{
- char *cmd;
-
- if (!dock_docked())
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "undock") == 0) {
- if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
- !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
- return -EIO;
- } else if (strlencmp(cmd, "dock") == 0) {
- if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void dock_notify(struct ibm_struct *ibm, u32 event)
-{
- int docked = dock_docked();
- int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID);
-
- if (event == 1 && !pci) /* 570 */
- acpi_bus_generate_event(ibm->device, event, 1); /* button */
- else if (event == 1 && pci) /* 570 */
- acpi_bus_generate_event(ibm->device, event, 3); /* dock */
- else if (event == 3 && docked)
- acpi_bus_generate_event(ibm->device, event, 1); /* button */
- else if (event == 3 && !docked)
- acpi_bus_generate_event(ibm->device, event, 2); /* undock */
- else if (event == 0 && docked)
- acpi_bus_generate_event(ibm->device, event, 3); /* dock */
- else {
- printk(IBM_ERR "unknown dock event %d, status %d\n",
- event, _sta(dock_handle));
- acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
- }
-}
-#endif
-
-#ifdef CONFIG_ACPI_IBM_BAY
-static int bay_status_supported;
-static int bay_status2_supported;
-static int bay_eject_supported;
-static int bay_eject2_supported;
-
-static int bay_init(void)
-{
- bay_status_supported = bay_handle &&
- acpi_evalf(bay_handle, NULL, "_STA", "qv");
- bay_status2_supported = bay2_handle &&
- acpi_evalf(bay2_handle, NULL, "_STA", "qv");
-
- bay_eject_supported = bay_handle && bay_ej_handle &&
- (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
- bay_eject2_supported = bay2_handle && bay2_ej_handle &&
- (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
-
- return 0;
-}
-
-#define bay_occupied(b) (_sta(b##_handle) & 1)
-
-static int bay_read(char *p)
-{
- int len = 0;
- int occupied = bay_occupied(bay);
- int occupied2 = bay_occupied(bay2);
- int eject, eject2;
-
- len += sprintf(p + len, "status:\t\t%s\n", bay_status_supported ?
- (occupied ? "occupied" : "unoccupied") :
- "not supported");
- if (bay_status2_supported)
- len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
- "occupied" : "unoccupied");
-
- eject = bay_eject_supported && occupied;
- eject2 = bay_eject2_supported && occupied2;
-
- if (eject && eject2)
- len += sprintf(p + len, "commands:\teject, eject2\n");
- else if (eject)
- len += sprintf(p + len, "commands:\teject\n");
- else if (eject2)
- len += sprintf(p + len, "commands:\teject2\n");
-
- return len;
-}
-
-static int bay_write(char *buf)
-{
- char *cmd;
-
- if (!bay_eject_supported && !bay_eject2_supported)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (bay_eject_supported && strlencmp(cmd, "eject") == 0) {
- if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
- return -EIO;
- } else if (bay_eject2_supported &&
- strlencmp(cmd, "eject2") == 0) {
- if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void bay_notify(struct ibm_struct *ibm, u32 event)
-{
- acpi_bus_generate_event(ibm->device, event, 0);
-}
-#endif /* CONFIG_ACPI_IBM_BAY */
-
-static int cmos_read(char *p)
-{
- int len = 0;
-
- /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
- R30, R31, T20-22, X20-21 */
- if (!cmos_handle)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else {
- len += sprintf(p + len, "status:\t\tsupported\n");
- len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
- }
-
- return len;
-}
-
-static int cmos_eval(int cmos_cmd)
-{
- if (cmos_handle)
- return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
- else
- return 1;
-}
-
-static int cmos_write(char *buf)
-{
- char *cmd;
- int cmos_cmd;
-
- if (!cmos_handle)
- return -EINVAL;
-
- while ((cmd = next_cmd(&buf))) {
- if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
- cmos_cmd >= 0 && cmos_cmd <= 21) {
- /* cmos_cmd set */
- } else
- return -EINVAL;
-
- if (!cmos_eval(cmos_cmd))
- return -EIO;
- }
-
- return 0;
-}
-
-enum led_access_mode {
- IBMACPI_LED_NONE = 0,
- IBMACPI_LED_570, /* 570 */
- IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
- IBMACPI_LED_NEW, /* all others */
-};
-static enum led_access_mode led_supported;
-
-static int led_init(void)
-{
- if (!led_handle)
- /* led not supported on R30, R31 */
- led_supported = IBMACPI_LED_NONE;
- else if (strlencmp(led_path, "SLED") == 0)
- /* 570 */
- led_supported = IBMACPI_LED_570;
- else if (strlencmp(led_path, "SYSL") == 0)
- /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
- led_supported = IBMACPI_LED_OLD;
- else
- /* all others */
- led_supported = IBMACPI_LED_NEW;
-
- return 0;
-}
-
-#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
-
-static int led_read(char *p)
-{
- int len = 0;
-
- if (!led_supported) {
- len += sprintf(p + len, "status:\t\tnot supported\n");
- return len;
- }
- len += sprintf(p + len, "status:\t\tsupported\n");
-
- if (led_supported == IBMACPI_LED_570) {
- /* 570 */
- int i, status;
- for (i = 0; i < 8; i++) {
- if (!acpi_evalf(ec_handle,
- &status, "GLED", "dd", 1 << i))
- return -EIO;
- len += sprintf(p + len, "%d:\t\t%s\n",
- i, led_status(status));
- }
- }
-
- len += sprintf(p + len, "commands:\t"
- "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
-
- return len;
-}
-
-/* off, on, blink */
-static const int led_sled_arg1[] = { 0, 1, 3 };
-static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
-static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
-static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
-
-#define EC_HLCL 0x0c
-#define EC_HLBL 0x0d
-#define EC_HLMS 0x0e
-
-static int led_write(char *buf)
-{
- char *cmd;
- int led, ind, ret;
-
- if (!led_supported)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
- return -EINVAL;
-
- if (strstr(cmd, "off")) {
- ind = 0;
- } else if (strstr(cmd, "on")) {
- ind = 1;
- } else if (strstr(cmd, "blink")) {
- ind = 2;
- } else
- return -EINVAL;
-
- if (led_supported == IBMACPI_LED_570) {
- /* 570 */
- led = 1 << led;
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_sled_arg1[ind]))
- return -EIO;
- } else if (led_supported == IBMACPI_LED_OLD) {
- /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
- led = 1 << led;
- ret = ec_write(EC_HLMS, led);
- if (ret >= 0)
- ret =
- ec_write(EC_HLBL, led * led_exp_hlbl[ind]);
- if (ret >= 0)
- ret =
- ec_write(EC_HLCL, led * led_exp_hlcl[ind]);
- if (ret < 0)
- return ret;
- } else {
- /* all others */
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_led_arg1[ind]))
- return -EIO;
- }
- }
-
- return 0;
-}
-
-static int beep_read(char *p)
-{
- int len = 0;
-
- if (!beep_handle)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else {
- len += sprintf(p + len, "status:\t\tsupported\n");
- len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
- }
-
- return len;
-}
-
-static int beep_write(char *buf)
-{
- char *cmd;
- int beep_cmd;
-
- if (!beep_handle)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
- beep_cmd >= 0 && beep_cmd <= 17) {
- /* beep_cmd set */
- } else
- return -EINVAL;
- if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
- return -EIO;
- }
-
- return 0;
-}
-
-static int acpi_ec_read(int i, u8 * p)
-{
- int v;
-
- if (ecrd_handle) {
- if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
- return 0;
- *p = v;
- } else {
- if (ec_read(i, p) < 0)
- return 0;
- }
-
- return 1;
-}
-
-static int acpi_ec_write(int i, u8 v)
-{
- if (ecwr_handle) {
- if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
- return 0;
- } else {
- if (ec_write(i, v) < 0)
- return 0;
- }
-
- return 1;
-}
-
-static enum thermal_access_mode thermal_read_mode;
-
-static int thermal_init(void)
-{
- u8 t, ta1, ta2;
- int i;
- int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
-
- if (ibm_thinkpad_ec_found && experimental) {
- /*
- * Direct EC access mode: sensors at registers
- * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
- * non-implemented, thermal sensors return 0x80 when
- * not available
- */
-
- ta1 = ta2 = 0;
- for (i = 0; i < 8; i++) {
- if (likely(acpi_ec_read(0x78 + i, &t))) {
- ta1 |= t;
- } else {
- ta1 = 0;
- break;
- }
- if (likely(acpi_ec_read(0xC0 + i, &t))) {
- ta2 |= t;
- } else {
- ta1 = 0;
- break;
- }
- }
- if (ta1 == 0) {
- /* This is sheer paranoia, but we handle it anyway */
- if (acpi_tmp7) {
- printk(IBM_ERR
- "ThinkPad ACPI EC access misbehaving, "
- "falling back to ACPI TMPx access mode\n");
- thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
- } else {
- printk(IBM_ERR
- "ThinkPad ACPI EC access misbehaving, "
- "disabling thermal sensors access\n");
- thermal_read_mode = IBMACPI_THERMAL_NONE;
- }
- } else {
- thermal_read_mode =
- (ta2 != 0) ?
- IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
- }
- } else if (acpi_tmp7) {
- if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
- /* 600e/x, 770e, 770x */
- thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
- } else {
- /* Standard ACPI TMPx access, max 8 sensors */
- thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
- }
- } else {
- /* temperatures not supported on 570, G4x, R30, R31, R32 */
- thermal_read_mode = IBMACPI_THERMAL_NONE;
- }
-
- return 0;
-}
-
-static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
-{
- int i, t;
- s8 tmp;
- char tmpi[] = "TMPi";
-
- if (!s)
- return -EINVAL;
-
- switch (thermal_read_mode) {
-#if IBMACPI_MAX_THERMAL_SENSORS >= 16
- case IBMACPI_THERMAL_TPEC_16:
- for (i = 0; i < 8; i++) {
- if (!acpi_ec_read(0xC0 + i, &tmp))
- return -EIO;
- s->temp[i + 8] = tmp * 1000;
- }
- /* fallthrough */
-#endif
- case IBMACPI_THERMAL_TPEC_8:
- for (i = 0; i < 8; i++) {
- if (!acpi_ec_read(0x78 + i, &tmp))
- return -EIO;
- s->temp[i] = tmp * 1000;
- }
- return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
-
- case IBMACPI_THERMAL_ACPI_UPDT:
- if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
- return -EIO;
- for (i = 0; i < 8; i++) {
- tmpi[3] = '0' + i;
- if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
- return -EIO;
- s->temp[i] = (t - 2732) * 100;
- }
- return 8;
-
- case IBMACPI_THERMAL_ACPI_TMP07:
- for (i = 0; i < 8; i++) {
- tmpi[3] = '0' + i;
- if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
- return -EIO;
- s->temp[i] = t * 1000;
- }
- return 8;
-
- case IBMACPI_THERMAL_NONE:
- default:
- return 0;
- }
-}
-
-static int thermal_read(char *p)
-{
- int len = 0;
- int n, i;
- struct ibm_thermal_sensors_struct t;
-
- n = thermal_get_sensors(&t);
- if (unlikely(n < 0))
- return n;
-
- len += sprintf(p + len, "temperatures:\t");
-
- if (n > 0) {
- for (i = 0; i < (n - 1); i++)
- len += sprintf(p + len, "%d ", t.temp[i] / 1000);
- len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
- } else
- len += sprintf(p + len, "not supported\n");
-
- return len;
-}
-
-static u8 ecdump_regs[256];
-
-static int ecdump_read(char *p)
-{
- int len = 0;
- int i, j;
- u8 v;
-
- len += sprintf(p + len, "EC "
- " +00 +01 +02 +03 +04 +05 +06 +07"
- " +08 +09 +0a +0b +0c +0d +0e +0f\n");
- for (i = 0; i < 256; i += 16) {
- len += sprintf(p + len, "EC 0x%02x:", i);
- for (j = 0; j < 16; j++) {
- if (!acpi_ec_read(i + j, &v))
- break;
- if (v != ecdump_regs[i + j])
- len += sprintf(p + len, " *%02x", v);
- else
- len += sprintf(p + len, " %02x", v);
- ecdump_regs[i + j] = v;
- }
- len += sprintf(p + len, "\n");
- if (j != 16)
- break;
- }
-
- /* These are way too dangerous to advertise openly... */
-#if 0
- len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
- " (<offset> is 00-ff, <value> is 00-ff)\n");
- len += sprintf(p + len, "commands:\t0x<offset> <value> "
- " (<offset> is 00-ff, <value> is 0-255)\n");
-#endif
- return len;
-}
-
-static int ecdump_write(char *buf)
-{
- char *cmd;
- int i, v;
-
- while ((cmd = next_cmd(&buf))) {
- if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
- /* i and v set */
- } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
- /* i and v set */
- } else
- return -EINVAL;
- if (i >= 0 && i < 256 && v >= 0 && v < 256) {
- if (!acpi_ec_write(i, v))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int brightness_offset = 0x31;
-
-static int brightness_get(struct backlight_device *bd)
-{
- u8 level;
- if (!acpi_ec_read(brightness_offset, &level))
- return -EIO;
-
- level &= 0x7;
-
- return level;
-}
-
-static int brightness_read(char *p)
-{
- int len = 0;
- int level;
-
- if ((level = brightness_get(NULL)) < 0) {
- len += sprintf(p + len, "level:\t\tunreadable\n");
- } else {
- len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
- len += sprintf(p + len, "commands:\tup, down\n");
- len += sprintf(p + len, "commands:\tlevel <level>"
- " (<level> is 0-7)\n");
- }
-
- return len;
-}
-
-#define BRIGHTNESS_UP 4
-#define BRIGHTNESS_DOWN 5
-
-static int brightness_set(int value)
-{
- int cmos_cmd, inc, i;
- int current_value = brightness_get(NULL);
-
- value &= 7;
-
- cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
- inc = value > current_value ? 1 : -1;
- for (i = current_value; i != value; i += inc) {
- if (!cmos_eval(cmos_cmd))
- return -EIO;
- if (!acpi_ec_write(brightness_offset, i + inc))
- return -EIO;
- }
-
- return 0;
-}
-
-static int brightness_write(char *buf)
-{
- int level;
- int new_level;
- char *cmd;
-
- while ((cmd = next_cmd(&buf))) {
- if ((level = brightness_get(NULL)) < 0)
- return level;
- level &= 7;
-
- if (strlencmp(cmd, "up") == 0) {
- new_level = level == 7 ? 7 : level + 1;
- } else if (strlencmp(cmd, "down") == 0) {
- new_level = level == 0 ? 0 : level - 1;
- } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
- new_level >= 0 && new_level <= 7) {
- /* new_level set */
- } else
- return -EINVAL;
-
- brightness_set(new_level);
- }
-
- return 0;
-}
-
-static int brightness_update_status(struct backlight_device *bd)
-{
- return brightness_set(
- (bd->props.fb_blank == FB_BLANK_UNBLANK &&
- bd->props.power == FB_BLANK_UNBLANK) ?
- bd->props.brightness : 0);
-}
-
-static struct backlight_ops ibm_backlight_data = {
- .get_brightness = brightness_get,
- .update_status = brightness_update_status,
-};
-
-static int brightness_init(void)
-{
- int b;
-
- b = brightness_get(NULL);
- if (b < 0)
- return b;
-
- ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
- &ibm_backlight_data);
- if (IS_ERR(ibm_backlight_device)) {
- printk(IBM_ERR "Could not register backlight device\n");
- return PTR_ERR(ibm_backlight_device);
- }
-
- ibm_backlight_device->props.max_brightness = 7;
- ibm_backlight_device->props.brightness = b;
- backlight_update_status(ibm_backlight_device);
-
- return 0;
-}
-
-static void brightness_exit(void)
-{
- if (ibm_backlight_device) {
- backlight_device_unregister(ibm_backlight_device);
- ibm_backlight_device = NULL;
- }
-}
-
-static int volume_offset = 0x30;
-
-static int volume_read(char *p)
-{
- int len = 0;
- u8 level;
-
- if (!acpi_ec_read(volume_offset, &level)) {
- len += sprintf(p + len, "level:\t\tunreadable\n");
- } else {
- len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
- len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
- len += sprintf(p + len, "commands:\tup, down, mute\n");
- len += sprintf(p + len, "commands:\tlevel <level>"
- " (<level> is 0-15)\n");
- }
-
- return len;
-}
-
-#define VOLUME_DOWN 0
-#define VOLUME_UP 1
-#define VOLUME_MUTE 2
-
-static int volume_write(char *buf)
-{
- int cmos_cmd, inc, i;
- u8 level, mute;
- int new_level, new_mute;
- char *cmd;
-
- while ((cmd = next_cmd(&buf))) {
- if (!acpi_ec_read(volume_offset, &level))
- return -EIO;
- new_mute = mute = level & 0x40;
- new_level = level = level & 0xf;
-
- if (strlencmp(cmd, "up") == 0) {
- if (mute)
- new_mute = 0;
- else
- new_level = level == 15 ? 15 : level + 1;
- } else if (strlencmp(cmd, "down") == 0) {
- if (mute)
- new_mute = 0;
- else
- new_level = level == 0 ? 0 : level - 1;
- } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
- new_level >= 0 && new_level <= 15) {
- /* new_level set */
- } else if (strlencmp(cmd, "mute") == 0) {
- new_mute = 0x40;
- } else
- return -EINVAL;
-
- if (new_level != level) { /* mute doesn't change */
- cmos_cmd = new_level > level ? VOLUME_UP : VOLUME_DOWN;
- inc = new_level > level ? 1 : -1;
-
- if (mute && (!cmos_eval(cmos_cmd) ||
- !acpi_ec_write(volume_offset, level)))
- return -EIO;
-
- for (i = level; i != new_level; i += inc)
- if (!cmos_eval(cmos_cmd) ||
- !acpi_ec_write(volume_offset, i + inc))
- return -EIO;
-
- if (mute && (!cmos_eval(VOLUME_MUTE) ||
- !acpi_ec_write(volume_offset,
- new_level + mute)))
- return -EIO;
- }
-
- if (new_mute != mute) { /* level doesn't change */
- cmos_cmd = new_mute ? VOLUME_MUTE : VOLUME_UP;
-
- if (!cmos_eval(cmos_cmd) ||
- !acpi_ec_write(volume_offset, level + new_mute))
- return -EIO;
- }
- }
-
- return 0;
-}
-
-static enum fan_status_access_mode fan_status_access_mode;
-static enum fan_control_access_mode fan_control_access_mode;
-static enum fan_control_commands fan_control_commands;
-
-static int fan_control_status_known;
-static u8 fan_control_initial_status;
-
-static void fan_watchdog_fire(struct work_struct *ignored);
-static int fan_watchdog_maxinterval;
-static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
-
-static int fan_init(void)
-{
- fan_status_access_mode = IBMACPI_FAN_NONE;
- fan_control_access_mode = IBMACPI_FAN_WR_NONE;
- fan_control_commands = 0;
- fan_control_status_known = 1;
- fan_watchdog_maxinterval = 0;
-
- if (gfan_handle) {
- /* 570, 600e/x, 770e, 770x */
- fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN;
- } else {
- /* all other ThinkPads: note that even old-style
- * ThinkPad ECs supports the fan control register */
- if (likely(acpi_ec_read(fan_status_offset,
- &fan_control_initial_status))) {
- fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
-
- /* In some ThinkPads, neither the EC nor the ACPI
- * DSDT initialize the fan status, and it ends up
- * being set to 0x07 when it *could* be either
- * 0x07 or 0x80.
- *
- * Enable for TP-1Y (T43), TP-78 (R51e),
- * TP-76 (R52), TP-70 (T43, R52), which are known
- * to be buggy. */
- if (fan_control_initial_status == 0x07 &&
- ibm_thinkpad_ec_found &&
- ((ibm_thinkpad_ec_found[0] == '1' &&
- ibm_thinkpad_ec_found[1] == 'Y') ||
- (ibm_thinkpad_ec_found[0] == '7' &&
- (ibm_thinkpad_ec_found[1] == '6' ||
- ibm_thinkpad_ec_found[1] == '8' ||
- ibm_thinkpad_ec_found[1] == '0'))
- )) {
- printk(IBM_NOTICE
- "fan_init: initial fan status is "
- "unknown, assuming it is in auto "
- "mode\n");
- fan_control_status_known = 0;
- }
- } else {
- printk(IBM_ERR
- "ThinkPad ACPI EC access misbehaving, "
- "fan status and control unavailable\n");
- return 0;
- }
- }
-
- if (sfan_handle) {
- /* 570, 770x-JL */
- fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
- fan_control_commands |=
- IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE;
- } else {
- if (!gfan_handle) {
- /* gfan without sfan means no fan control */
- /* all other models implement TP EC 0x2f control */
-
- if (fans_handle) {
- /* X31, X40, X41 */
- fan_control_access_mode =
- IBMACPI_FAN_WR_ACPI_FANS;
- fan_control_commands |=
- IBMACPI_FAN_CMD_SPEED |
- IBMACPI_FAN_CMD_LEVEL |
- IBMACPI_FAN_CMD_ENABLE;
- } else {
- fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
- fan_control_commands |=
- IBMACPI_FAN_CMD_LEVEL |
- IBMACPI_FAN_CMD_ENABLE;
- }
- }
- }
-
- return 0;
-}
-
-static int fan_get_status(u8 *status)
-{
- u8 s;
-
- /* TODO:
- * Add IBMACPI_FAN_RD_ACPI_FANS ? */
-
- switch (fan_status_access_mode) {
- case IBMACPI_FAN_RD_ACPI_GFAN:
- /* 570, 600e/x, 770e, 770x */
-
- if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
- return -EIO;
-
- if (likely(status))
- *status = s & 0x07;
-
- break;
-
- case IBMACPI_FAN_RD_TPEC:
- /* all except 570, 600e/x, 770e, 770x */
- if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
- return -EIO;
-
- if (likely(status))
- *status = s;
-
- break;
-
- default:
- return -ENXIO;
- }
-
- return 0;
-}
-
-static int fan_get_speed(unsigned int *speed)
-{
- u8 hi, lo;
-
- switch (fan_status_access_mode) {
- case IBMACPI_FAN_RD_TPEC:
- /* all except 570, 600e/x, 770e, 770x */
- if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
- !acpi_ec_read(fan_rpm_offset + 1, &hi)))
- return -EIO;
-
- if (likely(speed))
- *speed = (hi << 8) | lo;
-
- break;
-
- default:
- return -ENXIO;
- }
-
- return 0;
-}
-
-static void fan_exit(void)
-{
- cancel_delayed_work(&fan_watchdog_task);
- flush_scheduled_work();
-}
-
-static void fan_watchdog_reset(void)
-{
- static int fan_watchdog_active = 0;
-
- if (fan_watchdog_active)
- cancel_delayed_work(&fan_watchdog_task);
-
- if (fan_watchdog_maxinterval > 0) {
- fan_watchdog_active = 1;
- if (!schedule_delayed_work(&fan_watchdog_task,
- msecs_to_jiffies(fan_watchdog_maxinterval
- * 1000))) {
- printk(IBM_ERR "failed to schedule the fan watchdog, "
- "watchdog will not trigger\n");
- }
- } else
- fan_watchdog_active = 0;
-}
-
-static int fan_read(char *p)
-{
- int len = 0;
- int rc;
- u8 status;
- unsigned int speed = 0;
-
- switch (fan_status_access_mode) {
- case IBMACPI_FAN_RD_ACPI_GFAN:
- /* 570, 600e/x, 770e, 770x */
- if ((rc = fan_get_status(&status)) < 0)
- return rc;
-
- len += sprintf(p + len, "status:\t\t%s\n"
- "level:\t\t%d\n",
- (status != 0) ? "enabled" : "disabled", status);
- break;
-
- case IBMACPI_FAN_RD_TPEC:
- /* all except 570, 600e/x, 770e, 770x */
- if ((rc = fan_get_status(&status)) < 0)
- return rc;
-
- if (unlikely(!fan_control_status_known)) {
- if (status != fan_control_initial_status)
- fan_control_status_known = 1;
- else
- /* Return most likely status. In fact, it
- * might be the only possible status */
- status = IBMACPI_FAN_EC_AUTO;
- }
-
- len += sprintf(p + len, "status:\t\t%s\n",
- (status != 0) ? "enabled" : "disabled");
-
- /* No ThinkPad boots on disengaged mode, we can safely
- * assume the tachometer is online if fan control status
- * was unknown */
- if ((rc = fan_get_speed(&speed)) < 0)
- return rc;
-
- len += sprintf(p + len, "speed:\t\t%d\n", speed);
-
- if (status & IBMACPI_FAN_EC_DISENGAGED)
- /* Disengaged mode takes precedence */
- len += sprintf(p + len, "level:\t\tdisengaged\n");
- else if (status & IBMACPI_FAN_EC_AUTO)
- len += sprintf(p + len, "level:\t\tauto\n");
- else
- len += sprintf(p + len, "level:\t\t%d\n", status);
- break;
-
- case IBMACPI_FAN_NONE:
- default:
- len += sprintf(p + len, "status:\t\tnot supported\n");
- }
-
- if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
- len += sprintf(p + len, "commands:\tlevel <level>");
-
- switch (fan_control_access_mode) {
- case IBMACPI_FAN_WR_ACPI_SFAN:
- len += sprintf(p + len, " (<level> is 0-7)\n");
- break;
-
- default:
- len += sprintf(p + len, " (<level> is 0-7, "
- "auto, disengaged)\n");
- break;
- }
- }
-
- if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
- len += sprintf(p + len, "commands:\tenable, disable\n"
- "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
- "1-120 (seconds))\n");
-
- if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
- len += sprintf(p + len, "commands:\tspeed <speed>"
- " (<speed> is 0-65535)\n");
-
- return len;
-}
-
-static int fan_set_level(int level)
-{
- switch (fan_control_access_mode) {
- case IBMACPI_FAN_WR_ACPI_SFAN:
- if (level >= 0 && level <= 7) {
- if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
- return -EIO;
- } else
- return -EINVAL;
- break;
-
- case IBMACPI_FAN_WR_ACPI_FANS:
- case IBMACPI_FAN_WR_TPEC:
- if ((level != IBMACPI_FAN_EC_AUTO) &&
- (level != IBMACPI_FAN_EC_DISENGAGED) &&
- ((level < 0) || (level > 7)))
- return -EINVAL;
-
- if (!acpi_ec_write(fan_status_offset, level))
- return -EIO;
- else
- fan_control_status_known = 1;
- break;
-
- default:
- return -ENXIO;
- }
- return 0;
-}
-
-static int fan_set_enable(void)
-{
- u8 s;
- int rc;
-
- switch (fan_control_access_mode) {
- case IBMACPI_FAN_WR_ACPI_FANS:
- case IBMACPI_FAN_WR_TPEC:
- if ((rc = fan_get_status(&s)) < 0)
- return rc;
-
- /* Don't go out of emergency fan mode */
- if (s != 7)
- s = IBMACPI_FAN_EC_AUTO;
-
- if (!acpi_ec_write(fan_status_offset, s))
- return -EIO;
- else
- fan_control_status_known = 1;
- break;
-
- case IBMACPI_FAN_WR_ACPI_SFAN:
- if ((rc = fan_get_status(&s)) < 0)
- return rc;
-
- s &= 0x07;
-
- /* Set fan to at least level 4 */
- if (s < 4)
- s = 4;
-
- if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
- return -EIO;
- break;
-
- default:
- return -ENXIO;
- }
- return 0;
-}
-
-static int fan_set_disable(void)
-{
- switch (fan_control_access_mode) {
- case IBMACPI_FAN_WR_ACPI_FANS:
- case IBMACPI_FAN_WR_TPEC:
- if (!acpi_ec_write(fan_status_offset, 0x00))
- return -EIO;
- else
- fan_control_status_known = 1;
- break;
-
- case IBMACPI_FAN_WR_ACPI_SFAN:
- if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
- return -EIO;
- break;
-
- default:
- return -ENXIO;
- }
- return 0;
-}
-
-static int fan_set_speed(int speed)
-{
- switch (fan_control_access_mode) {
- case IBMACPI_FAN_WR_ACPI_FANS:
- if (speed >= 0 && speed <= 65535) {
- if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
- speed, speed, speed))
- return -EIO;
- } else
- return -EINVAL;
- break;
-
- default:
- return -ENXIO;
- }
- return 0;
-}
-
-static int fan_write_cmd_level(const char *cmd, int *rc)
-{
- int level;
-
- if (strlencmp(cmd, "level auto") == 0)
- level = IBMACPI_FAN_EC_AUTO;
- else if (strlencmp(cmd, "level disengaged") == 0)
- level = IBMACPI_FAN_EC_DISENGAGED;
- else if (sscanf(cmd, "level %d", &level) != 1)
- return 0;
-
- if ((*rc = fan_set_level(level)) == -ENXIO)
- printk(IBM_ERR "level command accepted for unsupported "
- "access mode %d", fan_control_access_mode);
-
- return 1;
-}
-
-static int fan_write_cmd_enable(const char *cmd, int *rc)
-{
- if (strlencmp(cmd, "enable") != 0)
- return 0;
-
- if ((*rc = fan_set_enable()) == -ENXIO)
- printk(IBM_ERR "enable command accepted for unsupported "
- "access mode %d", fan_control_access_mode);
-
- return 1;
-}
-
-static int fan_write_cmd_disable(const char *cmd, int *rc)
-{
- if (strlencmp(cmd, "disable") != 0)
- return 0;
-
- if ((*rc = fan_set_disable()) == -ENXIO)
- printk(IBM_ERR "disable command accepted for unsupported "
- "access mode %d", fan_control_access_mode);
-
- return 1;
-}
-
-static int fan_write_cmd_speed(const char *cmd, int *rc)
-{
- int speed;
-
- /* TODO:
- * Support speed <low> <medium> <high> ? */
-
- if (sscanf(cmd, "speed %d", &speed) != 1)
- return 0;
-
- if ((*rc = fan_set_speed(speed)) == -ENXIO)
- printk(IBM_ERR "speed command accepted for unsupported "
- "access mode %d", fan_control_access_mode);
-
- return 1;
-}
-
-static int fan_write_cmd_watchdog(const char *cmd, int *rc)
-{
- int interval;
-
- if (sscanf(cmd, "watchdog %d", &interval) != 1)
- return 0;
-
- if (interval < 0 || interval > 120)
- *rc = -EINVAL;
- else
- fan_watchdog_maxinterval = interval;
-
- return 1;
-}
-
-static int fan_write(char *buf)
-{
- char *cmd;
- int rc = 0;
-
- while (!rc && (cmd = next_cmd(&buf))) {
- if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) &&
- fan_write_cmd_level(cmd, &rc)) &&
- !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) &&
- (fan_write_cmd_enable(cmd, &rc) ||
- fan_write_cmd_disable(cmd, &rc) ||
- fan_write_cmd_watchdog(cmd, &rc))) &&
- !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) &&
- fan_write_cmd_speed(cmd, &rc))
- )
- rc = -EINVAL;
- else if (!rc)
- fan_watchdog_reset();
- }
-
- return rc;
-}
-
-static void fan_watchdog_fire(struct work_struct *ignored)
-{
- printk(IBM_NOTICE "fan watchdog: enabling fan\n");
- if (fan_set_enable()) {
- printk(IBM_ERR "fan watchdog: error while enabling fan\n");
- /* reschedule for later */
- fan_watchdog_reset();
- }
-}
-
-static struct ibm_struct ibms[] = {
- {
- .name = "driver",
- .init = ibm_acpi_driver_init,
- .read = driver_read,
- },
- {
- .name = "hotkey",
- .hid = IBM_HKEY_HID,
- .init = hotkey_init,
- .read = hotkey_read,
- .write = hotkey_write,
- .exit = hotkey_exit,
- .notify = hotkey_notify,
- .handle = &hkey_handle,
- .type = ACPI_DEVICE_NOTIFY,
- },
- {
- .name = "bluetooth",
- .init = bluetooth_init,
- .read = bluetooth_read,
- .write = bluetooth_write,
- },
- {
- .name = "wan",
- .init = wan_init,
- .read = wan_read,
- .write = wan_write,
- .experimental = 1,
- },
- {
- .name = "video",
- .init = video_init,
- .read = video_read,
- .write = video_write,
- .exit = video_exit,
- },
- {
- .name = "light",
- .init = light_init,
- .read = light_read,
- .write = light_write,
- },
-#ifdef CONFIG_ACPI_IBM_DOCK
- {
- .name = "dock",
- .read = dock_read,
- .write = dock_write,
- .notify = dock_notify,
- .handle = &dock_handle,
- .type = ACPI_SYSTEM_NOTIFY,
- },
- {
- .name = "dock",
- .hid = IBM_PCI_HID,
- .notify = dock_notify,
- .handle = &pci_handle,
- .type = ACPI_SYSTEM_NOTIFY,
- },
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
- {
- .name = "bay",
- .init = bay_init,
- .read = bay_read,
- .write = bay_write,
- .notify = bay_notify,
- .handle = &bay_handle,
- .type = ACPI_SYSTEM_NOTIFY,
- },
-#endif /* CONFIG_ACPI_IBM_BAY */
- {
- .name = "cmos",
- .read = cmos_read,
- .write = cmos_write,
- },
- {
- .name = "led",
- .init = led_init,
- .read = led_read,
- .write = led_write,
- },
- {
- .name = "beep",
- .read = beep_read,
- .write = beep_write,
- },
- {
- .name = "thermal",
- .init = thermal_init,
- .read = thermal_read,
- },
- {
- .name = "ecdump",
- .read = ecdump_read,
- .write = ecdump_write,
- .experimental = 1,
- },
- {
- .name = "brightness",
- .read = brightness_read,
- .write = brightness_write,
- .init = brightness_init,
- .exit = brightness_exit,
- },
- {
- .name = "volume",
- .read = volume_read,
- .write = volume_write,
- },
- {
- .name = "fan",
- .read = fan_read,
- .write = fan_write,
- .init = fan_init,
- .exit = fan_exit,
- .experimental = 1,
- },
-};
-
-static int dispatch_read(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- struct ibm_struct *ibm = data;
- int len;
-
- if (!ibm || !ibm->read)
- return -EINVAL;
-
- len = ibm->read(page);
- if (len < 0)
- return len;
-
- if (len <= off + count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
-
- return len;
-}
-
-static int dispatch_write(struct file *file, const char __user * userbuf,
- unsigned long count, void *data)
-{
- struct ibm_struct *ibm = data;
- char *kernbuf;
- int ret;
-
- if (!ibm || !ibm->write)
- return -EINVAL;
-
- kernbuf = kmalloc(count + 2, GFP_KERNEL);
- if (!kernbuf)
- return -ENOMEM;
-
- if (copy_from_user(kernbuf, userbuf, count)) {
- kfree(kernbuf);
- return -EFAULT;
- }
-
- kernbuf[count] = 0;
- strcat(kernbuf, ",");
- ret = ibm->write(kernbuf);
- if (ret == 0)
- ret = count;
-
- kfree(kernbuf);
-
- return ret;
-}
-
-static void dispatch_notify(acpi_handle handle, u32 event, void *data)
-{
- struct ibm_struct *ibm = data;
-
- if (!ibm || !ibm->notify)
- return;
-
- ibm->notify(ibm, event);
-}
-
-static int __init setup_notify(struct ibm_struct *ibm)
-{
- acpi_status status;
- int ret;
-
- if (!*ibm->handle)
- return 0;
-
- ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
- if (ret < 0) {
- printk(IBM_ERR "%s device not present\n", ibm->name);
- return -ENODEV;
- }
-
- acpi_driver_data(ibm->device) = ibm;
- sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
-
- status = acpi_install_notify_handler(*ibm->handle, ibm->type,
- dispatch_notify, ibm);
- if (ACPI_FAILURE(status)) {
- if (status == AE_ALREADY_EXISTS) {
- printk(IBM_NOTICE "another device driver is already handling %s events\n",
- ibm->name);
- } else {
- printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
- ibm->name, status);
- }
- return -ENODEV;
- }
- ibm->notify_installed = 1;
- return 0;
-}
-
-static int __init ibm_device_add(struct acpi_device *device)
-{
- return 0;
-}
-
-static int __init register_driver(struct ibm_struct *ibm)
-{
- int ret;
-
- ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
- if (!ibm->driver) {
- printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
- return -1;
- }
-
- sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
- ibm->driver->ids = ibm->hid;
- ibm->driver->ops.add = &ibm_device_add;
-
- ret = acpi_bus_register_driver(ibm->driver);
- if (ret < 0) {
- printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
- ibm->hid, ret);
- kfree(ibm->driver);
- }
-
- return ret;
-}
-
-static void ibm_exit(struct ibm_struct *ibm);
-
-static int __init ibm_init(struct ibm_struct *ibm)
-{
- int ret;
- struct proc_dir_entry *entry;
-
- if (ibm->experimental && !experimental)
- return 0;
-
- if (ibm->hid) {
- ret = register_driver(ibm);
- if (ret < 0)
- return ret;
- ibm->driver_registered = 1;
- }
-
- if (ibm->init) {
- ret = ibm->init();
- if (ret != 0)
- return ret;
- ibm->init_called = 1;
- }
-
- if (ibm->read) {
- entry = create_proc_entry(ibm->name,
- S_IFREG | S_IRUGO | S_IWUSR,
- proc_dir);
- if (!entry) {
- printk(IBM_ERR "unable to create proc entry %s\n",
- ibm->name);
- return -ENODEV;
- }
- entry->owner = THIS_MODULE;
- entry->data = ibm;
- entry->read_proc = &dispatch_read;
- if (ibm->write)
- entry->write_proc = &dispatch_write;
- ibm->proc_created = 1;
- }
-
- if (ibm->notify) {
- ret = setup_notify(ibm);
- if (ret == -ENODEV) {
- printk(IBM_NOTICE "disabling subdriver %s\n",
- ibm->name);
- ibm_exit(ibm);
- return 0;
- }
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-static void ibm_exit(struct ibm_struct *ibm)
-{
- if (ibm->notify_installed)
- acpi_remove_notify_handler(*ibm->handle, ibm->type,
- dispatch_notify);
-
- if (ibm->proc_created)
- remove_proc_entry(ibm->name, proc_dir);
-
- if (ibm->init_called && ibm->exit)
- ibm->exit();
-
- if (ibm->driver_registered) {
- acpi_bus_unregister_driver(ibm->driver);
- kfree(ibm->driver);
- }
-}
-
-static void __init ibm_handle_init(char *name,
- acpi_handle * handle, acpi_handle parent,
- char **paths, int num_paths, char **path)
-{
- int i;
- acpi_status status;
-
- for (i = 0; i < num_paths; i++) {
- status = acpi_get_handle(parent, paths[i], handle);
- if (ACPI_SUCCESS(status)) {
- *path = paths[i];
- return;
- }
- }
-
- *handle = NULL;
-}
-
-#define IBM_HANDLE_INIT(object) \
- ibm_handle_init(#object, &object##_handle, *object##_parent, \
- object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
-
-static int __init set_ibm_param(const char *val, struct kernel_param *kp)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(ibms); i++)
- if (strcmp(ibms[i].name, kp->name) == 0 && ibms[i].write) {
- if (strlen(val) > sizeof(ibms[i].param) - 2)
- return -ENOSPC;
- strcpy(ibms[i].param, val);
- strcat(ibms[i].param, ",");
- return 0;
- }
-
- return -EINVAL;
-}
-
-#define IBM_PARAM(feature) \
- module_param_call(feature, set_ibm_param, NULL, NULL, 0)
-
-IBM_PARAM(hotkey);
-IBM_PARAM(bluetooth);
-IBM_PARAM(video);
-IBM_PARAM(light);
-#ifdef CONFIG_ACPI_IBM_DOCK
-IBM_PARAM(dock);
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
-IBM_PARAM(bay);
-#endif /* CONFIG_ACPI_IBM_BAY */
-IBM_PARAM(cmos);
-IBM_PARAM(led);
-IBM_PARAM(beep);
-IBM_PARAM(ecdump);
-IBM_PARAM(brightness);
-IBM_PARAM(volume);
-IBM_PARAM(fan);
-
-static void acpi_ibm_exit(void)
-{
- int i;
-
- for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
- ibm_exit(&ibms[i]);
-
- if (proc_dir)
- remove_proc_entry(IBM_DIR, acpi_root_dir);
-
- if (ibm_thinkpad_ec_found)
- kfree(ibm_thinkpad_ec_found);
-}
-
-static char* __init check_dmi_for_ec(void)
-{
- struct dmi_device *dev = NULL;
- char ec_fw_string[18];
-
- /*
- * ThinkPad T23 or newer, A31 or newer, R50e or newer,
- * X32 or newer, all Z series; Some models must have an
- * up-to-date BIOS or they will not be detected.
- *
- * See http://thinkwiki.org/wiki/List_of_DMI_IDs
- */
- while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
- if (sscanf(dev->name,
- "IBM ThinkPad Embedded Controller -[%17c",
- ec_fw_string) == 1) {
- ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
- ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
- return kstrdup(ec_fw_string, GFP_KERNEL);
- }
- }
- return NULL;
-}
-
-static int __init acpi_ibm_init(void)
-{
- int ret, i;
-
- if (acpi_disabled)
- return -ENODEV;
-
- /* ec is required because many other handles are relative to it */
- IBM_HANDLE_INIT(ec);
- if (!ec_handle) {
- printk(IBM_ERR "ec object not found\n");
- return -ENODEV;
- }
-
- /* Models with newer firmware report the EC in DMI */
- ibm_thinkpad_ec_found = check_dmi_for_ec();
-
- /* these handles are not required */
- IBM_HANDLE_INIT(vid);
- IBM_HANDLE_INIT(vid2);
- IBM_HANDLE_INIT(ledb);
- IBM_HANDLE_INIT(led);
- IBM_HANDLE_INIT(hkey);
- IBM_HANDLE_INIT(lght);
- IBM_HANDLE_INIT(cmos);
-#ifdef CONFIG_ACPI_IBM_DOCK
- IBM_HANDLE_INIT(dock);
-#endif
- IBM_HANDLE_INIT(pci);
-#ifdef CONFIG_ACPI_IBM_BAY
- IBM_HANDLE_INIT(bay);
- if (bay_handle)
- IBM_HANDLE_INIT(bay_ej);
- IBM_HANDLE_INIT(bay2);
- if (bay2_handle)
- IBM_HANDLE_INIT(bay2_ej);
-#endif /* CONFIG_ACPI_IBM_BAY */
- IBM_HANDLE_INIT(beep);
- IBM_HANDLE_INIT(ecrd);
- IBM_HANDLE_INIT(ecwr);
- IBM_HANDLE_INIT(fans);
- IBM_HANDLE_INIT(gfan);
- IBM_HANDLE_INIT(sfan);
-
- proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir);
- if (!proc_dir) {
- printk(IBM_ERR "unable to create proc dir %s", IBM_DIR);
- acpi_ibm_exit();
- return -ENODEV;
- }
- proc_dir->owner = THIS_MODULE;
-
- for (i = 0; i < ARRAY_SIZE(ibms); i++) {
- ret = ibm_init(&ibms[i]);
- if (ret >= 0 && *ibms[i].param)
- ret = ibms[i].write(ibms[i].param);
- if (ret < 0) {
- acpi_ibm_exit();
- return ret;
- }
- }
-
- return 0;
-}
-
-module_init(acpi_ibm_init);
-module_exit(acpi_ibm_exit);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 99d1516d1e70..f7de02a6f497 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -70,8 +70,6 @@
#define ACPI_PROCESSOR_LIMIT_USER 0
#define ACPI_PROCESSOR_LIMIT_THERMAL 1
-#define ACPI_STA_PRESENT 0x00000001
-
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_core");
@@ -779,7 +777,7 @@ static int is_processor_present(acpi_handle handle)
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
- if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
+ if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) {
ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
return 0;
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index cdf78943af4d..ae0654cd11ea 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -51,14 +51,6 @@
#include <asm/apic.h>
#endif
-/*
- * Include the apic definitions for x86 to have the APIC timer related defines
- * available also for UP (on SMP it gets magically included via linux/smp.h).
- */
-#ifdef CONFIG_X86
-#include <asm/apic.h>
-#endif
-
#include <asm/io.h>
#include <asm/uaccess.h>
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 59640d9a0acc..c1bae106833c 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -30,30 +30,10 @@
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <linux/acpi.h>
-#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
#include <linux/delay.h>
-#include "i2c_ec.h"
-
-#define DEF_CAPACITY_UNIT 3
-#define MAH_CAPACITY_UNIT 1
-#define MWH_CAPACITY_UNIT 2
-#define CAPACITY_UNIT DEF_CAPACITY_UNIT
-
-#define REQUEST_UPDATE_MODE 1
-#define QUEUE_UPDATE_MODE 2
-
-#define DATA_TYPE_COMMON 0
-#define DATA_TYPE_INFO 1
-#define DATA_TYPE_STATE 2
-#define DATA_TYPE_ALARM 3
-#define DATA_TYPE_AC_STATE 4
-
-extern struct proc_dir_entry *acpi_lock_ac_dir(void);
-extern struct proc_dir_entry *acpi_lock_battery_dir(void);
-extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
-extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
-
#define ACPI_SBS_COMPONENT 0x00080000
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
@@ -74,39 +54,75 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
#define _COMPONENT ACPI_SBS_COMPONENT
-#define MAX_SBS_BAT 4
-#define MAX_SMBUS_ERR 1
-
ACPI_MODULE_NAME("sbs");
MODULE_AUTHOR("Rich Townsend");
MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
MODULE_LICENSE("GPL");
-static struct semaphore sbs_sem;
+#define xmsleep(t) msleep(t)
+
+#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */
+
+#define ACPI_EC_SMB_STS 0x01 /* status */
+#define ACPI_EC_SMB_ADDR 0x02 /* address */
+#define ACPI_EC_SMB_CMD 0x03 /* command */
+#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */
+#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */
-#define UPDATE_MODE QUEUE_UPDATE_MODE
-/* REQUEST_UPDATE_MODE QUEUE_UPDATE_MODE */
-#define UPDATE_INFO_MODE 0
-#define UPDATE_TIME 60
-#define UPDATE_TIME2 0
+#define ACPI_EC_SMB_STS_DONE 0x80
+#define ACPI_EC_SMB_STS_STATUS 0x1f
-static int capacity_mode = CAPACITY_UNIT;
-static int update_mode = UPDATE_MODE;
-static int update_info_mode = UPDATE_INFO_MODE;
-static int update_time = UPDATE_TIME;
-static int update_time2 = UPDATE_TIME2;
+#define ACPI_EC_SMB_PRTCL_WRITE 0x00
+#define ACPI_EC_SMB_PRTCL_READ 0x01
+#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08
+#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a
-module_param(capacity_mode, int, 0);
-module_param(update_mode, int, 0);
-module_param(update_info_mode, int, 0);
-module_param(update_time, int, 0);
-module_param(update_time2, int, 0);
+#define ACPI_EC_SMB_TRANSACTION_SLEEP 1
+#define ACPI_EC_SMB_ACCESS_SLEEP1 1
+#define ACPI_EC_SMB_ACCESS_SLEEP2 10
+
+#define DEF_CAPACITY_UNIT 3
+#define MAH_CAPACITY_UNIT 1
+#define MWH_CAPACITY_UNIT 2
+#define CAPACITY_UNIT DEF_CAPACITY_UNIT
+
+#define REQUEST_UPDATE_MODE 1
+#define QUEUE_UPDATE_MODE 2
+
+#define DATA_TYPE_COMMON 0
+#define DATA_TYPE_INFO 1
+#define DATA_TYPE_STATE 2
+#define DATA_TYPE_ALARM 3
+#define DATA_TYPE_AC_STATE 4
+
+extern struct proc_dir_entry *acpi_lock_ac_dir(void);
+extern struct proc_dir_entry *acpi_lock_battery_dir(void);
+extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
+extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
+
+#define MAX_SBS_BAT 4
+#define ACPI_SBS_BLOCK_MAX 32
+
+#define ACPI_SBS_SMBUS_READ 1
+#define ACPI_SBS_SMBUS_WRITE 2
+
+#define ACPI_SBS_WORD_DATA 1
+#define ACPI_SBS_BLOCK_DATA 2
+
+#define UPDATE_DELAY 10
+
+/* 0 - every time, > 0 - by update_time */
+static unsigned int update_time = 120;
+
+static unsigned int capacity_mode = CAPACITY_UNIT;
+
+module_param(update_time, uint, 0644);
+module_param(capacity_mode, uint, 0444);
static int acpi_sbs_add(struct acpi_device *device);
static int acpi_sbs_remove(struct acpi_device *device, int type);
-static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus);
-static void acpi_sbs_update_queue(void *data);
+static int acpi_sbs_resume(struct acpi_device *device);
static struct acpi_driver acpi_sbs_driver = {
.name = "sbs",
@@ -115,9 +131,14 @@ static struct acpi_driver acpi_sbs_driver = {
.ops = {
.add = acpi_sbs_add,
.remove = acpi_sbs_remove,
+ .resume = acpi_sbs_resume,
},
};
+struct acpi_ac {
+ int ac_present;
+};
+
struct acpi_battery_info {
int capacity_mode;
s16 full_charge_capacity;
@@ -126,18 +147,16 @@ struct acpi_battery_info {
int vscale;
int ipscale;
s16 serial_number;
- char manufacturer_name[I2C_SMBUS_BLOCK_MAX + 3];
- char device_name[I2C_SMBUS_BLOCK_MAX + 3];
- char device_chemistry[I2C_SMBUS_BLOCK_MAX + 3];
+ char manufacturer_name[ACPI_SBS_BLOCK_MAX + 3];
+ char device_name[ACPI_SBS_BLOCK_MAX + 3];
+ char device_chemistry[ACPI_SBS_BLOCK_MAX + 3];
};
struct acpi_battery_state {
s16 voltage;
s16 amperage;
s16 remaining_capacity;
- s16 average_time_to_empty;
- s16 average_time_to_full;
- s16 battery_status;
+ s16 battery_state;
};
struct acpi_battery_alarm {
@@ -146,9 +165,9 @@ struct acpi_battery_alarm {
struct acpi_battery {
int alive;
- int battery_present;
int id;
int init_state;
+ int battery_present;
struct acpi_sbs *sbs;
struct acpi_battery_info info;
struct acpi_battery_state state;
@@ -158,186 +177,251 @@ struct acpi_battery {
struct acpi_sbs {
acpi_handle handle;
+ int base;
struct acpi_device *device;
struct acpi_ec_smbus *smbus;
+ struct mutex mutex;
int sbsm_present;
int sbsm_batteries_supported;
- int ac_present;
struct proc_dir_entry *ac_entry;
+ struct acpi_ac ac;
struct acpi_battery battery[MAX_SBS_BAT];
- int update_info_mode;
int zombie;
- int update_time;
- int update_time2;
struct timer_list update_timer;
+ int run_cnt;
+ int update_proc_flg;
};
-static void acpi_update_delay(struct acpi_sbs *sbs);
-static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type);
+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type);
+static void acpi_sbs_update_time(void *data);
+
+union sbs_rw_data {
+ u16 word;
+ u8 block[ACPI_SBS_BLOCK_MAX + 2];
+};
+
+static int acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
+ char read_write, u8 command, int size,
+ union sbs_rw_data *data);
/* --------------------------------------------------------------------------
SMBus Communication
-------------------------------------------------------------------------- */
-static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus)
+static int acpi_ec_sbs_read(struct acpi_sbs *sbs, u8 address, u8 * data)
{
- union i2c_smbus_data data;
- int result = 0;
- char *err_str;
- int err_number;
+ u8 val;
+ int err;
- data.word = 0;
+ err = ec_read(sbs->base + address, &val);
+ if (!err) {
+ *data = val;
+ }
+ xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
+ return (err);
+}
- result = smbus->adapter.algo->
- smbus_xfer(&smbus->adapter,
- ACPI_SB_SMBUS_ADDR,
- 0, I2C_SMBUS_READ, 0x16, I2C_SMBUS_BLOCK_DATA, &data);
+static int acpi_ec_sbs_write(struct acpi_sbs *sbs, u8 address, u8 data)
+{
+ int err;
- err_number = (data.word & 0x000f);
+ err = ec_write(sbs->base + address, data);
+ return (err);
+}
- switch (data.word & 0x000f) {
- case 0x0000:
- err_str = "unexpected bus error";
- break;
- case 0x0001:
- err_str = "busy";
- break;
- case 0x0002:
- err_str = "reserved command";
- break;
- case 0x0003:
- err_str = "unsupported command";
- break;
- case 0x0004:
- err_str = "access denied";
+static int
+acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
+ char read_write, u8 command, int size,
+ union sbs_rw_data *data)
+{
+ unsigned char protocol, len = 0, temp[2] = { 0, 0 };
+ int i;
+
+ if (read_write == ACPI_SBS_SMBUS_READ) {
+ protocol = ACPI_EC_SMB_PRTCL_READ;
+ } else {
+ protocol = ACPI_EC_SMB_PRTCL_WRITE;
+ }
+
+ switch (size) {
+
+ case ACPI_SBS_WORD_DATA:
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
+ if (read_write == ACPI_SBS_SMBUS_WRITE) {
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA, data->word);
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + 1,
+ data->word >> 8);
+ }
+ protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA;
break;
- case 0x0005:
- err_str = "overflow/underflow";
+ case ACPI_SBS_BLOCK_DATA:
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
+ if (read_write == ACPI_SBS_SMBUS_WRITE) {
+ len = min_t(u8, data->block[0], 32);
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_BCNT, len);
+ for (i = 0; i < len; i++)
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + i,
+ data->block[i + 1]);
+ }
+ protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA;
break;
- case 0x0006:
- err_str = "bad size";
+ default:
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "unsupported transaction %d", size));
+ return (-1);
+ }
+
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_ADDR, addr << 1);
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_PRTCL, protocol);
+
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+
+ if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+ xmsleep(ACPI_EC_SMB_ACCESS_SLEEP1);
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+ }
+ if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+ xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+ }
+ if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
+ || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "transaction %d error", size));
+ return (-1);
+ }
+
+ if (read_write == ACPI_SBS_SMBUS_WRITE) {
+ return (0);
+ }
+
+ switch (size) {
+
+ case ACPI_SBS_WORD_DATA:
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA, temp);
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + 1, temp + 1);
+ data->word = (temp[1] << 8) | temp[0];
break;
- case 0x0007:
- err_str = "unknown error";
+
+ case ACPI_SBS_BLOCK_DATA:
+ len = 0;
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_BCNT, &len);
+ len = min_t(u8, len, 32);
+ for (i = 0; i < len; i++)
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + i,
+ data->block + i + 1);
+ data->block[0] = len;
break;
default:
- err_str = "unrecognized error";
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "unsupported transaction %d", size));
+ return (-1);
}
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "%s: ret %i, err %i\n", err_str, result, err_number));
+
+ return (0);
}
static int
-acpi_sbs_smbus_read_word(struct acpi_ec_smbus *smbus, int addr, int func,
- u16 * word,
- void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_read_word(struct acpi_sbs *sbs, int addr, int func, u16 * word)
{
- union i2c_smbus_data data;
+ union sbs_rw_data data;
int result = 0;
- int i;
- if (err_handler == NULL) {
- err_handler = acpi_battery_smbus_err_handler;
- }
-
- for (i = 0; i < MAX_SMBUS_ERR; i++) {
- result =
- smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
- I2C_SMBUS_READ, func,
- I2C_SMBUS_WORD_DATA, &data);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
- i));
- if (err_handler) {
- err_handler(smbus);
- }
- } else {
- *word = data.word;
- break;
- }
+ result = acpi_ec_sbs_access(sbs, addr,
+ ACPI_SBS_SMBUS_READ, func,
+ ACPI_SBS_WORD_DATA, &data);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_ec_sbs_access() failed"));
+ } else {
+ *word = data.word;
}
return result;
}
static int
-acpi_sbs_smbus_read_str(struct acpi_ec_smbus *smbus, int addr, int func,
- char *str,
- void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_read_str(struct acpi_sbs *sbs, int addr, int func, char *str)
{
- union i2c_smbus_data data;
+ union sbs_rw_data data;
int result = 0;
- int i;
-
- if (err_handler == NULL) {
- err_handler = acpi_battery_smbus_err_handler;
- }
- for (i = 0; i < MAX_SMBUS_ERR; i++) {
- result =
- smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
- I2C_SMBUS_READ, func,
- I2C_SMBUS_BLOCK_DATA,
- &data);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
- i));
- if (err_handler) {
- err_handler(smbus);
- }
- } else {
- strncpy(str, (const char *)data.block + 1,
- data.block[0]);
- str[data.block[0]] = 0;
- break;
- }
+ result = acpi_ec_sbs_access(sbs, addr,
+ ACPI_SBS_SMBUS_READ, func,
+ ACPI_SBS_BLOCK_DATA, &data);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_ec_sbs_access() failed"));
+ } else {
+ strncpy(str, (const char *)data.block + 1, data.block[0]);
+ str[data.block[0]] = 0;
}
return result;
}
static int
-acpi_sbs_smbus_write_word(struct acpi_ec_smbus *smbus, int addr, int func,
- int word,
- void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_write_word(struct acpi_sbs *sbs, int addr, int func, int word)
{
- union i2c_smbus_data data;
+ union sbs_rw_data data;
int result = 0;
- int i;
-
- if (err_handler == NULL) {
- err_handler = acpi_battery_smbus_err_handler;
- }
data.word = word;
- for (i = 0; i < MAX_SMBUS_ERR; i++) {
- result =
- smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
- I2C_SMBUS_WRITE, func,
- I2C_SMBUS_WORD_DATA, &data);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "try %i: smbus->adapter.algo"
- "->smbus_xfer() failed\n", i));
- if (err_handler) {
- err_handler(smbus);
- }
- } else {
- break;
- }
+ result = acpi_ec_sbs_access(sbs, addr,
+ ACPI_SBS_SMBUS_WRITE, func,
+ ACPI_SBS_WORD_DATA, &data);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_ec_sbs_access() failed"));
}
return result;
}
+static int sbs_zombie(struct acpi_sbs *sbs)
+{
+ return (sbs->zombie);
+}
+
+static int sbs_mutex_lock(struct acpi_sbs *sbs)
+{
+ if (sbs_zombie(sbs)) {
+ return -ENODEV;
+ }
+ mutex_lock(&sbs->mutex);
+ return 0;
+}
+
+static void sbs_mutex_unlock(struct acpi_sbs *sbs)
+{
+ mutex_unlock(&sbs->mutex);
+}
+
/* --------------------------------------------------------------------------
Smart Battery System Management
-------------------------------------------------------------------------- */
-/* Smart Battery */
+static int acpi_check_update_proc(struct acpi_sbs *sbs)
+{
+ acpi_status status = AE_OK;
+
+ if (update_time == 0) {
+ sbs->update_proc_flg = 0;
+ return 0;
+ }
+ if (sbs->update_proc_flg == 0) {
+ status = acpi_os_execute(OSL_GPE_HANDLER,
+ acpi_sbs_update_time, sbs);
+ if (status != AE_OK) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "acpi_os_execute() failed"));
+ return 1;
+ }
+ sbs->update_proc_flg = 1;
+ }
+ return 0;
+}
static int acpi_sbs_generate_event(struct acpi_device *device,
int event, int state, char *bid, char *class)
@@ -366,12 +450,11 @@ static int acpi_battery_get_present(struct acpi_battery *battery)
int result = 0;
int is_present = 0;
- result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
- ACPI_SBSM_SMBUS_ADDR, 0x01,
- &state, NULL);
+ result = acpi_sbs_read_word(battery->sbs,
+ ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
}
if (!result) {
is_present = (state & 0x000f) & (1 << battery->id);
@@ -381,45 +464,33 @@ static int acpi_battery_get_present(struct acpi_battery *battery)
return result;
}
-static int acpi_battery_is_present(struct acpi_battery *battery)
-{
- return (battery->battery_present);
-}
-
-static int acpi_ac_is_present(struct acpi_sbs *sbs)
-{
- return (sbs->ac_present);
-}
-
static int acpi_battery_select(struct acpi_battery *battery)
{
- struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
s16 state;
int foo;
- if (battery->sbs->sbsm_present) {
+ if (sbs->sbsm_present) {
/* Take special care not to knobble other nibbles of
* state (aka selector_state), since
* it causes charging to halt on SBSELs */
result =
- acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
- &state, NULL);
+ acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
foo = (state & 0x0fff) | (1 << (battery->id + 12));
result =
- acpi_sbs_smbus_write_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
- foo, NULL);
+ acpi_sbs_write_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, foo);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_write_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_write_word() failed"));
goto end;
}
}
@@ -430,15 +501,14 @@ static int acpi_battery_select(struct acpi_battery *battery)
static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
{
- struct acpi_ec_smbus *smbus = sbs->smbus;
int result = 0;
s16 battery_system_info;
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x04,
- &battery_system_info, NULL);
+ result = acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x04,
+ &battery_system_info);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
@@ -451,53 +521,50 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
static int acpi_battery_get_info(struct acpi_battery *battery)
{
- struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
s16 battery_mode;
s16 specification_info;
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
- &battery_mode,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
+ &battery_mode);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
battery->info.capacity_mode = (battery_mode & 0x8000) >> 15;
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x10,
- &battery->info.full_charge_capacity,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x10,
+ &battery->info.full_charge_capacity);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x18,
- &battery->info.design_capacity,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x18,
+ &battery->info.design_capacity);
if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x19,
- &battery->info.design_voltage,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x19,
+ &battery->info.design_voltage);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1a,
- &specification_info,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1a,
+ &specification_info);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
@@ -529,37 +596,35 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
battery->info.ipscale = 1;
}
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1c,
- &battery->info.serial_number,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1c,
+ &battery->info.serial_number);
if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x20,
- battery->info.manufacturer_name,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x20,
+ battery->info.manufacturer_name);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_str() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_str() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x21,
- battery->info.device_name,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x21,
+ battery->info.device_name);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_str() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_str() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x22,
- battery->info.device_chemistry,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x22,
+ battery->info.device_chemistry);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_str() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_str() failed"));
goto end;
}
@@ -567,103 +632,60 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
return result;
}
-static void acpi_update_delay(struct acpi_sbs *sbs)
-{
- if (sbs->zombie) {
- return;
- }
- if (sbs->update_time2 > 0) {
- msleep(sbs->update_time2 * 1000);
- }
-}
-
static int acpi_battery_get_state(struct acpi_battery *battery)
{
- struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x09,
- &battery->state.voltage,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x09,
+ &battery->state.voltage);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0a,
- &battery->state.amperage,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0a,
+ &battery->state.amperage);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0f,
- &battery->state.remaining_capacity,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0f,
+ &battery->state.remaining_capacity);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x12,
- &battery->state.average_time_to_empty,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x16,
+ &battery->state.battery_state);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x13,
- &battery->state.average_time_to_full,
- &acpi_battery_smbus_err_handler);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
- goto end;
- }
-
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x16,
- &battery->state.battery_status,
- &acpi_battery_smbus_err_handler);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
- goto end;
- }
-
- acpi_update_delay(battery->sbs);
-
end:
return result;
}
static int acpi_battery_get_alarm(struct acpi_battery *battery)
{
- struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
- &battery->alarm.remaining_capacity,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
+ &battery->alarm.remaining_capacity);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- acpi_update_delay(battery->sbs);
-
end:
return result;
@@ -672,15 +694,15 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery)
static int acpi_battery_set_alarm(struct acpi_battery *battery,
unsigned long alarm)
{
- struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
s16 battery_mode;
int foo;
result = acpi_battery_select(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_select() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_select() failed"));
goto end;
}
@@ -688,33 +710,29 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,
if (alarm > 0) {
result =
- acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
- &battery_mode,
- &acpi_battery_smbus_err_handler);
+ acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
+ &battery_mode);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
result =
- acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
- battery_mode & 0xbfff,
- &acpi_battery_smbus_err_handler);
+ acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
+ battery_mode & 0xbfff);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_write_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_write_word() failed"));
goto end;
}
}
foo = alarm / (battery->info.capacity_mode ? 10 : 1);
- result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
- foo,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, foo);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_write_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_write_word() failed"));
goto end;
}
@@ -725,6 +743,7 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,
static int acpi_battery_set_mode(struct acpi_battery *battery)
{
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
s16 battery_mode;
@@ -732,12 +751,11 @@ static int acpi_battery_set_mode(struct acpi_battery *battery)
goto end;
}
- result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
- ACPI_SB_SMBUS_ADDR, 0x03,
- &battery_mode, NULL);
+ result = acpi_sbs_read_word(sbs,
+ ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
@@ -746,21 +764,19 @@ static int acpi_battery_set_mode(struct acpi_battery *battery)
} else {
battery_mode |= 0x8000;
}
- result = acpi_sbs_smbus_write_word(battery->sbs->smbus,
- ACPI_SB_SMBUS_ADDR, 0x03,
- battery_mode, NULL);
+ result = acpi_sbs_write_word(sbs,
+ ACPI_SB_SMBUS_ADDR, 0x03, battery_mode);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_write_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_write_word() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
- ACPI_SB_SMBUS_ADDR, 0x03,
- &battery_mode, NULL);
+ result = acpi_sbs_read_word(sbs,
+ ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
@@ -774,36 +790,36 @@ static int acpi_battery_init(struct acpi_battery *battery)
result = acpi_battery_select(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_init() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_select() failed"));
goto end;
}
result = acpi_battery_set_mode(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_set_mode() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_set_mode() failed"));
goto end;
}
result = acpi_battery_get_info(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_info() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_info() failed"));
goto end;
}
result = acpi_battery_get_state(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_state() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_state() failed"));
goto end;
}
result = acpi_battery_get_alarm(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_alarm() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_alarm() failed"));
goto end;
}
@@ -813,20 +829,19 @@ static int acpi_battery_init(struct acpi_battery *battery)
static int acpi_ac_get_present(struct acpi_sbs *sbs)
{
- struct acpi_ec_smbus *smbus = sbs->smbus;
int result = 0;
s16 charger_status;
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x13,
- &charger_status, NULL);
+ result = acpi_sbs_read_word(sbs, ACPI_SBC_SMBUS_ADDR, 0x13,
+ &charger_status);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- sbs->ac_present = (charger_status & 0x8000) >> 15;
+ sbs->ac.ac_present = (charger_status & 0x8000) >> 15;
end:
@@ -852,8 +867,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
if (!*dir) {
*dir = proc_mkdir(dir_name, parent_dir);
if (!*dir) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "proc_mkdir() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "proc_mkdir() failed"));
return -ENODEV;
}
(*dir)->owner = THIS_MODULE;
@@ -863,8 +878,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
if (info_fops) {
entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
if (!entry) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "create_proc_entry() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "create_proc_entry() failed"));
} else {
entry->proc_fops = info_fops;
entry->data = data;
@@ -876,8 +891,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
if (state_fops) {
entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
if (!entry) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "create_proc_entry() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "create_proc_entry() failed"));
} else {
entry->proc_fops = state_fops;
entry->data = data;
@@ -889,8 +904,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
if (alarm_fops) {
entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
if (!entry) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "create_proc_entry() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "create_proc_entry() failed"));
} else {
entry->proc_fops = alarm_fops;
entry->data = data;
@@ -923,24 +938,27 @@ static struct proc_dir_entry *acpi_battery_dir = NULL;
static int acpi_battery_read_info(struct seq_file *seq, void *offset)
{
struct acpi_battery *battery = seq->private;
+ struct acpi_sbs *sbs = battery->sbs;
int cscale;
int result = 0;
- if (battery->sbs->zombie) {
+ if (sbs_mutex_lock(sbs)) {
return -ENODEV;
}
- down(&sbs_sem);
+ result = acpi_check_update_proc(sbs);
+ if (result)
+ goto end;
- if (update_mode == REQUEST_UPDATE_MODE) {
- result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_INFO);
+ if (update_time == 0) {
+ result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_INFO);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_update_run() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_update_run() failed"));
}
}
- if (acpi_battery_is_present(battery)) {
+ if (battery->battery_present) {
seq_printf(seq, "present: yes\n");
} else {
seq_printf(seq, "present: no\n");
@@ -952,13 +970,13 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
} else {
cscale = battery->info.ipscale;
}
- seq_printf(seq, "design capacity: %i%s",
+ seq_printf(seq, "design capacity: %i%s\n",
battery->info.design_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+ battery->info.capacity_mode ? "0 mWh" : " mAh");
- seq_printf(seq, "last full capacity: %i%s",
+ seq_printf(seq, "last full capacity: %i%s\n",
battery->info.full_charge_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+ battery->info.capacity_mode ? "0 mWh" : " mAh");
seq_printf(seq, "battery technology: rechargeable\n");
@@ -984,7 +1002,7 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
end:
- up(&sbs_sem);
+ sbs_mutex_unlock(sbs);
return result;
}
@@ -996,26 +1014,29 @@ static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
static int acpi_battery_read_state(struct seq_file *seq, void *offset)
{
- struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ struct acpi_battery *battery = seq->private;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
int cscale;
int foo;
- if (battery->sbs->zombie) {
+ if (sbs_mutex_lock(sbs)) {
return -ENODEV;
}
- down(&sbs_sem);
+ result = acpi_check_update_proc(sbs);
+ if (result)
+ goto end;
- if (update_mode == REQUEST_UPDATE_MODE) {
- result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_STATE);
+ if (update_time == 0) {
+ result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_STATE);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_update_run() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_update_run() failed"));
}
}
- if (acpi_battery_is_present(battery)) {
+ if (battery->battery_present) {
seq_printf(seq, "present: yes\n");
} else {
seq_printf(seq, "present: no\n");
@@ -1028,7 +1049,7 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
cscale = battery->info.ipscale;
}
- if (battery->state.battery_status & 0x0010) {
+ if (battery->state.battery_state & 0x0010) {
seq_printf(seq, "capacity state: critical\n");
} else {
seq_printf(seq, "capacity state: ok\n");
@@ -1052,16 +1073,16 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
battery->info.capacity_mode ? "mW" : "mA");
}
- seq_printf(seq, "remaining capacity: %i%s",
+ seq_printf(seq, "remaining capacity: %i%s\n",
battery->state.remaining_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+ battery->info.capacity_mode ? "0 mWh" : " mAh");
seq_printf(seq, "present voltage: %i mV\n",
battery->state.voltage * battery->info.vscale);
end:
- up(&sbs_sem);
+ sbs_mutex_unlock(sbs);
return result;
}
@@ -1074,24 +1095,27 @@ static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
{
struct acpi_battery *battery = seq->private;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
int cscale;
- if (battery->sbs->zombie) {
+ if (sbs_mutex_lock(sbs)) {
return -ENODEV;
}
- down(&sbs_sem);
+ result = acpi_check_update_proc(sbs);
+ if (result)
+ goto end;
- if (update_mode == REQUEST_UPDATE_MODE) {
- result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_ALARM);
+ if (update_time == 0) {
+ result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_ALARM);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_update_run() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_update_run() failed"));
}
}
- if (!acpi_battery_is_present(battery)) {
+ if (!battery->battery_present) {
seq_printf(seq, "present: no\n");
goto end;
}
@@ -1104,16 +1128,16 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
seq_printf(seq, "alarm: ");
if (battery->alarm.remaining_capacity) {
- seq_printf(seq, "%i%s",
+ seq_printf(seq, "%i%s\n",
battery->alarm.remaining_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+ battery->info.capacity_mode ? "0 mWh" : " mAh");
} else {
seq_printf(seq, "disabled\n");
}
end:
- up(&sbs_sem);
+ sbs_mutex_unlock(sbs);
return result;
}
@@ -1124,16 +1148,19 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer,
{
struct seq_file *seq = file->private_data;
struct acpi_battery *battery = seq->private;
+ struct acpi_sbs *sbs = battery->sbs;
char alarm_string[12] = { '\0' };
int result, old_alarm, new_alarm;
- if (battery->sbs->zombie) {
+ if (sbs_mutex_lock(sbs)) {
return -ENODEV;
}
- down(&sbs_sem);
+ result = acpi_check_update_proc(sbs);
+ if (result)
+ goto end;
- if (!acpi_battery_is_present(battery)) {
+ if (!battery->battery_present) {
result = -ENODEV;
goto end;
}
@@ -1155,21 +1182,21 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer,
result = acpi_battery_set_alarm(battery, new_alarm);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_set_alarm() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_set_alarm() failed"));
acpi_battery_set_alarm(battery, old_alarm);
goto end;
}
result = acpi_battery_get_alarm(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_alarm() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_alarm() failed"));
acpi_battery_set_alarm(battery, old_alarm);
goto end;
}
end:
- up(&sbs_sem);
+ sbs_mutex_unlock(sbs);
if (result) {
return result;
@@ -1217,24 +1244,22 @@ static int acpi_ac_read_state(struct seq_file *seq, void *offset)
struct acpi_sbs *sbs = seq->private;
int result;
- if (sbs->zombie) {
+ if (sbs_mutex_lock(sbs)) {
return -ENODEV;
}
- down(&sbs_sem);
-
- if (update_mode == REQUEST_UPDATE_MODE) {
- result = acpi_sbs_update_run(sbs, DATA_TYPE_AC_STATE);
+ if (update_time == 0) {
+ result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_AC_STATE);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_update_run() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_update_run() failed"));
}
}
seq_printf(seq, "state: %s\n",
- sbs->ac_present ? "on-line" : "off-line");
+ sbs->ac.ac_present ? "on-line" : "off-line");
- up(&sbs_sem);
+ sbs_mutex_unlock(sbs);
return 0;
}
@@ -1275,25 +1300,25 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
result = acpi_battery_select(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_select() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_select() failed"));
goto end;
}
result = acpi_battery_get_present(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_present() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_present() failed"));
goto end;
}
- is_present = acpi_battery_is_present(battery);
+ is_present = battery->battery_present;
if (is_present) {
result = acpi_battery_init(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_init() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_init() failed"));
goto end;
}
battery->init_state = 1;
@@ -1308,12 +1333,16 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
&acpi_battery_state_fops,
&acpi_battery_alarm_fops, battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_generic_add_fs() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_generic_add_fs() failed"));
goto end;
}
battery->alive = 1;
+ printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
+ ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), dir_name,
+ sbs->battery->battery_present ? "present" : "absent");
+
end:
return result;
}
@@ -1333,8 +1362,8 @@ static int acpi_ac_add(struct acpi_sbs *sbs)
result = acpi_ac_get_present(sbs);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_ac_get_present() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_ac_get_present() failed"));
goto end;
}
@@ -1343,11 +1372,15 @@ static int acpi_ac_add(struct acpi_sbs *sbs)
ACPI_AC_DIR_NAME,
NULL, &acpi_ac_state_fops, NULL, sbs);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_generic_add_fs() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_generic_add_fs() failed"));
goto end;
}
+ printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
+ ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
+ ACPI_AC_DIR_NAME, sbs->ac.ac_present ? "on-line" : "off-line");
+
end:
return result;
@@ -1361,45 +1394,85 @@ static void acpi_ac_remove(struct acpi_sbs *sbs)
}
}
-static void acpi_sbs_update_queue_run(unsigned long data)
+static void acpi_sbs_update_time_run(unsigned long data)
{
- acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_queue, (void *)data);
+ acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_time, (void *)data);
}
-static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type)
{
struct acpi_battery *battery;
- int result = 0;
- int old_ac_present;
- int old_battery_present;
- int new_ac_present;
- int new_battery_present;
- int id;
+ int result = 0, cnt;
+ int old_ac_present = -1;
+ int old_battery_present = -1;
+ int new_ac_present = -1;
+ int new_battery_present = -1;
+ int id_min = 0, id_max = MAX_SBS_BAT - 1;
char dir_name[32];
- int do_battery_init, do_ac_init;
- s16 old_remaining_capacity;
+ int do_battery_init = 0, do_ac_init = 0;
+ int old_remaining_capacity = 0;
+ int update_ac = 1, update_battery = 1;
+ int up_tm = update_time;
- if (sbs->zombie) {
+ if (sbs_zombie(sbs)) {
goto end;
}
- old_ac_present = acpi_ac_is_present(sbs);
+ if (id >= 0) {
+ id_min = id_max = id;
+ }
+
+ if (data_type == DATA_TYPE_COMMON && up_tm > 0) {
+ cnt = up_tm / (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm);
+ if (sbs->run_cnt % cnt != 0) {
+ update_battery = 0;
+ }
+ }
+
+ sbs->run_cnt++;
+
+ if (!update_ac && !update_battery) {
+ goto end;
+ }
+
+ old_ac_present = sbs->ac.ac_present;
result = acpi_ac_get_present(sbs);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_ac_get_present() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_ac_get_present() failed"));
}
- new_ac_present = acpi_ac_is_present(sbs);
+ new_ac_present = sbs->ac.ac_present;
do_ac_init = (old_ac_present != new_ac_present);
+ if (sbs->run_cnt == 1 && data_type == DATA_TYPE_COMMON) {
+ do_ac_init = 1;
+ }
- if (data_type == DATA_TYPE_AC_STATE) {
+ if (do_ac_init) {
+ result = acpi_sbs_generate_event(sbs->device,
+ ACPI_SBS_AC_NOTIFY_STATUS,
+ new_ac_present,
+ ACPI_AC_DIR_NAME,
+ ACPI_AC_CLASS);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_generate_event() failed"));
+ }
+ }
+
+ if (data_type == DATA_TYPE_COMMON) {
+ if (!do_ac_init && !update_battery) {
+ goto end;
+ }
+ }
+
+ if (data_type == DATA_TYPE_AC_STATE && !do_ac_init) {
goto end;
}
- for (id = 0; id < MAX_SBS_BAT; id++) {
+ for (id = id_min; id <= id_max; id++) {
battery = &sbs->battery[id];
if (battery->alive == 0) {
continue;
@@ -1407,94 +1480,92 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
old_remaining_capacity = battery->state.remaining_capacity;
- old_battery_present = acpi_battery_is_present(battery);
+ old_battery_present = battery->battery_present;
result = acpi_battery_select(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_select() failed\n"));
- }
- if (sbs->zombie) {
- goto end;
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_select() failed"));
}
result = acpi_battery_get_present(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_present() failed\n"));
- }
- if (sbs->zombie) {
- goto end;
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_present() failed"));
}
- new_battery_present = acpi_battery_is_present(battery);
+ new_battery_present = battery->battery_present;
do_battery_init = ((old_battery_present != new_battery_present)
&& new_battery_present);
-
- if (sbs->zombie) {
+ if (!new_battery_present)
+ goto event;
+ if (do_ac_init || do_battery_init) {
+ result = acpi_battery_init(battery);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_init() "
+ "failed"));
+ }
+ }
+ if (sbs_zombie(sbs)) {
goto end;
}
- if (do_ac_init || do_battery_init ||
- update_info_mode || sbs->update_info_mode) {
- if (sbs->update_info_mode) {
- sbs->update_info_mode = 0;
- } else {
- sbs->update_info_mode = 1;
- }
- result = acpi_battery_init(battery);
+
+ if ((data_type == DATA_TYPE_COMMON
+ || data_type == DATA_TYPE_INFO)
+ && new_battery_present) {
+ result = acpi_battery_get_info(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_init() "
- "failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_info() failed"));
}
}
if (data_type == DATA_TYPE_INFO) {
continue;
}
-
- if (sbs->zombie) {
+ if (sbs_zombie(sbs)) {
goto end;
}
- if (new_battery_present) {
- result = acpi_battery_get_alarm(battery);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_alarm() "
- "failed\n"));
- }
- if (data_type == DATA_TYPE_ALARM) {
- continue;
- }
+ if ((data_type == DATA_TYPE_COMMON
+ || data_type == DATA_TYPE_STATE)
+ && new_battery_present) {
result = acpi_battery_get_state(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_state() "
- "failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_state() failed"));
}
}
- if (sbs->zombie) {
- goto end;
+ if (data_type == DATA_TYPE_STATE) {
+ goto event;
}
- if (data_type != DATA_TYPE_COMMON) {
- continue;
+ if (sbs_zombie(sbs)) {
+ goto end;
}
- if (old_battery_present != new_battery_present) {
- sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
- result = acpi_sbs_generate_event(sbs->device,
- ACPI_SBS_BATTERY_NOTIFY_STATUS,
- new_battery_present,
- dir_name,
- ACPI_BATTERY_CLASS);
+ if ((data_type == DATA_TYPE_COMMON
+ || data_type == DATA_TYPE_ALARM)
+ && new_battery_present) {
+ result = acpi_battery_get_alarm(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_generate_event() "
- "failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_alarm() "
+ "failed"));
}
}
- if (old_remaining_capacity != battery->state.remaining_capacity) {
+ if (data_type == DATA_TYPE_ALARM) {
+ continue;
+ }
+ if (sbs_zombie(sbs)) {
+ goto end;
+ }
+
+ event:
+
+ if (old_battery_present != new_battery_present || do_ac_init ||
+ old_remaining_capacity !=
+ battery->state.remaining_capacity) {
sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
result = acpi_sbs_generate_event(sbs->device,
ACPI_SBS_BATTERY_NOTIFY_STATUS,
@@ -1502,138 +1573,120 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
dir_name,
ACPI_BATTERY_CLASS);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_generate_event() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_generate_event() "
+ "failed"));
}
}
-
- }
- if (sbs->zombie) {
- goto end;
- }
- if (data_type != DATA_TYPE_COMMON) {
- goto end;
- }
-
- if (old_ac_present != new_ac_present) {
- result = acpi_sbs_generate_event(sbs->device,
- ACPI_SBS_AC_NOTIFY_STATUS,
- new_ac_present,
- ACPI_AC_DIR_NAME,
- ACPI_AC_CLASS);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_generate_event() failed\n"));
- }
}
end:
+
return result;
}
-static void acpi_sbs_update_queue(void *data)
+static void acpi_sbs_update_time(void *data)
{
struct acpi_sbs *sbs = data;
unsigned long delay = -1;
int result;
+ unsigned int up_tm = update_time;
- if (sbs->zombie) {
- goto end;
- }
+ if (sbs_mutex_lock(sbs))
+ return;
- result = acpi_sbs_update_run(sbs, DATA_TYPE_COMMON);
+ result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_COMMON);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_update_run() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_update_run() failed"));
}
- if (sbs->zombie) {
+ if (sbs_zombie(sbs)) {
goto end;
}
- if (update_mode == REQUEST_UPDATE_MODE) {
- goto end;
+ if (!up_tm) {
+ if (timer_pending(&sbs->update_timer))
+ del_timer(&sbs->update_timer);
+ } else {
+ delay = (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm);
+ delay = jiffies + HZ * delay;
+ if (timer_pending(&sbs->update_timer)) {
+ mod_timer(&sbs->update_timer, delay);
+ } else {
+ sbs->update_timer.data = (unsigned long)data;
+ sbs->update_timer.function = acpi_sbs_update_time_run;
+ sbs->update_timer.expires = delay;
+ add_timer(&sbs->update_timer);
+ }
}
- delay = jiffies + HZ * update_time;
- sbs->update_timer.data = (unsigned long)data;
- sbs->update_timer.function = acpi_sbs_update_queue_run;
- sbs->update_timer.expires = delay;
- add_timer(&sbs->update_timer);
end:
- ;
+
+ sbs_mutex_unlock(sbs);
}
static int acpi_sbs_add(struct acpi_device *device)
{
struct acpi_sbs *sbs = NULL;
- struct acpi_ec_hc *ec_hc = NULL;
- int result, remove_result = 0;
+ int result = 0, remove_result = 0;
unsigned long sbs_obj;
- int id, cnt;
+ int id;
acpi_status status = AE_OK;
+ unsigned long val;
+
+ status =
+ acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
+ return -EIO;
+ }
sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
if (!sbs) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));
- return -ENOMEM;
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "kzalloc() failed"));
+ result = -ENOMEM;
+ goto end;
}
- cnt = 0;
- while (cnt < 10) {
- cnt++;
- ec_hc = acpi_get_ec_hc(device);
- if (ec_hc) {
- break;
- }
- msleep(1000);
- }
+ mutex_init(&sbs->mutex);
- if (!ec_hc) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_get_ec_hc() failed: "
- "NO driver found for EC HC SMBus\n"));
- result = -ENODEV;
- goto end;
- }
+ sbs_mutex_lock(sbs);
+ sbs->base = (val & 0xff00ull) >> 8;
sbs->device = device;
- sbs->smbus = ec_hc->smbus;
strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
acpi_driver_data(device) = sbs;
- sbs->update_time = 0;
- sbs->update_time2 = 0;
-
result = acpi_ac_add(sbs);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_ac_add() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
goto end;
}
- result = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
- if (ACPI_FAILURE(result)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_evaluate_integer() failed\n"));
+ status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
+ if (status) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "acpi_evaluate_integer() failed"));
result = -EIO;
goto end;
}
-
if (sbs_obj > 0) {
result = acpi_sbsm_get_info(sbs);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbsm_get_info() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbsm_get_info() failed"));
goto end;
}
sbs->sbsm_present = 1;
}
+
if (sbs->sbsm_present == 0) {
result = acpi_battery_add(sbs, 0);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_add() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_add() failed"));
goto end;
}
} else {
@@ -1641,9 +1694,8 @@ static int acpi_sbs_add(struct acpi_device *device)
if ((sbs->sbsm_batteries_supported & (1 << id))) {
result = acpi_battery_add(sbs, id);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_add() "
- "failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_add() failed"));
goto end;
}
}
@@ -1653,33 +1705,26 @@ static int acpi_sbs_add(struct acpi_device *device)
sbs->handle = device->handle;
init_timer(&sbs->update_timer);
- if (update_mode == QUEUE_UPDATE_MODE) {
- status = acpi_os_execute(OSL_GPE_HANDLER,
- acpi_sbs_update_queue, sbs);
- if (status != AE_OK) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_os_execute() failed\n"));
- }
- }
- sbs->update_time = update_time;
- sbs->update_time2 = update_time2;
-
- printk(KERN_INFO PREFIX "%s [%s]\n",
- acpi_device_name(device), acpi_device_bid(device));
+ result = acpi_check_update_proc(sbs);
+ if (result)
+ goto end;
end:
+
+ sbs_mutex_unlock(sbs);
+
if (result) {
remove_result = acpi_sbs_remove(device, 0);
if (remove_result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_remove() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_remove() failed"));
}
}
return result;
}
-int acpi_sbs_remove(struct acpi_device *device, int type)
+static int acpi_sbs_remove(struct acpi_device *device, int type)
{
struct acpi_sbs *sbs;
int id;
@@ -1688,15 +1733,14 @@ int acpi_sbs_remove(struct acpi_device *device, int type)
return -EINVAL;
}
- sbs = (struct acpi_sbs *)acpi_driver_data(device);
-
+ sbs = acpi_driver_data(device);
if (!sbs) {
return -EINVAL;
}
+ sbs_mutex_lock(sbs);
+
sbs->zombie = 1;
- sbs->update_time = 0;
- sbs->update_time2 = 0;
del_timer_sync(&sbs->update_timer);
acpi_os_wait_events_complete(NULL);
del_timer_sync(&sbs->update_timer);
@@ -1707,11 +1751,41 @@ int acpi_sbs_remove(struct acpi_device *device, int type)
acpi_ac_remove(sbs);
+ sbs_mutex_unlock(sbs);
+
+ mutex_destroy(&sbs->mutex);
+
kfree(sbs);
return 0;
}
+static void acpi_sbs_rmdirs(void)
+{
+ if (acpi_ac_dir) {
+ acpi_unlock_ac_dir(acpi_ac_dir);
+ acpi_ac_dir = NULL;
+ }
+ if (acpi_battery_dir) {
+ acpi_unlock_battery_dir(acpi_battery_dir);
+ acpi_battery_dir = NULL;
+ }
+}
+
+static int acpi_sbs_resume(struct acpi_device *device)
+{
+ struct acpi_sbs *sbs;
+
+ if (!device)
+ return -EINVAL;
+
+ sbs = device->driver_data;
+
+ sbs->run_cnt = 0;
+
+ return 0;
+}
+
static int __init acpi_sbs_init(void)
{
int result = 0;
@@ -1719,35 +1793,34 @@ static int __init acpi_sbs_init(void)
if (acpi_disabled)
return -ENODEV;
- init_MUTEX(&sbs_sem);
-
if (capacity_mode != DEF_CAPACITY_UNIT
&& capacity_mode != MAH_CAPACITY_UNIT
&& capacity_mode != MWH_CAPACITY_UNIT) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_sbs_init: "
- "invalid capacity_mode = %d\n",
- capacity_mode));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "invalid capacity_mode = %d", capacity_mode));
return -EINVAL;
}
acpi_ac_dir = acpi_lock_ac_dir();
if (!acpi_ac_dir) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_lock_ac_dir() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_lock_ac_dir() failed"));
return -ENODEV;
}
acpi_battery_dir = acpi_lock_battery_dir();
if (!acpi_battery_dir) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_lock_battery_dir() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_lock_battery_dir() failed"));
+ acpi_sbs_rmdirs();
return -ENODEV;
}
result = acpi_bus_register_driver(&acpi_sbs_driver);
if (result < 0) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_bus_register_driver() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_bus_register_driver() failed"));
+ acpi_sbs_rmdirs();
return -ENODEV;
}
@@ -1756,13 +1829,9 @@ static int __init acpi_sbs_init(void)
static void __exit acpi_sbs_exit(void)
{
-
acpi_bus_unregister_driver(&acpi_sbs_driver);
- acpi_unlock_ac_dir(acpi_ac_dir);
- acpi_ac_dir = NULL;
- acpi_unlock_battery_dir(acpi_battery_dir);
- acpi_battery_dir = NULL;
+ acpi_sbs_rmdirs();
return;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index bb0e0da39fb1..d80dd84e5bfd 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1068,7 +1068,9 @@ acpi_add_single_object(struct acpi_device **child,
}
break;
default:
- STRUCT_TO_INT(device->status) = 0x0F;
+ STRUCT_TO_INT(device->status) =
+ ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
break;
}
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index ccc11b33d89c..2d912b71e543 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -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);
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 807c7116e94b..1db833eb2417 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -347,6 +347,18 @@ static void acpi_tb_convert_fadt(void)
acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
}
+
+ /*
+ * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero)
+ * are indeed zero. This will workaround BIOSs that inadvertently placed
+ * values in these fields.
+ */
+ if (acpi_gbl_FADT.header.revision < 3) {
+ acpi_gbl_FADT.preferred_profile = 0;
+ acpi_gbl_FADT.pstate_control = 0;
+ acpi_gbl_FADT.cst_control = 0;
+ acpi_gbl_FADT.boot_flags = 0;
+ }
}
/******************************************************************************
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 7bdbe5a914d0..365c306c7cf8 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -156,11 +156,6 @@ config SATA_INIC162X
help
This option enables support for Initio 162x Serial ATA.
-config SATA_INTEL_COMBINED
- bool
- depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
- default y
-
config SATA_ACPI
bool
depends on ACPI && PCI
@@ -184,7 +179,7 @@ config PATA_ALI
If unsure, say N.
config PATA_AMD
- tristate "AMD/NVidia PATA support (Experimental)"
+ tristate "AMD/NVidia PATA support"
depends on PCI
help
This option enables support for the AMD and NVidia PATA
@@ -209,6 +204,16 @@ config PATA_ATIIXP
If unsure, say N.
+config PATA_CMD640_PCI
+ tristate "CMD640 PCI PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the CMD640 PCI IDE
+ interface chip. Only the primary channel is currently
+ supported.
+
+ If unsure, say N.
+
config PATA_CMD64X
tristate "CMD64x PATA support (Very Experimental)"
depends on PCI&& EXPERIMENTAL
@@ -273,7 +278,7 @@ config ATA_GENERIC
If unsure, say N.
config PATA_HPT366
- tristate "HPT 366/368 PATA support (Very Experimental)"
+ tristate "HPT 366/368 PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables support for the HPT 366 and 368
@@ -282,7 +287,7 @@ config PATA_HPT366
If unsure, say N.
config PATA_HPT37X
- tristate "HPT 370/370A/371/372/374/302 PATA support (Very Experimental)"
+ tristate "HPT 370/370A/371/372/374/302 PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables support for the majority of the later HPT
@@ -309,7 +314,7 @@ config PATA_HPT3X3
If unsure, say N.
config PATA_ISAPNP
- tristate "ISA Plug and Play PATA support (Very Experimental)"
+ tristate "ISA Plug and Play PATA support (Experimental)"
depends on EXPERIMENTAL && ISAPNP
help
This option enables support for ISA plug & play ATA
@@ -318,8 +323,8 @@ config PATA_ISAPNP
If unsure, say N.
config PATA_IT821X
- tristate "IT8211/2 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "IT8211/2 PATA support"
+ depends on PCI
help
This option enables support for the ITE 8211 and 8212
PATA controllers via the new ATA layer, including RAID
@@ -390,10 +395,10 @@ config PATA_MPIIX
If unsure, say N.
config PATA_OLDPIIX
- tristate "Intel PATA old PIIX support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "Intel PATA old PIIX support"
+ depends on PCI
help
- This option enables support for old(?) PIIX PATA support.
+ This option enables support for early PIIX PATA support.
If unsure, say N.
@@ -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.
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 13d7397e0008..b7055e302650 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_PATA_ALI) += pata_ali.o
obj-$(CONFIG_PATA_AMD) += pata_amd.o
obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
+obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o
obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index fd27227771b4..34c5534ed64c 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -170,6 +170,10 @@ enum {
AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */
AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */
AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */
+
+ AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_SKIP_D2H_BSY,
};
struct ahci_cmd_hdr {
@@ -188,8 +192,10 @@ struct ahci_sg {
};
struct ahci_host_priv {
- u32 cap; /* cache of HOST_CAP register */
- u32 port_map; /* cache of HOST_PORTS_IMPL reg */
+ u32 cap; /* cap to use */
+ u32 port_map; /* port map to use */
+ u32 saved_cap; /* saved initial cap */
+ u32 saved_port_map; /* saved initial port_map */
};
struct ahci_port_priv {
@@ -209,7 +215,6 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
static void ahci_irq_clear(struct ata_port *ap);
static int ahci_port_start(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
@@ -263,7 +268,6 @@ static const struct ata_port_operations ahci_ops = {
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
- .irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
.irq_on = ata_dummy_irq_on,
.irq_ack = ata_dummy_irq_ack,
@@ -298,7 +302,6 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
- .irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
.irq_on = ata_dummy_irq_on,
.irq_ack = ata_dummy_irq_ack,
@@ -324,58 +327,41 @@ static const struct ata_port_operations ahci_vt8251_ops = {
static const struct ata_port_info ahci_port_info[] = {
/* board_ahci */
{
- .sht = &ahci_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY,
+ .flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
/* board_ahci_pi */
{
- .sht = &ahci_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI,
+ .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
/* board_ahci_vt8251 */
{
- .sht = &ahci_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY |
- ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ,
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
+ AHCI_FLAG_NO_NCQ,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_vt8251_ops,
},
/* board_ahci_ign_iferr */
{
- .sht = &ahci_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY |
- AHCI_FLAG_IGN_IRQ_IF_ERR,
+ .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
/* board_ahci_sb600 */
{
- .sht = &ahci_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY |
+ .flags = AHCI_FLAG_COMMON |
AHCI_FLAG_IGN_SERR_INTERNAL,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
-
};
static const struct pci_device_id ahci_pci_tbl[] = {
@@ -413,11 +399,11 @@ static const struct pci_device_id ahci_pci_tbl[] = {
PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
/* ATI */
- { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 non-raid */
- { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
+ { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
+ { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
/* NVIDIA */
{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */
@@ -471,10 +457,100 @@ static inline int ahci_nr_ports(u32 cap)
return (cap & 0x1f) + 1;
}
-static inline void __iomem *ahci_port_base(void __iomem *base,
- unsigned int port)
+static inline void __iomem *ahci_port_base(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
+
+ return mmio + 0x100 + (ap->port_no * 0x80);
+}
+
+/**
+ * ahci_save_initial_config - Save and fixup initial config values
+ * @pdev: target PCI device
+ * @pi: associated ATA port info
+ * @hpriv: host private area to store config values
+ *
+ * Some registers containing configuration info might be setup by
+ * BIOS and might be cleared on reset. This function saves the
+ * initial values of those registers into @hpriv such that they
+ * can be restored after controller reset.
+ *
+ * If inconsistent, config values are fixed up by this function.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ahci_save_initial_config(struct pci_dev *pdev,
+ const struct ata_port_info *pi,
+ struct ahci_host_priv *hpriv)
{
- return base + 0x100 + (port * 0x80);
+ void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
+ u32 cap, port_map;
+ int i;
+
+ /* Values prefixed with saved_ are written back to host after
+ * reset. Values without are used for driver operation.
+ */
+ hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
+ hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
+
+ /* fixup zero port_map */
+ if (!port_map) {
+ port_map = (1 << ahci_nr_ports(hpriv->cap)) - 1;
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
+
+ /* write the fixed up value to the PI register */
+ hpriv->saved_port_map = port_map;
+ }
+
+ /* cross check port_map and cap.n_ports */
+ if (pi->flags & AHCI_FLAG_HONOR_PI) {
+ u32 tmp_port_map = port_map;
+ int n_ports = ahci_nr_ports(cap);
+
+ for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
+ if (tmp_port_map & (1 << i)) {
+ n_ports--;
+ tmp_port_map &= ~(1 << i);
+ }
+ }
+
+ /* Whine if inconsistent. No need to update cap.
+ * port_map is used to determine number of ports.
+ */
+ if (n_ports || tmp_port_map)
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "nr_ports (%u) and implemented port map "
+ "(0x%x) don't match\n",
+ ahci_nr_ports(cap), port_map);
+ } else {
+ /* fabricate port_map from cap.nr_ports */
+ port_map = (1 << ahci_nr_ports(cap)) - 1;
+ }
+
+ /* record values to use during operation */
+ hpriv->cap = cap;
+ hpriv->port_map = port_map;
+}
+
+/**
+ * ahci_restore_initial_config - Restore initial config
+ * @host: target ATA host
+ *
+ * Restore initial config stored by ahci_save_initial_config().
+ *
+ * LOCKING:
+ * None.
+ */
+static void ahci_restore_initial_config(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+
+ writel(hpriv->saved_cap, mmio + HOST_CAP);
+ writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
+ (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
}
static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
@@ -511,8 +587,9 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
-static void ahci_start_engine(void __iomem *port_mmio)
+static void ahci_start_engine(struct ata_port *ap)
{
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
/* start DMA */
@@ -522,8 +599,9 @@ static void ahci_start_engine(void __iomem *port_mmio)
readl(port_mmio + PORT_CMD); /* flush */
}
-static int ahci_stop_engine(void __iomem *port_mmio)
+static int ahci_stop_engine(struct ata_port *ap)
{
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
tmp = readl(port_mmio + PORT_CMD);
@@ -545,19 +623,23 @@ static int ahci_stop_engine(void __iomem *port_mmio)
return 0;
}
-static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
- dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_start_fis_rx(struct ata_port *ap)
{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
u32 tmp;
/* set FIS registers */
- if (cap & HOST_CAP_64)
- writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
- writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+ if (hpriv->cap & HOST_CAP_64)
+ writel((pp->cmd_slot_dma >> 16) >> 16,
+ port_mmio + PORT_LST_ADDR_HI);
+ writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
- if (cap & HOST_CAP_64)
- writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
- writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+ if (hpriv->cap & HOST_CAP_64)
+ writel((pp->rx_fis_dma >> 16) >> 16,
+ port_mmio + PORT_FIS_ADDR_HI);
+ writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
/* enable FIS reception */
tmp = readl(port_mmio + PORT_CMD);
@@ -568,8 +650,9 @@ static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
readl(port_mmio + PORT_CMD);
}
-static int ahci_stop_fis_rx(void __iomem *port_mmio)
+static int ahci_stop_fis_rx(struct ata_port *ap)
{
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
/* disable FIS reception */
@@ -586,14 +669,16 @@ static int ahci_stop_fis_rx(void __iomem *port_mmio)
return 0;
}
-static void ahci_power_up(void __iomem *port_mmio, u32 cap)
+static void ahci_power_up(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 cmd;
cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
/* spin up device */
- if (cap & HOST_CAP_SSS) {
+ if (hpriv->cap & HOST_CAP_SSS) {
cmd |= PORT_CMD_SPIN_UP;
writel(cmd, port_mmio + PORT_CMD);
}
@@ -603,11 +688,13 @@ static void ahci_power_up(void __iomem *port_mmio, u32 cap)
}
#ifdef CONFIG_PM
-static void ahci_power_down(void __iomem *port_mmio, u32 cap)
+static void ahci_power_down(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 cmd, scontrol;
- if (!(cap & HOST_CAP_SSS))
+ if (!(hpriv->cap & HOST_CAP_SSS))
return;
/* put device into listen mode, first set PxSCTL.DET to 0 */
@@ -622,29 +709,28 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap)
}
#endif
-static void ahci_init_port(void __iomem *port_mmio, u32 cap,
- dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_init_port(struct ata_port *ap)
{
/* enable FIS reception */
- ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
+ ahci_start_fis_rx(ap);
/* enable DMA */
- ahci_start_engine(port_mmio);
+ ahci_start_engine(ap);
}
-static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
+static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
{
int rc;
/* disable DMA */
- rc = ahci_stop_engine(port_mmio);
+ rc = ahci_stop_engine(ap);
if (rc) {
*emsg = "failed to stop engine";
return rc;
}
/* disable FIS reception */
- rc = ahci_stop_fis_rx(port_mmio);
+ rc = ahci_stop_fis_rx(ap);
if (rc) {
*emsg = "failed stop FIS RX";
return rc;
@@ -653,12 +739,11 @@ static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
return 0;
}
-static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
+static int ahci_reset_controller(struct ata_host *host)
{
- u32 cap_save, impl_save, tmp;
-
- cap_save = readl(mmio + HOST_CAP);
- impl_save = readl(mmio + HOST_PORTS_IMPL);
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+ u32 tmp;
/* global controller reset */
tmp = readl(mmio + HOST_CTL);
@@ -674,7 +759,7 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
tmp = readl(mmio + HOST_CTL);
if (tmp & HOST_RESET) {
- dev_printk(KERN_ERR, &pdev->dev,
+ dev_printk(KERN_ERR, host->dev,
"controller reset failed (0x%x)\n", tmp);
return -EIO;
}
@@ -683,18 +768,8 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
writel(HOST_AHCI_EN, mmio + HOST_CTL);
(void) readl(mmio + HOST_CTL); /* flush */
- /* These write-once registers are normally cleared on reset.
- * Restore BIOS values... which we HOPE were present before
- * reset.
- */
- if (!impl_save) {
- impl_save = (1 << ahci_nr_ports(cap_save)) - 1;
- dev_printk(KERN_WARNING, &pdev->dev,
- "PORTS_IMPL is zero, forcing 0x%x\n", impl_save);
- }
- writel(cap_save, mmio + HOST_CAP);
- writel(impl_save, mmio + HOST_PORTS_IMPL);
- (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
+ /* some registers might be cleared on reset. restore initial values */
+ ahci_restore_initial_config(host);
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
u16 tmp16;
@@ -708,23 +783,23 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
return 0;
}
-static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
- int n_ports, unsigned int port_flags,
- struct ahci_host_priv *hpriv)
+static void ahci_init_controller(struct ata_host *host)
{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
int i, rc;
u32 tmp;
- for (i = 0; i < n_ports; i++) {
- void __iomem *port_mmio = ahci_port_base(mmio, i);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ void __iomem *port_mmio = ahci_port_base(ap);
const char *emsg = NULL;
- if ((port_flags & AHCI_FLAG_HONOR_PI) &&
- !(hpriv->port_map & (1 << i)))
+ if (ata_port_is_dummy(ap))
continue;
/* make sure port is not active */
- rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+ rc = ahci_deinit_port(ap, &emsg);
if (rc)
dev_printk(KERN_WARNING, &pdev->dev,
"%s (%d)\n", emsg, rc);
@@ -752,7 +827,7 @@ static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
static unsigned int ahci_dev_classify(struct ata_port *ap)
{
- void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ahci_port_base(ap);
struct ata_taskfile tf;
u32 tmp;
@@ -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)
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index d8e79882b880..92a491ddd030 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -33,35 +33,6 @@
*/
/**
- * generic_pre_reset - probe begin
- * @ap: ATA port
- *
- * Set up cable type and use generic probe init
- */
-
-static int generic_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
-}
-
-
-/**
- * generic_error_handler - Probe specified port on PATA host controller
- * @ap: Port to probe
- * @classes:
- *
- * LOCKING:
- * None (inherited from caller).
- */
-
-
-static void generic_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, generic_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-/**
* generic_set_mode - mode setting
* @ap: interface to set up
* @unused: returned device on error
@@ -144,8 +115,9 @@ static struct ata_port_operations generic_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = generic_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index b952c584338f..55d306a3e538 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -93,7 +93,7 @@
#include <linux/libata.h>
#define DRV_NAME "ata_piix"
-#define DRV_VERSION "2.10ac1"
+#define DRV_VERSION "2.11"
enum {
PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
@@ -155,11 +155,11 @@ struct piix_host_priv {
static int piix_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
static void piix_pata_error_handler(struct ata_port *ap);
-static void ich_pata_error_handler(struct ata_port *ap);
static void piix_sata_error_handler(struct ata_port *ap);
static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+static int ich_pata_cable_detect(struct ata_port *ap);
static unsigned int in_module_init = 1;
@@ -305,6 +305,7 @@ static const struct ata_port_operations piix_pata_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = piix_pata_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -336,8 +337,9 @@ static const struct ata_port_operations ich_pata_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ich_pata_error_handler,
+ .error_handler = piix_pata_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ich_pata_cable_detect,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -580,12 +582,13 @@ static const struct ich_laptop ich_laptop[] = {
/* devid, subvendor, subdev */
{ 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
{ 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
+ { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
/* end marker */
{ 0, }
};
/**
- * piix_pata_cbl_detect - Probe host controller cable detect info
+ * ich_pata_cable_detect - Probe host controller cable detect info
* @ap: Port for which cable detect info is desired
*
* Read 80c cable indicator from ATA PCI device's PCI config
@@ -595,23 +598,18 @@ static const struct ich_laptop ich_laptop[] = {
* None (inherited from caller).
*/
-static void ich_pata_cbl_detect(struct ata_port *ap)
+static int ich_pata_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
const struct ich_laptop *lap = &ich_laptop[0];
u8 tmp, mask;
- /* no 80c support in host controller? */
- if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
- goto cbl40;
-
/* Check for specials - Acer Aspire 5602WLMi */
while (lap->device) {
if (lap->device == pdev->device &&
lap->subvendor == pdev->subsystem_vendor &&
lap->subdevice == pdev->subsystem_device) {
- ap->cbl = ATA_CBL_PATA40_SHORT;
- return;
+ return ATA_CBL_PATA40_SHORT;
}
lap++;
}
@@ -620,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,
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 0abd72d0dec2..ca67484af1eb 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -72,7 +72,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
static void ata_dev_xfermask(struct ata_device *dev);
-static unsigned int ata_print_id = 1;
+unsigned int ata_print_id = 1;
static struct workqueue_struct *ata_wq;
struct workqueue_struct *ata_aux_wq;
@@ -89,6 +89,10 @@ int libata_fua = 0;
module_param_named(fua, libata_fua, int, 0444);
MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
+static int ata_ignore_hpa = 0;
+module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
+MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)");
+
static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
module_param(ata_probe_timeout, int, 0444);
MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
@@ -808,6 +812,205 @@ void ata_id_c_string(const u16 *id, unsigned char *s,
*p = '\0';
}
+static u64 ata_tf_to_lba48(struct ata_taskfile *tf)
+{
+ u64 sectors = 0;
+
+ sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40;
+ sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32;
+ sectors |= (tf->hob_lbal & 0xff) << 24;
+ sectors |= (tf->lbah & 0xff) << 16;
+ sectors |= (tf->lbam & 0xff) << 8;
+ sectors |= (tf->lbal & 0xff);
+
+ return ++sectors;
+}
+
+static u64 ata_tf_to_lba(struct ata_taskfile *tf)
+{
+ u64 sectors = 0;
+
+ sectors |= (tf->device & 0x0f) << 24;
+ sectors |= (tf->lbah & 0xff) << 16;
+ sectors |= (tf->lbam & 0xff) << 8;
+ sectors |= (tf->lbal & 0xff);
+
+ return ++sectors;
+}
+
+/**
+ * ata_read_native_max_address_ext - LBA48 native max query
+ * @dev: Device to query
+ *
+ * Perform an LBA48 size query upon the device in question. Return the
+ * actual LBA48 size or zero if the command fails.
+ */
+
+static u64 ata_read_native_max_address_ext(struct ata_device *dev)
+{
+ unsigned int err;
+ struct ata_taskfile tf;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
+ tf.protocol |= ATA_PROT_NODATA;
+ tf.device |= 0x40;
+
+ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err)
+ return 0;
+
+ return ata_tf_to_lba48(&tf);
+}
+
+/**
+ * ata_read_native_max_address - LBA28 native max query
+ * @dev: Device to query
+ *
+ * Performa an LBA28 size query upon the device in question. Return the
+ * actual LBA28 size or zero if the command fails.
+ */
+
+static u64 ata_read_native_max_address(struct ata_device *dev)
+{
+ unsigned int err;
+ struct ata_taskfile tf;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = ATA_CMD_READ_NATIVE_MAX;
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+ tf.protocol |= ATA_PROT_NODATA;
+ tf.device |= 0x40;
+
+ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err)
+ return 0;
+
+ return ata_tf_to_lba(&tf);
+}
+
+/**
+ * ata_set_native_max_address_ext - LBA48 native max set
+ * @dev: Device to query
+ *
+ * Perform an LBA48 size set max upon the device in question. Return the
+ * actual LBA48 size or zero if the command fails.
+ */
+
+static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors)
+{
+ unsigned int err;
+ struct ata_taskfile tf;
+
+ new_sectors--;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = ATA_CMD_SET_MAX_EXT;
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
+ tf.protocol |= ATA_PROT_NODATA;
+ tf.device |= 0x40;
+
+ tf.lbal = (new_sectors >> 0) & 0xff;
+ tf.lbam = (new_sectors >> 8) & 0xff;
+ tf.lbah = (new_sectors >> 16) & 0xff;
+
+ tf.hob_lbal = (new_sectors >> 24) & 0xff;
+ tf.hob_lbam = (new_sectors >> 32) & 0xff;
+ tf.hob_lbah = (new_sectors >> 40) & 0xff;
+
+ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err)
+ return 0;
+
+ return ata_tf_to_lba48(&tf);
+}
+
+/**
+ * ata_set_native_max_address - LBA28 native max set
+ * @dev: Device to query
+ *
+ * Perform an LBA28 size set max upon the device in question. Return the
+ * actual LBA28 size or zero if the command fails.
+ */
+
+static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
+{
+ unsigned int err;
+ struct ata_taskfile tf;
+
+ new_sectors--;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = ATA_CMD_SET_MAX;
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+ tf.protocol |= ATA_PROT_NODATA;
+
+ tf.lbal = (new_sectors >> 0) & 0xff;
+ tf.lbam = (new_sectors >> 8) & 0xff;
+ tf.lbah = (new_sectors >> 16) & 0xff;
+ tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40;
+
+ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err)
+ return 0;
+
+ return ata_tf_to_lba(&tf);
+}
+
+/**
+ * ata_hpa_resize - Resize a device with an HPA set
+ * @dev: Device to resize
+ *
+ * Read the size of an LBA28 or LBA48 disk with HPA features and resize
+ * it if required to the full size of the media. The caller must check
+ * the drive has the HPA feature set enabled.
+ */
+
+static u64 ata_hpa_resize(struct ata_device *dev)
+{
+ u64 sectors = dev->n_sectors;
+ u64 hpa_sectors;
+
+ if (ata_id_has_lba48(dev->id))
+ hpa_sectors = ata_read_native_max_address_ext(dev);
+ else
+ hpa_sectors = ata_read_native_max_address(dev);
+
+ /* if no hpa, both should be equal */
+ ata_dev_printk(dev, KERN_INFO, "%s 1: sectors = %lld, "
+ "hpa_sectors = %lld\n",
+ __FUNCTION__, (long long)sectors, (long long)hpa_sectors);
+
+ if (hpa_sectors > sectors) {
+ ata_dev_printk(dev, KERN_INFO,
+ "Host Protected Area detected:\n"
+ "\tcurrent size: %lld sectors\n"
+ "\tnative size: %lld sectors\n",
+ (long long)sectors, (long long)hpa_sectors);
+
+ if (ata_ignore_hpa) {
+ if (ata_id_has_lba48(dev->id))
+ hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors);
+ else
+ hpa_sectors = ata_set_native_max_address(dev,
+ hpa_sectors);
+
+ if (hpa_sectors) {
+ ata_dev_printk(dev, KERN_INFO, "native size "
+ "increased to %lld sectors\n",
+ (long long)hpa_sectors);
+ return hpa_sectors;
+ }
+ }
+ }
+ return sectors;
+}
+
static u64 ata_id_n_sectors(const u16 *id)
{
if (ata_id_has_lba(id)) {
@@ -1270,12 +1473,16 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
if (ap->ops->post_internal_cmd)
ap->ops->post_internal_cmd(qc);
- if ((qc->flags & ATA_QCFLAG_FAILED) && !qc->err_mask) {
- if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING,
- "zero err_mask for failed "
- "internal command, assuming AC_ERR_OTHER\n");
- qc->err_mask |= AC_ERR_OTHER;
+ /* perform minimal error analysis */
+ if (qc->flags & ATA_QCFLAG_FAILED) {
+ if (qc->result_tf.command & (ATA_ERR | ATA_DF))
+ qc->err_mask |= AC_ERR_DEV;
+
+ if (!qc->err_mask)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ if (qc->err_mask & ~AC_ERR_OTHER)
+ qc->err_mask &= ~AC_ERR_OTHER;
}
/* finish up */
@@ -1379,30 +1586,44 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
* Check if the current speed of the device requires IORDY. Used
* by various controllers for chip configuration.
*/
-
+
unsigned int ata_pio_need_iordy(const struct ata_device *adev)
{
- int pio;
- int speed = adev->pio_mode - XFER_PIO_0;
-
- if (speed < 2)
+ /* Controller doesn't support IORDY. Probably a pointless check
+ as the caller should know this */
+ if (adev->ap->flags & ATA_FLAG_NO_IORDY)
return 0;
- if (speed > 2)
+ /* PIO3 and higher it is mandatory */
+ if (adev->pio_mode > XFER_PIO_2)
+ return 1;
+ /* We turn it on when possible */
+ if (ata_id_has_iordy(adev->id))
return 1;
+ return 0;
+}
+/**
+ * ata_pio_mask_no_iordy - Return the non IORDY mask
+ * @adev: ATA device
+ *
+ * Compute the highest mode possible if we are not using iordy. Return
+ * -1 if no iordy mode is available.
+ */
+
+static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
+{
/* If we have no drive specific rule, then PIO 2 is non IORDY */
-
if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE */
- pio = adev->id[ATA_ID_EIDE_PIO];
+ u16 pio = adev->id[ATA_ID_EIDE_PIO];
/* Is the speed faster than the drive allows non IORDY ? */
if (pio) {
/* This is cycle times not frequency - watch the logic! */
if (pio > 240) /* PIO2 is 240nS per cycle */
- return 1;
- return 0;
+ return 3 << ATA_SHIFT_PIO;
+ return 7 << ATA_SHIFT_PIO;
}
}
- return 0;
+ return 3 << ATA_SHIFT_PIO;
}
/**
@@ -1431,13 +1652,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
struct ata_taskfile tf;
unsigned int err_mask = 0;
const char *reason;
+ int tried_spinup = 0;
int rc;
if (ata_msg_ctl(ap))
ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);
ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
-
retry:
ata_tf_init(dev, &tf);
@@ -1494,6 +1715,32 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
goto err_out;
}
+ if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) {
+ tried_spinup = 1;
+ /*
+ * Drive powered-up in standby mode, and requires a specific
+ * SET_FEATURES spin-up subcommand before it will accept
+ * anything other than the original IDENTIFY command.
+ */
+ ata_tf_init(dev, &tf);
+ tf.command = ATA_CMD_SET_FEATURES;
+ tf.feature = SETFEATURES_SPINUP;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "SPINUP failed";
+ goto err_out;
+ }
+ /*
+ * If the drive initially returned incomplete IDENTIFY info,
+ * we now must reissue the IDENTIFY command.
+ */
+ if (id[2] == 0x37c8)
+ goto retry;
+ }
+
if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) {
/*
* The exact sequence expected by certain pre-ATA4 drives is:
@@ -1560,20 +1807,6 @@ static void ata_dev_config_ncq(struct ata_device *dev,
snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
}
-static void ata_set_port_max_cmd_len(struct ata_port *ap)
-{
- int i;
-
- if (ap->scsi_host) {
- unsigned int len = 0;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- len = max(len, ap->device[i].cdb_len);
-
- ap->scsi_host->max_cmd_len = len;
- }
-}
-
/**
* ata_dev_configure - Configure the specified ATA/ATAPI device
* @dev: Target device to configure
@@ -1658,6 +1891,7 @@ int ata_dev_configure(struct ata_device *dev)
snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
dev->n_sectors = ata_id_n_sectors(id);
+ dev->n_sectors_boot = dev->n_sectors;
/* SCSI only uses 4-char revisions, dump full 8 chars from ATA */
ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV,
@@ -1684,6 +1918,9 @@ int ata_dev_configure(struct ata_device *dev)
dev->flags |= ATA_DFLAG_FLUSH_EXT;
}
+ if (ata_id_hpa_enabled(dev->id))
+ dev->n_sectors = ata_hpa_resize(dev);
+
/* config NCQ */
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
@@ -1773,8 +2010,6 @@ int ata_dev_configure(struct ata_device *dev)
}
}
- ata_set_port_max_cmd_len(ap);
-
/* limit bridge transfers to udma5, 200 sectors */
if (ata_dev_knobble(dev)) {
if (ata_msg_drv(ap) && print_info)
@@ -1785,14 +2020,15 @@ int ata_dev_configure(struct ata_device *dev)
}
if (ata_device_blacklisted(dev) & ATA_HORKAGE_MAX_SEC_128)
- dev->max_sectors = min(ATA_MAX_SECTORS_128, dev->max_sectors);
+ dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
+ dev->max_sectors);
/* limit ATAPI DMA to R/W commands only */
if (ata_device_blacklisted(dev) & ATA_HORKAGE_DMA_RW_ONLY)
dev->horkage |= ATA_HORKAGE_DMA_RW_ONLY;
if (ap->ops->dev_config)
- ap->ops->dev_config(ap, dev);
+ ap->ops->dev_config(dev);
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
@@ -1807,6 +2043,56 @@ err_out_nosup:
}
/**
+ * ata_cable_40wire - return 40 wire cable type
+ * @ap: port
+ *
+ * Helper method for drivers which want to hardwire 40 wire cable
+ * detection.
+ */
+
+int ata_cable_40wire(struct ata_port *ap)
+{
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * ata_cable_80wire - return 80 wire cable type
+ * @ap: port
+ *
+ * Helper method for drivers which want to hardwire 80 wire cable
+ * detection.
+ */
+
+int ata_cable_80wire(struct ata_port *ap)
+{
+ return ATA_CBL_PATA80;
+}
+
+/**
+ * ata_cable_unknown - return unknown PATA cable.
+ * @ap: port
+ *
+ * Helper method for drivers which have no PATA cable detection.
+ */
+
+int ata_cable_unknown(struct ata_port *ap)
+{
+ return ATA_CBL_PATA_UNK;
+}
+
+/**
+ * ata_cable_sata - return SATA cable type
+ * @ap: port
+ *
+ * Helper method for drivers which have SATA cables
+ */
+
+int ata_cable_sata(struct ata_port *ap)
+{
+ return ATA_CBL_SATA;
+}
+
+/**
* ata_bus_probe - Reset and probe ATA bus
* @ap: Bus to probe
*
@@ -1876,6 +2162,10 @@ int ata_bus_probe(struct ata_port *ap)
goto fail;
}
+ /* Now ask for the cable type as PDIAG- should have been released */
+ if (ap->ops->cable_detect)
+ ap->cbl = ap->ops->cable_detect(ap);
+
/* After the identify sequence we can now set up the devices. We do
this in the normal order so that the user doesn't get confused */
@@ -1958,7 +2248,7 @@ void ata_port_probe(struct ata_port *ap)
* LOCKING:
* None.
*/
-static void sata_print_link_status(struct ata_port *ap)
+void sata_print_link_status(struct ata_port *ap)
{
u32 sstatus, scontrol, tmp;
@@ -2352,6 +2642,12 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
t->active += (t->cycle - (t->active + t->recover)) / 2;
t->recover = t->cycle - t->active;
}
+
+ /* In a few cases quantisation may produce enough errors to
+ leave t->cycle too low for the sum of active and recovery
+ if so we must correct this */
+ if (t->active + t->recover > t->cycle)
+ t->cycle = t->active + t->recover;
return 0;
}
@@ -2481,12 +2777,13 @@ static int ata_dev_set_mode(struct ata_device *dev)
}
/**
- * ata_set_mode - Program timings and issue SET FEATURES - XFER
+ * ata_do_set_mode - Program timings and issue SET FEATURES - XFER
* @ap: port on which timings will be programmed
* @r_failed_dev: out paramter for failed device
*
- * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
- * ata_set_mode() fails, pointer to the failing device is
+ * Standard implementation of the function used to tune and set
+ * ATA device disk transfer mode (PIO3, UDMA6, etc.). If
+ * ata_dev_set_mode() fails, pointer to the failing device is
* returned in @r_failed_dev.
*
* LOCKING:
@@ -2495,14 +2792,12 @@ static int ata_dev_set_mode(struct ata_device *dev)
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+
+int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
{
struct ata_device *dev;
int i, rc = 0, used_dma = 0, found = 0;
- /* has private set_mode? */
- if (ap->ops->set_mode)
- return ap->ops->set_mode(ap, r_failed_dev);
/* step 1: calculate xfer_mask */
for (i = 0; i < ATA_MAX_DEVICES; i++) {
@@ -2587,6 +2882,29 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
}
/**
+ * ata_set_mode - Program timings and issue SET FEATURES - XFER
+ * @ap: port on which timings will be programmed
+ * @r_failed_dev: out paramter for failed device
+ *
+ * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
+ * ata_set_mode() fails, pointer to the failing device is
+ * returned in @r_failed_dev.
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * 0 on success, negative errno otherwise
+ */
+int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ /* has private set_mode? */
+ if (ap->ops->set_mode)
+ return ap->ops->set_mode(ap, r_failed_dev);
+ return ata_do_set_mode(ap, r_failed_dev);
+}
+
+/**
* ata_tf_to_host - issue ATA taskfile to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
@@ -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,16 +6331,52 @@ int ata_device_add(const struct ata_probe_ent *ent)
ata_scsi_scan_host(ap);
}
- VPRINTK("EXIT, returning %u\n", ent->n_ports);
- return ent->n_ports; /* success */
-
- err_out:
- devres_release_group(dev, ata_device_add);
- VPRINTK("EXIT, returning %d\n", rc);
return 0;
}
/**
+ * ata_host_activate - start host, request IRQ and register it
+ * @host: target ATA host
+ * @irq: IRQ to request
+ * @irq_handler: irq_handler used when requesting IRQ
+ * @irq_flags: irq_flags used when requesting IRQ
+ * @sht: scsi_host_template to use when registering the host
+ *
+ * After allocating an ATA host and initializing it, most libata
+ * LLDs perform three steps to activate the host - start host,
+ * request IRQ and register it. This helper takes necessasry
+ * arguments and performs the three steps in one go.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_host_activate(struct ata_host *host, int irq,
+ irq_handler_t irq_handler, unsigned long irq_flags,
+ struct scsi_host_template *sht)
+{
+ int rc;
+
+ rc = ata_host_start(host);
+ if (rc)
+ return rc;
+
+ rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
+ dev_driver_string(host->dev), host);
+ if (rc)
+ return rc;
+
+ rc = ata_host_register(host, sht);
+ /* if failed, just free the IRQ and leave ports alone */
+ if (rc)
+ devm_free_irq(host->dev, irq, host);
+
+ return rc;
+}
+
+/**
* ata_port_detach - Detach ATA port in prepration of device removal
* @ap: ATA port to be detached
*
@@ -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);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 39f556c02992..2bff9adcacf1 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -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.
*/
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index e9364434182c..9afba2ba489e 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -104,7 +104,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
* libata transport template. libata doesn't do real transport stuff.
* It just needs the eh_timed_out hook.
*/
-struct scsi_transport_template ata_scsi_transport_template = {
+static struct scsi_transport_template ata_scsi_transport_template = {
.eh_strategy_handler = ata_scsi_error,
.eh_timed_out = ata_scsi_timed_out,
.user_scan = ata_scsi_user_scan,
@@ -2678,6 +2678,18 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
tf->device = qc->dev->devno ?
tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
+ /* READ/WRITE LONG use a non-standard sect_size */
+ qc->sect_size = ATA_SECT_SIZE;
+ switch (tf->command) {
+ case ATA_CMD_READ_LONG:
+ case ATA_CMD_READ_LONG_ONCE:
+ case ATA_CMD_WRITE_LONG:
+ case ATA_CMD_WRITE_LONG_ONCE:
+ if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
+ goto invalid_fld;
+ qc->sect_size = scmd->request_bufflen;
+ }
+
/*
* Filter SET_FEATURES - XFER MODE command -- otherwise,
* SET_FEATURES - XFER MODE must be preceded/succeeded
@@ -2792,8 +2804,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
{
int rc = 0;
- if (unlikely(!scmd->cmd_len)) {
- ata_dev_printk(dev, KERN_WARNING, "WARNING: zero len CDB\n");
+ if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) {
+ DPRINTK("bad CDB len=%u, max=%u\n",
+ scmd->cmd_len, dev->cdb_len);
scmd->result = DID_ERROR << 16;
done(scmd);
return 0;
@@ -2948,6 +2961,48 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
}
}
+int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
+{
+ int i, rc;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct Scsi_Host *shost;
+
+ rc = -ENOMEM;
+ shost = scsi_host_alloc(sht, sizeof(struct ata_port *));
+ if (!shost)
+ goto err_alloc;
+
+ *(struct ata_port **)&shost->hostdata[0] = ap;
+ ap->scsi_host = shost;
+
+ shost->transportt = &ata_scsi_transport_template;
+ shost->unique_id = ap->print_id;
+ shost->max_id = 16;
+ shost->max_lun = 1;
+ shost->max_channel = 1;
+ shost->max_cmd_len = 16;
+
+ rc = scsi_add_host(ap->scsi_host, ap->host->dev);
+ if (rc)
+ goto err_add;
+ }
+
+ return 0;
+
+ err_add:
+ scsi_host_put(host->ports[i]->scsi_host);
+ err_alloc:
+ while (--i >= 0) {
+ struct Scsi_Host *shost = host->ports[i]->scsi_host;
+
+ scsi_remove_host(shost);
+ scsi_host_put(shost);
+ }
+ return rc;
+}
+
void ata_scsi_scan_host(struct ata_port *ap)
{
unsigned int i;
@@ -3224,21 +3279,21 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host,
struct ata_port_info *port_info,
struct Scsi_Host *shost)
{
- struct ata_port *ap = kzalloc(sizeof(*ap), GFP_KERNEL);
- struct ata_probe_ent *ent;
+ struct ata_port *ap;
+ ap = ata_port_alloc(host);
if (!ap)
return NULL;
- ent = ata_probe_ent_alloc(host->dev, port_info);
- if (!ent) {
- kfree(ap);
- return NULL;
- }
-
- ata_port_init(ap, host, ent, 0);
+ ap->port_no = 0;
ap->lock = shost->host_lock;
- devm_kfree(host->dev, ent);
+ ap->pio_mask = port_info->pio_mask;
+ ap->mwdma_mask = port_info->mwdma_mask;
+ ap->udma_mask = port_info->udma_mask;
+ ap->flags |= port_info->flags;
+ ap->ops = port_info->port_ops;
+ ap->cbl = ATA_CBL_SATA;
+
return ap;
}
EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
@@ -3294,8 +3349,10 @@ int ata_sas_port_init(struct ata_port *ap)
{
int rc = ap->ops->port_start(ap);
- if (!rc)
+ if (!rc) {
+ ap->print_id = ata_print_id++;
rc = ata_bus_probe(ap);
+ }
return rc;
}
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 2ffcca063d80..8af18ad1ca7f 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -526,168 +526,399 @@ static int ata_resources_present(struct pci_dev *pdev, int port)
port = port * 2;
for (i = 0; i < 2; i ++) {
if (pci_resource_start(pdev, port + i) == 0 ||
- pci_resource_len(pdev, port + i) == 0)
- return 0;
+ pci_resource_len(pdev, port + i) == 0)
+ return 0;
}
return 1;
}
/**
- * ata_pci_init_native_mode - Initialize native-mode driver
- * @pdev: pci device to be initialized
- * @port: array[2] of pointers to port info structures.
- * @ports: bitmap of ports present
- *
- * Utility function which allocates and initializes an
- * ata_probe_ent structure for a standard dual-port
- * PIO-based IDE controller. The returned ata_probe_ent
- * structure can be passed to ata_device_add(). The returned
- * ata_probe_ent structure should then be freed with kfree().
- *
- * The caller need only pass the address of the primary port, the
- * secondary will be deduced automatically. If the device has non
- * standard secondary port mappings this function can be called twice,
- * once for each interface.
+ * ata_pci_init_bmdma - acquire PCI BMDMA resources and init ATA host
+ * @host: target ATA host
+ *
+ * Acquire PCI BMDMA resources and initialize @host accordingly.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
*/
+static int ata_pci_init_bmdma(struct ata_host *host)
+{
+ struct device *gdev = host->dev;
+ struct pci_dev *pdev = to_pci_dev(gdev);
+ int i, rc;
+
+ /* TODO: If we get no DMA mask we should fall back to PIO */
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+
+ /* request and iomap DMA region */
+ rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME);
+ if (rc) {
+ dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n");
+ return -ENOMEM;
+ }
+ host->iomap = pcim_iomap_table(pdev);
+
+ for (i = 0; i < 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;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 1f1e3a51f859..5f4d40cd3288 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -52,6 +52,7 @@ enum {
ATA_DNXFER_QUIET = (1 << 31),
};
+extern unsigned int ata_print_id;
extern struct workqueue_struct *ata_aux_wq;
extern int atapi_enabled;
extern int atapi_dmadir;
@@ -92,10 +93,7 @@ extern int ata_flush_cache(struct ata_device *dev);
extern void ata_dev_init(struct ata_device *dev);
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
-extern void ata_port_init(struct ata_port *ap, struct ata_host *host,
- const struct ata_probe_ent *ent, unsigned int port_no);
-extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
- const struct ata_port_info *port);
+extern struct ata_port *ata_port_alloc(struct ata_host *host);
/* libata-acpi.c */
#ifdef CONFIG_SATA_ACPI
@@ -113,8 +111,8 @@ static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
#endif
/* libata-scsi.c */
-extern struct scsi_transport_template ata_scsi_transport_template;
-
+extern int ata_scsi_add_hosts(struct ata_host *host,
+ struct scsi_host_template *sht);
extern void ata_scsi_scan_host(struct ata_port *ap);
extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 11ea552a58ca..d40edebb510a 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -34,7 +34,7 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.7.3"
+#define DRV_VERSION "0.7.4"
/*
* Cable special cases
@@ -90,59 +90,6 @@ static int ali_c2_cable_detect(struct ata_port *ap)
}
/**
- * ali_early_error_handler - reset for eary chip
- * @ap: ATA port
- *
- * Handle the reset callback for the later chips with cable detect
- */
-
-static int ali_c2_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ali_c2_cable_detect(ap);
- return ata_std_prereset(ap);
-}
-
-static void ali_c2_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, ali_c2_pre_reset,
- ata_std_softreset, NULL,
- ata_std_postreset);
-}
-
-/**
- * ali_early_cable_detect - cable detection
- * @ap: ATA port
- *
- * Perform cable detection for older chipsets. This turns out to be
- * rather easy to implement
- */
-
-static int ali_early_cable_detect(struct ata_port *ap)
-{
- return ATA_CBL_PATA40;
-}
-
-/**
- * ali_early_probe_init - reset for early chip
- * @ap: ATA port
- *
- * Handle the reset callback for the early (pre cable detect) chips.
- */
-
-static int ali_early_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ali_early_cable_detect(ap);
- return ata_std_prereset(ap);
-}
-
-static void ali_early_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, ali_early_pre_reset,
- ata_std_softreset, NULL,
- ata_std_postreset);
-}
-
-/**
* ali_20_filter - filter for earlier ALI DMA
* @ap: ALi ATA port
* @adev: attached device
@@ -151,7 +98,7 @@ static void ali_early_error_handler(struct ata_port *ap)
* fix that later on. Also ensure we do not do UDMA on WDC drives
*/
-static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long ali_20_filter(struct ata_device *adev, unsigned long mask)
{
char model_num[ATA_ID_PROD_LEN + 1];
/* No DMA on anything but a disk for now */
@@ -160,7 +107,7 @@ static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device
ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
if (strstr(model_num, "WDC"))
return mask &= ~ATA_MASK_UDMA;
- return ata_pci_default_filter(ap, adev, mask);
+ return ata_pci_default_filter(adev, mask);
}
/**
@@ -314,7 +261,6 @@ static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/**
* ali_lock_sectors - Keep older devices to 255 sector mode
- * @ap: ATA port
* @adev: Device
*
* Called during the bus probe for each device that is found. We use
@@ -324,7 +270,7 @@ static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
* slower PIO methods
*/
-static void ali_lock_sectors(struct ata_port *ap, struct ata_device *adev)
+static void ali_lock_sectors(struct ata_device *adev)
{
adev->max_sectors = 255;
}
@@ -366,8 +312,9 @@ static struct ata_port_operations ali_early_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ali_early_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -402,8 +349,9 @@ static struct ata_port_operations ali_20_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ali_early_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -440,8 +388,9 @@ static struct ata_port_operations ali_c2_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ali_c2_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ali_c2_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -477,8 +426,9 @@ static struct ata_port_operations ali_c5_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ali_c2_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ali_c2_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 18381762908b..536ee892ab72 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.2.8"
+#define DRV_VERSION "0.3.8"
/**
* timing_setup - shared timing computation and load
@@ -119,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,
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index 21c30282717c..00e9ec342db0 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -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,
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 51d9923be02e..39c871a3ddac 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -22,7 +22,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_atiixp"
-#define DRV_VERSION "0.4.4"
+#define DRV_VERSION "0.4.5"
enum {
ATIIXP_IDE_PIO_TIMING = 0x40,
@@ -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
index 000000000000..2105985a8013
--- /dev/null
+++ b/drivers/ata/pata_cmd640.c
@@ -0,0 +1,312 @@
+/*
+ * pata_cmd640.c - CMD640 PCI PATA for new ATA layer
+ * (C) 2007 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based upon
+ * linux/drivers/ide/pci/cmd640.c Version 1.02 Sep 01, 1996
+ *
+ * Copyright (C) 1995-1996 Linus Torvalds & authors (see driver)
+ *
+ * This drives only the PCI version of the controller. If you have a
+ * VLB one then we have enough docs to support it but you can write
+ * your own code.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_cmd640"
+#define DRV_VERSION "0.0.5"
+
+struct cmd640_reg {
+ int last;
+ u8 reg58[ATA_MAX_DEVICES];
+};
+
+enum {
+ CFR = 0x50,
+ CNTRL = 0x51,
+ CMDTIM = 0x52,
+ ARTIM0 = 0x53,
+ DRWTIM0 = 0x54,
+ ARTIM23 = 0x57,
+ DRWTIM23 = 0x58,
+ BRST = 0x59
+};
+
+/**
+ * cmd640_set_piomode - set initial PIO mode data
+ * @ap: ATA port
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup.
+ */
+
+static void cmd640_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct cmd640_reg *timing = ap->private_data;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_timing t;
+ const unsigned long T = 1000000 / 33;
+ const u8 setup_data[] = { 0x40, 0x40, 0x40, 0x80, 0x00 };
+ u8 reg;
+ int arttim = ARTIM0 + 2 * adev->devno;
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+ printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
+ return;
+ }
+
+ /* The second channel has shared timings and the setup timing is
+ messy to switch to merge it for worst case */
+ if (ap->port_no && pair) {
+ struct ata_timing p;
+ ata_timing_compute(pair, pair->pio_mode, &p, T, 1);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP);
+ }
+
+ /* Make the timings fit */
+ if (t.recover > 16) {
+ t.active += t.recover - 16;
+ t.recover = 16;
+ }
+ if (t.active > 16)
+ t.active = 16;
+
+ /* Now convert the clocks into values we can actually stuff into
+ the chip */
+
+ if (t.recover > 1)
+ t.recover--; /* 640B only */
+ else
+ t.recover = 15;
+
+ if (t.setup > 4)
+ t.setup = 0xC0;
+ else
+ t.setup = setup_data[t.setup];
+
+ if (ap->port_no == 0) {
+ t.active &= 0x0F; /* 0 = 16 */
+
+ /* Load setup timing */
+ pci_read_config_byte(pdev, arttim, &reg);
+ reg &= 0x3F;
+ reg |= t.setup;
+ pci_write_config_byte(pdev, arttim, reg);
+
+ /* Load active/recovery */
+ pci_write_config_byte(pdev, arttim + 1, (t.active << 4) | t.recover);
+ } else {
+ /* Save the shared timings for channel, they will be loaded
+ by qc_issue_prot. Reloading the setup time is expensive
+ so we keep a merged one loaded */
+ pci_read_config_byte(pdev, ARTIM23, &reg);
+ reg &= 0x3F;
+ reg |= t.setup;
+ pci_write_config_byte(pdev, ARTIM23, reg);
+ timing->reg58[adev->devno] = (t.active << 4) | t.recover;
+ }
+}
+
+
+/**
+ * cmd640_qc_issue_prot - command preparation hook
+ * @qc: Command to be issued
+ *
+ * Channel 1 has shared timings. We must reprogram the
+ * clock each drive 2/3 switch we do.
+ */
+
+static unsigned int cmd640_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct cmd640_reg *timing = ap->private_data;
+
+ if (ap->port_no != 0 && adev->devno != timing->last) {
+ pci_write_config_byte(pdev, DRWTIM23, timing->reg58[adev->devno]);
+ timing->last = adev->devno;
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+/**
+ * cmd640_port_start - port setup
+ * @ap: ATA port being set up
+ *
+ * The CMD640 needs to maintain private data structures so we
+ * allocate space here.
+ */
+
+static int cmd640_port_start(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct cmd640_reg *timing;
+
+ int ret = ata_port_start(ap);
+ if (ret < 0)
+ return ret;
+
+ timing = devm_kzalloc(&pdev->dev, sizeof(struct cmd640_reg), GFP_KERNEL);
+ if (timing == NULL)
+ return -ENOMEM;
+ timing->last = -1; /* Force a load */
+ ap->private_data = timing;
+ return ret;
+}
+
+static struct scsi_host_template cmd640_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
+ .resume = ata_scsi_device_resume,
+ .suspend = ata_scsi_device_suspend,
+#endif
+};
+
+static struct ata_port_operations cmd640_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cmd640_set_piomode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = cmd640_qc_issue_prot,
+
+ /* In theory this is not needed once we kill the prefetcher */
+ .data_xfer = ata_data_xfer_noirq,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .port_start = cmd640_port_start,
+};
+
+static void cmd640_hardware_init(struct pci_dev *pdev)
+{
+ u8 r;
+ u8 ctrl;
+
+ /* CMD640 detected, commiserations */
+ pci_write_config_byte(pdev, 0x5B, 0x00);
+ /* Get version info */
+ pci_read_config_byte(pdev, CFR, &r);
+ /* PIO0 command cycles */
+ pci_write_config_byte(pdev, CMDTIM, 0);
+ /* 512 byte bursts (sector) */
+ pci_write_config_byte(pdev, BRST, 0x40);
+ /*
+ * A reporter a long time ago
+ * Had problems with the data fifo
+ * So don't run the risk
+ * Of putting crap on the disk
+ * For its better just to go slow
+ */
+ /* Do channel 0 */
+ pci_read_config_byte(pdev, CNTRL, &ctrl);
+ pci_write_config_byte(pdev, CNTRL, ctrl | 0xC0);
+ /* Ditto for channel 1 */
+ pci_read_config_byte(pdev, ARTIM23, &ctrl);
+ ctrl |= 0x0C;
+ pci_write_config_byte(pdev, ARTIM23, ctrl);
+}
+
+static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &cmd640_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &cmd640_port_ops
+ };
+
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ cmd640_hardware_init(pdev);
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static int cmd640_reinit_one(struct pci_dev *pdev)
+{
+ cmd640_hardware_init(pdev);
+#ifdef CONFIG_PM
+ return ata_pci_device_resume(pdev);
+#else
+ return 0;
+#endif
+}
+
+static const struct pci_device_id cmd640[] = {
+ { PCI_VDEVICE(CMD, 0x640), 0 },
+ { },
+};
+
+static struct pci_driver cmd640_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cmd640,
+ .probe = cmd640_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+#endif
+ .resume = cmd640_reinit_one,
+};
+
+static int __init cmd640_init(void)
+{
+ return pci_register_driver(&cmd640_pci_driver);
+}
+
+static void __exit cmd640_exit(void)
+{
+ pci_unregister_driver(&cmd640_pci_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for CMD640 PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cmd640);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cmd640_init);
+module_exit(cmd640_exit);
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index 5b13bdd1edc0..3989cc577fcd 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -75,13 +75,7 @@ enum {
DTPR1 = 0x7C
};
-static int cmd64x_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-static int cmd648_pre_reset(struct ata_port *ap)
+static int cmd648_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 r;
@@ -89,21 +83,8 @@ static int cmd648_pre_reset(struct ata_port *ap)
/* Check cable detect bits */
pci_read_config_byte(pdev, BMIDECSR, &r);
if (r & (1 << ap->port_no))
- ap->cbl = ATA_CBL_PATA80;
- else
- ap->cbl = ATA_CBL_PATA40;
-
- return ata_std_prereset(ap);
-}
-
-static void cmd64x_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, cmd64x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-static void cmd648_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, cmd648_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+ return ATA_CBL_PATA80;
+ return ATA_CBL_PATA40;
}
/**
@@ -304,8 +285,9 @@ static struct ata_port_operations cmd64x_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cmd64x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -338,8 +320,9 @@ static struct ata_port_operations cmd646r1_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cmd64x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -372,8 +355,9 @@ static struct ata_port_operations cmd648_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cmd648_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = cmd648_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 55cc293e7487..79bef0d1fad3 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -139,18 +139,6 @@ static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
cs5520_set_timings(ap, adev, adev->pio_mode);
}
-
-static int cs5520_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-static void cs5520_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, cs5520_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
static struct scsi_host_template cs5520_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -186,8 +174,9 @@ static struct ata_port_operations cs5520_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cs5520_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -197,7 +186,6 @@ static struct ata_port_operations cs5520_port_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -205,91 +193,104 @@ static struct ata_port_operations cs5520_port_ops = {
.port_start = ata_port_start,
};
-static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ struct ata_port_info pi = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f,
+ .port_ops = &cs5520_port_ops,
+ };
+ const struct ata_port_info *ppi[2];
u8 pcicfg;
- void __iomem *iomap[5];
- static struct ata_probe_ent probe[2];
- int ports = 0;
+ void *iomap[5];
+ struct ata_host *host;
+ struct ata_ioports *ioaddr;
+ int i, rc;
/* IDE port enable bits */
- pci_read_config_byte(dev, 0x60, &pcicfg);
+ pci_read_config_byte(pdev, 0x60, &pcicfg);
/* Check if the ATA ports are enabled */
if ((pcicfg & 3) == 0)
return -ENODEV;
+ ppi[0] = ppi[1] = &ata_dummy_port_info;
+ if (pcicfg & 1)
+ ppi[0] = &pi;
+ if (pcicfg & 2)
+ ppi[1] = &pi;
+
if ((pcicfg & 0x40) == 0) {
- printk(KERN_WARNING DRV_NAME ": DMA mode disabled. Enabling.\n");
- pci_write_config_byte(dev, 0x60, pcicfg | 0x40);
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "DMA mode disabled. Enabling.\n");
+ pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
}
+ pi.mwdma_mask = id->driver_data;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+ if (!host)
+ return -ENOMEM;
+
/* Perform set up for DMA */
- if (pci_enable_device_bars(dev, 1<<2)) {
+ if (pci_enable_device_bars(pdev, 1<<2)) {
printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n");
return -ENODEV;
}
- pci_set_master(dev);
- if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.\n");
return -ENODEV;
}
- if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) {
+ if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n");
return -ENODEV;
}
- /* Map IO ports */
- iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8);
- iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1);
- iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8);
- iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1);
- iomap[4] = pcim_iomap(dev, 2, 0);
+ /* Map IO ports and initialize host accordingly */
+ iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8);
+ iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1);
+ iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8);
+ iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1);
+ iomap[4] = pcim_iomap(pdev, 2, 0);
if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
return -ENOMEM;
- /* We have to do our own plumbing as the PCI setup for this
- chipset is non-standard so we can't punt to the libata code */
-
- INIT_LIST_HEAD(&probe[0].node);
- probe[0].dev = pci_dev_to_dev(dev);
- probe[0].port_ops = &cs5520_port_ops;
- probe[0].sht = &cs5520_sht;
- probe[0].pio_mask = 0x1F;
- probe[0].mwdma_mask = id->driver_data;
- probe[0].irq = 14;
- probe[0].irq_flags = 0;
- probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
- probe[0].n_ports = 1;
- probe[0].port[0].cmd_addr = iomap[0];
- probe[0].port[0].ctl_addr = iomap[1];
- probe[0].port[0].altstatus_addr = iomap[1];
- probe[0].port[0].bmdma_addr = iomap[4];
-
- /* The secondary lurks at different addresses but is otherwise
- the same beastie */
-
- probe[1] = probe[0];
- INIT_LIST_HEAD(&probe[1].node);
- probe[1].irq = 15;
- probe[1].port[0].cmd_addr = iomap[2];
- probe[1].port[0].ctl_addr = iomap[3];
- probe[1].port[0].altstatus_addr = iomap[3];
- probe[1].port[0].bmdma_addr = iomap[4] + 8;
-
- /* Let libata fill in the port details */
- ata_std_ports(&probe[0].port[0]);
- ata_std_ports(&probe[1].port[0]);
-
- /* Now add the ports that are active */
- if (pcicfg & 1)
- ports += ata_device_add(&probe[0]);
- if (pcicfg & 2)
- ports += ata_device_add(&probe[1]);
- if (ports)
- return 0;
- return -ENODEV;
+ ioaddr = &host->ports[0]->ioaddr;
+ ioaddr->cmd_addr = iomap[0];
+ ioaddr->ctl_addr = iomap[1];
+ ioaddr->altstatus_addr = iomap[1];
+ ioaddr->bmdma_addr = iomap[4];
+ ata_std_ports(ioaddr);
+
+ ioaddr = &host->ports[1]->ioaddr;
+ ioaddr->cmd_addr = iomap[2];
+ ioaddr->ctl_addr = iomap[3];
+ ioaddr->altstatus_addr = iomap[3];
+ ioaddr->bmdma_addr = iomap[4] + 8;
+ ata_std_ports(ioaddr);
+
+ /* activate the host */
+ pci_set_master(pdev);
+ rc = ata_host_start(host);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < 2; i++) {
+ static const int irq[] = { 14, 15 };
+ struct ata_port *ap = host->ports[0];
+
+ if (ata_port_is_dummy(ap))
+ continue;
+
+ rc = devm_request_irq(&pdev->dev, irq[ap->port_no],
+ ata_interrupt, 0, DRV_NAME, host);
+ if (rc)
+ return rc;
+ }
+
+ return ata_host_register(host, &cs5520_sht);
}
/**
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index db63e80e608b..29642d5ee189 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -160,18 +160,6 @@ static unsigned int cs5530_qc_issue_prot(struct ata_queued_cmd *qc)
return ata_qc_issue_prot(qc);
}
-static int cs5530_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-static void cs5530_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, cs5530_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-
static struct scsi_host_template cs5530_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -213,8 +201,9 @@ static struct ata_port_operations cs5530_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cs5530_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = cs5530_qc_issue_prot,
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 1572e5c9031a..08cccc9c659b 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -70,36 +70,23 @@
#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,
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index f69dde5f7066..6ec049c3b1dc 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -41,17 +41,6 @@ enum {
CY82_INDEX_TIMEOUT = 0x32
};
-static int cy82c693_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-static void cy82c693_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, cy82c693_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
/**
* cy82c693_set_piomode - set initial PIO mode data
* @ap: ATA interface
@@ -156,8 +145,9 @@ static struct ata_port_operations cy82c693_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cy82c693_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index dac7a6554f6c..a3216850bba1 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -22,10 +22,10 @@
#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);
}
@@ -67,6 +60,25 @@ static void efar_error_handler(struct ata_port *ap)
}
/**
+ * efar_cable_detect - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection for the EFAR ATA interface. This is
+ * different to the PIIX arrangement
+ */
+
+static int efar_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ pci_read_config_byte(pdev, 0x47, &tmp);
+ if (tmp & (2 >> ap->port_no))
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+}
+
+/**
* efar_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
* @adev: um
@@ -256,6 +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,
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index baf35f876030..93cfa6d300a5 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -27,7 +27,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt366"
-#define DRV_VERSION "0.6.0"
+#define DRV_VERSION "0.6.1"
struct hpt_clock {
u8 xfer_speed;
@@ -169,13 +169,12 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, cons
/**
* hpt366_filter - mode selection filter
- * @ap: ATA interface
* @adev: ATA device
*
* Block UDMA on devices that cause trouble with this controller.
*/
-static unsigned long hpt366_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask)
{
if (adev->class == ATA_DEV_ATA) {
if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
@@ -185,7 +184,7 @@ static unsigned long hpt366_filter(const struct ata_port *ap, struct ata_device
if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4))
mask &= ~(0x0F << ATA_SHIFT_UDMA);
}
- return ata_pci_default_filter(ap, adev, mask);
+ return ata_pci_default_filter(adev, mask);
}
/**
@@ -210,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,
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index f331eeeafa0f..41d831296347 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -8,6 +8,7 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
+ * Portions Copyright (C) 2005-2006 MontaVista Software, Inc.
*
* TODO
* PLL mode
@@ -25,7 +26,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt37x"
-#define DRV_VERSION "0.6.0"
+#define DRV_VERSION "0.6.5"
struct hpt_clock {
u8 xfer_speed;
@@ -61,201 +62,75 @@ struct hpt_chip {
* 31 FIFO enable.
*/
-/* from highpoint documentation. these are old values */
-static const struct hpt_clock hpt370_timings_33[] = {
-/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */
- { XFER_UDMA_5, 0x16454e31 },
- { XFER_UDMA_4, 0x16454e31 },
- { XFER_UDMA_3, 0x166d4e31 },
- { XFER_UDMA_2, 0x16494e31 },
- { XFER_UDMA_1, 0x164d4e31 },
- { XFER_UDMA_0, 0x16514e31 },
-
- { XFER_MW_DMA_2, 0x26514e21 },
- { XFER_MW_DMA_1, 0x26514e33 },
- { XFER_MW_DMA_0, 0x26514e97 },
-
- { XFER_PIO_4, 0x06514e21 },
- { XFER_PIO_3, 0x06514e22 },
- { XFER_PIO_2, 0x06514e33 },
- { XFER_PIO_1, 0x06914e43 },
- { XFER_PIO_0, 0x06914e57 },
- { 0, 0x06514e57 }
+static struct hpt_clock hpt37x_timings_33[] = {
+ { XFER_UDMA_6, 0x12446231 }, /* 0x12646231 ?? */
+ { XFER_UDMA_5, 0x12446231 },
+ { XFER_UDMA_4, 0x12446231 },
+ { XFER_UDMA_3, 0x126c6231 },
+ { XFER_UDMA_2, 0x12486231 },
+ { XFER_UDMA_1, 0x124c6233 },
+ { XFER_UDMA_0, 0x12506297 },
+
+ { XFER_MW_DMA_2, 0x22406c31 },
+ { XFER_MW_DMA_1, 0x22406c33 },
+ { XFER_MW_DMA_0, 0x22406c97 },
+
+ { XFER_PIO_4, 0x06414e31 },
+ { XFER_PIO_3, 0x06414e42 },
+ { XFER_PIO_2, 0x06414e53 },
+ { XFER_PIO_1, 0x06814e93 },
+ { XFER_PIO_0, 0x06814ea7 }
};
-static const struct hpt_clock hpt370_timings_66[] = {
- { XFER_UDMA_5, 0x14846231 },
- { XFER_UDMA_4, 0x14886231 },
- { XFER_UDMA_3, 0x148c6231 },
- { XFER_UDMA_2, 0x148c6231 },
- { XFER_UDMA_1, 0x14906231 },
- { XFER_UDMA_0, 0x14986231 },
-
- { XFER_MW_DMA_2, 0x26514e21 },
- { XFER_MW_DMA_1, 0x26514e33 },
- { XFER_MW_DMA_0, 0x26514e97 },
-
- { XFER_PIO_4, 0x06514e21 },
- { XFER_PIO_3, 0x06514e22 },
- { XFER_PIO_2, 0x06514e33 },
- { XFER_PIO_1, 0x06914e43 },
- { XFER_PIO_0, 0x06914e57 },
- { 0, 0x06514e57 }
+static struct hpt_clock hpt37x_timings_50[] = {
+ { XFER_UDMA_6, 0x12848242 },
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a }
};
-/* these are the current (4 sep 2001) timings from highpoint */
-static const struct hpt_clock hpt370a_timings_33[] = {
- { XFER_UDMA_5, 0x12446231 },
- { XFER_UDMA_4, 0x12446231 },
- { XFER_UDMA_3, 0x126c6231 },
- { XFER_UDMA_2, 0x12486231 },
- { XFER_UDMA_1, 0x124c6233 },
- { XFER_UDMA_0, 0x12506297 },
-
- { XFER_MW_DMA_2, 0x22406c31 },
- { XFER_MW_DMA_1, 0x22406c33 },
- { XFER_MW_DMA_0, 0x22406c97 },
-
- { XFER_PIO_4, 0x06414e31 },
- { XFER_PIO_3, 0x06414e42 },
- { XFER_PIO_2, 0x06414e53 },
- { XFER_PIO_1, 0x06814e93 },
- { XFER_PIO_0, 0x06814ea7 },
- { 0, 0x06814ea7 }
+static struct hpt_clock hpt37x_timings_66[] = {
+ { XFER_UDMA_6, 0x1c869c62 },
+ { XFER_UDMA_5, 0x1cae9c62 }, /* 0x1c8a9c62 */
+ { XFER_UDMA_4, 0x1c8a9c62 },
+ { XFER_UDMA_3, 0x1c8e9c62 },
+ { XFER_UDMA_2, 0x1c929c62 },
+ { XFER_UDMA_1, 0x1c9a9c62 },
+ { XFER_UDMA_0, 0x1c829c62 },
+
+ { XFER_MW_DMA_2, 0x2c829c62 },
+ { XFER_MW_DMA_1, 0x2c829c66 },
+ { XFER_MW_DMA_0, 0x2c829d2e },
+
+ { XFER_PIO_4, 0x0c829c62 },
+ { XFER_PIO_3, 0x0c829c84 },
+ { XFER_PIO_2, 0x0c829ca6 },
+ { XFER_PIO_1, 0x0d029d26 },
+ { XFER_PIO_0, 0x0d029d5e }
};
-/* 2x 33MHz timings */
-static const struct hpt_clock hpt370a_timings_66[] = {
- { XFER_UDMA_5, 0x1488e673 },
- { XFER_UDMA_4, 0x1488e673 },
- { XFER_UDMA_3, 0x1498e673 },
- { XFER_UDMA_2, 0x1490e673 },
- { XFER_UDMA_1, 0x1498e677 },
- { XFER_UDMA_0, 0x14a0e73f },
-
- { XFER_MW_DMA_2, 0x2480fa73 },
- { XFER_MW_DMA_1, 0x2480fa77 },
- { XFER_MW_DMA_0, 0x2480fb3f },
-
- { XFER_PIO_4, 0x0c82be73 },
- { XFER_PIO_3, 0x0c82be95 },
- { XFER_PIO_2, 0x0c82beb7 },
- { XFER_PIO_1, 0x0d02bf37 },
- { XFER_PIO_0, 0x0d02bf5f },
- { 0, 0x0d02bf5f }
-};
-
-static const struct hpt_clock hpt370a_timings_50[] = {
- { XFER_UDMA_5, 0x12848242 },
- { XFER_UDMA_4, 0x12ac8242 },
- { XFER_UDMA_3, 0x128c8242 },
- { XFER_UDMA_2, 0x120c8242 },
- { XFER_UDMA_1, 0x12148254 },
- { XFER_UDMA_0, 0x121882ea },
-
- { XFER_MW_DMA_2, 0x22808242 },
- { XFER_MW_DMA_1, 0x22808254 },
- { XFER_MW_DMA_0, 0x228082ea },
-
- { XFER_PIO_4, 0x0a81f442 },
- { XFER_PIO_3, 0x0a81f443 },
- { XFER_PIO_2, 0x0a81f454 },
- { XFER_PIO_1, 0x0ac1f465 },
- { XFER_PIO_0, 0x0ac1f48a },
- { 0, 0x0ac1f48a }
-};
-
-static const struct hpt_clock hpt372_timings_33[] = {
- { XFER_UDMA_6, 0x1c81dc62 },
- { XFER_UDMA_5, 0x1c6ddc62 },
- { XFER_UDMA_4, 0x1c8ddc62 },
- { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */
- { XFER_UDMA_2, 0x1c91dc62 },
- { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */
- { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */
-
- { XFER_MW_DMA_2, 0x2c829262 },
- { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */
- { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */
-
- { XFER_PIO_4, 0x0c829c62 },
- { XFER_PIO_3, 0x0c829c84 },
- { XFER_PIO_2, 0x0c829ca6 },
- { XFER_PIO_1, 0x0d029d26 },
- { XFER_PIO_0, 0x0d029d5e },
- { 0, 0x0d029d5e }
-};
-
-static const struct hpt_clock hpt372_timings_50[] = {
- { XFER_UDMA_5, 0x12848242 },
- { XFER_UDMA_4, 0x12ac8242 },
- { XFER_UDMA_3, 0x128c8242 },
- { XFER_UDMA_2, 0x120c8242 },
- { XFER_UDMA_1, 0x12148254 },
- { XFER_UDMA_0, 0x121882ea },
-
- { XFER_MW_DMA_2, 0x22808242 },
- { XFER_MW_DMA_1, 0x22808254 },
- { XFER_MW_DMA_0, 0x228082ea },
-
- { XFER_PIO_4, 0x0a81f442 },
- { XFER_PIO_3, 0x0a81f443 },
- { XFER_PIO_2, 0x0a81f454 },
- { XFER_PIO_1, 0x0ac1f465 },
- { XFER_PIO_0, 0x0ac1f48a },
- { 0, 0x0a81f443 }
-};
-
-static const struct hpt_clock hpt372_timings_66[] = {
- { XFER_UDMA_6, 0x1c869c62 },
- { XFER_UDMA_5, 0x1cae9c62 },
- { XFER_UDMA_4, 0x1c8a9c62 },
- { XFER_UDMA_3, 0x1c8e9c62 },
- { XFER_UDMA_2, 0x1c929c62 },
- { XFER_UDMA_1, 0x1c9a9c62 },
- { XFER_UDMA_0, 0x1c829c62 },
-
- { XFER_MW_DMA_2, 0x2c829c62 },
- { XFER_MW_DMA_1, 0x2c829c66 },
- { XFER_MW_DMA_0, 0x2c829d2e },
-
- { XFER_PIO_4, 0x0c829c62 },
- { XFER_PIO_3, 0x0c829c84 },
- { XFER_PIO_2, 0x0c829ca6 },
- { XFER_PIO_1, 0x0d029d26 },
- { XFER_PIO_0, 0x0d029d5e },
- { 0, 0x0d029d26 }
-};
-
-static const struct hpt_clock hpt374_timings_33[] = {
- { XFER_UDMA_6, 0x12808242 },
- { XFER_UDMA_5, 0x12848242 },
- { XFER_UDMA_4, 0x12ac8242 },
- { XFER_UDMA_3, 0x128c8242 },
- { XFER_UDMA_2, 0x120c8242 },
- { XFER_UDMA_1, 0x12148254 },
- { XFER_UDMA_0, 0x121882ea },
-
- { XFER_MW_DMA_2, 0x22808242 },
- { XFER_MW_DMA_1, 0x22808254 },
- { XFER_MW_DMA_0, 0x228082ea },
-
- { XFER_PIO_4, 0x0a81f442 },
- { XFER_PIO_3, 0x0a81f443 },
- { XFER_PIO_2, 0x0a81f454 },
- { XFER_PIO_1, 0x0ac1f465 },
- { XFER_PIO_0, 0x0ac1f48a },
- { 0, 0x06814e93 }
-};
static const struct hpt_chip hpt370 = {
"HPT370",
48,
{
- hpt370_timings_33,
+ hpt37x_timings_33,
NULL,
NULL,
- hpt370_timings_66
+ NULL
}
};
@@ -263,10 +138,10 @@ static const struct hpt_chip hpt370a = {
"HPT370A",
48,
{
- hpt370a_timings_33,
+ hpt37x_timings_33,
NULL,
- hpt370a_timings_50,
- hpt370a_timings_66
+ hpt37x_timings_50,
+ NULL
}
};
@@ -274,10 +149,10 @@ static const struct hpt_chip hpt372 = {
"HPT372",
55,
{
- hpt372_timings_33,
+ hpt37x_timings_33,
NULL,
- hpt372_timings_50,
- hpt372_timings_66
+ hpt37x_timings_50,
+ hpt37x_timings_66
}
};
@@ -285,10 +160,10 @@ static const struct hpt_chip hpt302 = {
"HPT302",
66,
{
- hpt372_timings_33,
+ hpt37x_timings_33,
NULL,
- hpt372_timings_50,
- hpt372_timings_66
+ hpt37x_timings_50,
+ hpt37x_timings_66
}
};
@@ -296,10 +171,10 @@ static const struct hpt_chip hpt371 = {
"HPT371",
66,
{
- hpt372_timings_33,
+ hpt37x_timings_33,
NULL,
- hpt372_timings_50,
- hpt372_timings_66
+ hpt37x_timings_50,
+ hpt37x_timings_66
}
};
@@ -307,10 +182,10 @@ static const struct hpt_chip hpt372a = {
"HPT372A",
66,
{
- hpt372_timings_33,
+ hpt37x_timings_33,
NULL,
- hpt372_timings_50,
- hpt372_timings_66
+ hpt37x_timings_50,
+ hpt37x_timings_66
}
};
@@ -318,7 +193,7 @@ static const struct hpt_chip hpt374 = {
"HPT374",
48,
{
- hpt374_timings_33,
+ hpt37x_timings_33,
NULL,
NULL,
NULL
@@ -397,13 +272,12 @@ static const char *bad_ata100_5[] = {
/**
* hpt370_filter - mode selection filter
- * @ap: ATA interface
* @adev: ATA device
*
* Block UDMA on devices that cause trouble with this controller.
*/
-static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask)
{
if (adev->class == ATA_DEV_ATA) {
if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
@@ -411,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);
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 65f2e180e7fa..6a34521b9e01 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -8,10 +8,10 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
+ * Portions Copyright (C) 2005-2006 MontaVista Software, Inc.
*
*
* TODO
- * 371N
* Work out best PLL policy
*/
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x2n"
-#define DRV_VERSION "0.3.2"
+#define DRV_VERSION "0.3.3"
enum {
HPT_PCI_FAST = (1 << 31),
@@ -115,14 +115,13 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
}
/**
- * hpt3x2n_pre_reset - reset the hpt3x2n bus
- * @ap: ATA port to reset
+ * hpt3x2n_cable_detect - Detect the cable type
+ * @ap: ATA port to detect on
*
- * Perform the initial reset handling for the 3x2n series controllers.
- * Reset the hardware and state machine, obtain the cable type.
+ * Return the cable type attached to this port
*/
-static int hpt3xn_pre_reset(struct ata_port *ap)
+static int hpt3x2n_cable_detect(struct ata_port *ap)
{
u8 scr2, ata66;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -135,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), },
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 813485c8526c..ac28ec8c50aa 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -25,25 +25,6 @@
#define DRV_NAME "pata_hpt3x3"
#define DRV_VERSION "0.4.2"
-static int hpt3x3_probe_init(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-/**
- * hpt3x3_probe_reset - reset the hpt3x3 bus
- * @ap: ATA port to reset
- *
- * Perform the housekeeping when doing an ATA bus reeset. We just
- * need to force the cable type.
- */
-
-static void hpt3x3_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, hpt3x3_probe_init, ata_std_softreset, NULL, ata_std_postreset);
-}
-
/**
* hpt3x3_set_piomode - PIO setup
* @ap: ATA interface
@@ -139,8 +120,9 @@ static struct ata_port_operations hpt3x3_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = hpt3x3_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index 1a61cc891741..d042efdfbac4 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -49,13 +49,13 @@ static struct ata_port_operations isapnp_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -74,8 +74,10 @@ static struct ata_port_operations isapnp_port_ops = {
static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id)
{
- struct ata_probe_ent ae;
+ struct ata_host *host;
+ struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
+ int rc;
if (pnp_port_valid(idev, 0) == 0)
return -ENODEV;
@@ -84,34 +86,36 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
if (pnp_irq_valid(idev, 0) == 0)
return -ENODEV;
+ /* allocate host */
+ host = ata_host_alloc(&idev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8);
if (!cmd_addr)
return -ENOMEM;
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &idev->dev;
- ae.port_ops = &isapnp_port_ops;
- ae.sht = &isapnp_sht;
- ae.n_ports = 1;
- ae.pio_mask = 1; /* ISA so PIO 0 cycles */
- ae.irq = pnp_irq(idev, 0);
- ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_SLAVE_POSS;
- ae.port[0].cmd_addr = cmd_addr;
+ ap = host->ports[0];
+
+ ap->ops = &isapnp_port_ops;
+ ap->pio_mask = 1;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+
+ ap->ioaddr.cmd_addr = cmd_addr;
if (pnp_port_valid(idev, 1) == 0) {
ctl_addr = devm_ioport_map(&idev->dev,
pnp_port_start(idev, 1), 1);
- ae.port[0].altstatus_addr = ctl_addr;
- ae.port[0].ctl_addr = ctl_addr;
- ae.port_flags |= ATA_FLAG_SRST;
+ ap->ioaddr.altstatus_addr = ctl_addr;
+ ap->ioaddr.ctl_addr = ctl_addr;
}
- ata_std_ports(&ae.port[0]);
- if (ata_device_add(&ae) == 0)
- return -ENODEV;
- return 0;
+ ata_std_ports(&ap->ioaddr);
+
+ /* activate */
+ return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0,
+ &isapnp_sht);
}
/**
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index ea734701555e..011306ef8334 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -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:
@@ -63,9 +54,27 @@ static void it8213_error_handler(struct ata_port *ap)
}
/**
+ * it8213_cable_detect - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection for the 8213 ATA interface. This is
+ * different to the PIIX arrangement
+ */
+
+static int it8213_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+ pci_read_config_byte(pdev, 0x42, &tmp);
+ if (tmp & 2) /* The initial docs are incorrect */
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+}
+
+/**
* it8213_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
- * @adev: um
+ * @adev: Device whose timings we are configuring
*
* Set PIO mode for device, in host controller PCI config space.
*
@@ -268,6 +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,
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 35ecb2ba067b..f1f8cec8c224 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -80,7 +80,7 @@
#define DRV_NAME "pata_it821x"
-#define DRV_VERSION "0.3.4"
+#define DRV_VERSION "0.3.6"
struct it821x_dev
{
@@ -113,31 +113,6 @@ struct it821x_dev
static int it8212_noraid;
/**
- * it821x_pre_reset - probe
- * @ap: ATA port
- *
- * Set the cable type
- */
-
-static int it821x_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
-}
-
-/**
- * it821x_error_handler - probe/reset
- * @ap: ATA port
- *
- * Set the cable type and trigger a probe
- */
-
-static void it821x_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, it821x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-/**
* it821x_program - program the PIO/MWDMA registers
* @ap: ATA port
* @adev: Device to program
@@ -520,7 +495,6 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused
/**
* it821x_dev_config - Called each device identify
- * @ap: ATA port
* @adev: Device that has just been identified
*
* Perform the initial setup needed for each device that is chip
@@ -531,7 +505,7 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused
* basically we need to filter commands for this chip.
*/
-static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev)
+static void it821x_dev_config(struct ata_device *adev)
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -667,8 +641,9 @@ static struct ata_port_operations it821x_smart_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = it821x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -703,8 +678,9 @@ static struct ata_port_operations it821x_passthru_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = it821x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = it821x_passthru_bmdma_start,
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index c6f0e1927551..420c343e5711 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -129,8 +129,8 @@ static struct ata_port_operations ixp4xx_port_ops = {
.qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout,
.data_xfer = ixp4xx_mmio_data_xfer,
+ .cable_detect = ata_cable_40wire,
- .irq_handler = ata_interrupt,
.irq_clear = ixp4xx_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -173,12 +173,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
{
- int ret;
unsigned int irq;
struct resource *cs0, *cs1;
- struct ata_probe_ent ae;
-
+ struct ata_host *host;
+ struct ata_port *ap;
struct ixp4xx_pata_data *data = pdev->dev.platform_data;
+ int rc;
cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -186,6 +186,12 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
if (!cs0 || !cs1)
return -EINVAL;
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
@@ -199,32 +205,22 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
*data->cs0_cfg = data->cs0_bits;
*data->cs1_cfg = data->cs1_bits;
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
+ ap = host->ports[0];
- ae.dev = &pdev->dev;
- ae.port_ops = &ixp4xx_port_ops;
- ae.sht = &ixp4xx_sht;
- ae.n_ports = 1;
- ae.pio_mask = 0x1f; /* PIO4 */
- ae.irq = irq;
- ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY
- | ATA_FLAG_NO_ATAPI | ATA_FLAG_SRST;
+ ap->ops = &ixp4xx_port_ops;
+ ap->pio_mask = 0x1f; /* PIO4 */
+ ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
/* run in polling mode if no irq has been assigned */
if (!irq)
- ae.port_flags |= ATA_FLAG_PIO_POLLING;
+ ap->flags |= ATA_FLAG_PIO_POLLING;
- ixp4xx_setup_port(&ae.port[0], data);
+ ixp4xx_setup_port(&ap->ioaddr, data);
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
- ret = ata_device_add(&ae);
- if (ret == 0)
- return -ENODEV;
-
- return 0;
+ /* activate host */
+ return ata_host_activate(host, irq, ata_interrupt, 0, &ixp4xx_sht);
}
static __devexit int ixp4xx_pata_remove(struct platform_device *dev)
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 86fbcd6a742b..707099291e01 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -162,6 +162,7 @@ static struct ata_port_operations simple_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -185,6 +186,7 @@ static struct ata_port_operations legacy_port_ops = {
.check_status = ata_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .cable_detect = ata_cable_40wire,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -305,6 +307,7 @@ static struct ata_port_operations pdc20230_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -360,6 +363,7 @@ static struct ata_port_operations ht6560a_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -426,6 +430,7 @@ static struct ata_port_operations ht6560b_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -547,6 +552,7 @@ static struct ata_port_operations opti82c611a_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -680,6 +686,7 @@ static struct ata_port_operations opti82c46x_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = opti82c46x_qc_issue_prot,
@@ -709,7 +716,8 @@ static struct ata_port_operations opti82c46x_port_ops = {
static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq)
{
struct legacy_data *ld = &legacy_data[nr_legacy_host];
- struct ata_probe_ent ae;
+ struct ata_host *host;
+ struct ata_port *ap;
struct platform_device *pdev;
struct ata_port_operations *ops = &legacy_port_ops;
void __iomem *io_addr, *ctrl_addr;
@@ -791,24 +799,23 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
if (ops == &legacy_port_ops && (autospeed & mask))
ops = &simple_port_ops;
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &pdev->dev;
- ae.port_ops = ops;
- ae.sht = &legacy_sht;
- ae.n_ports = 1;
- ae.pio_mask = pio_modes;
- ae.irq = irq;
- ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST|iordy;
- ae.port[0].cmd_addr = io_addr;
- ae.port[0].altstatus_addr = ctrl_addr;
- ae.port[0].ctl_addr = ctrl_addr;
- ata_std_ports(&ae.port[0]);
- ae.private_data = ld;
-
- ret = -ENODEV;
- if (!ata_device_add(&ae))
+ ret = -ENOMEM;
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ goto fail;
+ ap = host->ports[0];
+
+ ap->ops = ops;
+ ap->pio_mask = pio_modes;
+ ap->flags |= ATA_FLAG_SLAVE_POSS | iordy;
+ ap->ioaddr.cmd_addr = io_addr;
+ ap->ioaddr.altstatus_addr = ctrl_addr;
+ ap->ioaddr.ctl_addr = ctrl_addr;
+ ata_std_ports(&ap->ioaddr);
+ ap->private_data = ld;
+
+ ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
+ if (ret)
goto fail;
legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 6dd7c4ef3e66..d9b94a1b6954 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -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,
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 882c36eaf293..9587a89f9683 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -24,7 +24,7 @@
#define DRV_NAME "mpc52xx_ata"
-#define DRV_VERSION "0.1.0"
+#define DRV_VERSION "0.1.0ac2"
/* Private structures used by the driver */
@@ -297,38 +297,37 @@ static struct ata_port_operations mpc52xx_ata_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = mpc52xx_ata_error_handler,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
-static struct ata_probe_ent mpc52xx_ata_probe_ent = {
- .port_ops = &mpc52xx_ata_port_ops,
- .sht = &mpc52xx_ata_sht,
- .n_ports = 1,
- .pio_mask = 0x1f, /* Up to PIO4 */
- .mwdma_mask = 0x00, /* No MWDMA */
- .udma_mask = 0x00, /* No UDMA */
- .port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
- .irq_flags = 0,
-};
-
static int __devinit
mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
{
- struct ata_probe_ent *ae = &mpc52xx_ata_probe_ent;
- struct ata_ioports *aio = &ae->port[0];
- int rv;
-
- INIT_LIST_HEAD(&ae->node);
- ae->dev = dev;
- ae->irq = priv->ata_irq;
-
+ struct ata_host *host;
+ struct ata_port *ap;
+ struct ata_ioports *aio;
+ int rc;
+
+ host = ata_host_alloc(dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ ap = host->ports[0];
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+ ap->pio_mask = 0x1f; /* Up to PIO4 */
+ ap->mwdma_mask = 0x00; /* No MWDMA */
+ ap->udma_mask = 0x00; /* No UDMA */
+ ap->ops = &mpc52xx_ata_port_ops;
+ host->private_data = priv;
+
+ aio = &ap->ioaddr;
aio->cmd_addr = NULL; /* Don't have a classic reg block */
aio->altstatus_addr = &priv->ata_regs->tf_control;
aio->ctl_addr = &priv->ata_regs->tf_control;
@@ -343,11 +342,9 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
aio->status_addr = &priv->ata_regs->tf_command;
aio->command_addr = &priv->ata_regs->tf_command;
- ae->private_data = priv;
-
- rv = ata_device_add(ae);
-
- return rv ? 0 : -EINVAL;
+ /* activate host */
+ return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0,
+ &mpc52xx_ata_sht);
}
static struct mpc52xx_ata_priv *
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 4abe45ac19a2..987c5fafab08 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_mpiix"
-#define DRV_VERSION "0.7.5"
+#define DRV_VERSION "0.7.6"
enum {
IDETIM = 0x6C, /* IDE control register */
@@ -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[] = {
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index 38f99b38a5ea..dbba5b77d79c 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -16,33 +16,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_netcell"
-#define DRV_VERSION "0.1.6"
-
-/**
- * netcell_probe_init - check for 40/80 pin
- * @ap: Port
- *
- * Cables are handled by the RAID controller. Report 80 pin.
- */
-
-static int netcell_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
-}
-
-/**
- * netcell_probe_reset - Probe specified port on PATA host controller
- * @ap: Port to probe
- *
- * LOCKING:
- * None (inherited from caller).
- */
-
-static void netcell_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, netcell_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
+#define DRV_VERSION "0.1.7"
/* No PIO or DMA methods needed for this device */
@@ -81,8 +55,9 @@ static const struct ata_port_operations netcell_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = netcell_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_80wire,
/* BMDMA handling is PCI ATA format, use helpers */
.bmdma_setup = ata_bmdma_setup,
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 9944a28daa9c..078aeda9cf8d 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -28,13 +28,13 @@
#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,
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index da68cd19efd6..dea4690340d1 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -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,
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 3fd3a35c2241..13b63e21838d 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -34,7 +34,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_opti"
-#define DRV_VERSION "0.2.8"
+#define DRV_VERSION "0.2.9"
enum {
READ_REG = 0, /* index of Read cycle timing register */
@@ -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,
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 9764907e8a13..b70e04c144df 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -33,7 +33,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_optidma"
-#define DRV_VERSION "0.2.4"
+#define DRV_VERSION "0.3.2"
enum {
READ_REG = 0, /* index of Read cycle timing register */
@@ -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,
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 103720f873c8..75dc84797ff3 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@
#define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.3.0"
+#define DRV_VERSION "0.3.1"
/*
* Private data structure to glue stuff together
@@ -54,6 +54,39 @@ struct ata_pcmcia_info {
dev_node_t node;
};
+/**
+ * pcmcia_set_mode - PCMCIA specific mode setup
+ * @ap: Port
+ * @r_failed_dev: Return pointer for failed device
+ *
+ * Perform the tuning and setup of the devices and timings, which
+ * for PCMCIA is the same as any other controller. We wrap it however
+ * as we need to spot hardware with incorrect or missing master/slave
+ * decode, which alas is embarrassingly common in the PC world
+ */
+
+static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *master = &ap->device[0];
+ struct ata_device *slave = &ap->device[1];
+
+ if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
+ return ata_do_set_mode(ap, r_failed_dev);
+
+ if (memcmp(master->id + ATA_ID_FW_REV, slave->id + ATA_ID_FW_REV,
+ ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0)
+ {
+ /* Suspicious match, but could be two cards from
+ the same vendor - check serial */
+ if (memcmp(master->id + ATA_ID_SERNO, slave->id + ATA_ID_SERNO,
+ ATA_ID_SERNO_LEN) == 0 && master->id[ATA_ID_SERNO] >> 8) {
+ ata_dev_printk(slave, KERN_WARNING, "is a ghost device, ignoring.\n");
+ ata_dev_disable(slave);
+ }
+ }
+ return ata_do_set_mode(ap, r_failed_dev);
+}
+
static struct scsi_host_template pcmcia_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -73,6 +106,7 @@ static struct scsi_host_template pcmcia_sht = {
};
static struct ata_port_operations pcmcia_port_ops = {
+ .set_mode = pcmcia_set_mode,
.port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -84,13 +118,13 @@ static struct ata_port_operations pcmcia_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer_noirq,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -111,7 +145,8 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
static int pcmcia_init_one(struct pcmcia_device *pdev)
{
- struct ata_probe_ent ae;
+ struct ata_host *host;
+ struct ata_port *ap;
struct ata_pcmcia_info *info;
tuple_t tuple;
struct {
@@ -255,24 +290,24 @@ next_entry:
* Having done the PCMCIA plumbing the ATA side is relatively
* sane.
*/
-
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &pdev->dev;
- ae.port_ops = &pcmcia_port_ops;
- ae.sht = &pcmcia_sht;
- ae.n_ports = 1;
- ae.pio_mask = 1; /* ISA so PIO 0 cycles */
- ae.irq = pdev->irq.AssignedIRQ;
- ae.irq_flags = IRQF_SHARED;
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- ae.port[0].cmd_addr = io_addr;
- ae.port[0].altstatus_addr = ctl_addr;
- ae.port[0].ctl_addr = ctl_addr;
- ata_std_ports(&ae.port[0]);
-
- ret = -ENODEV;
- if (ata_device_add(&ae) == 0)
+ ret = -ENOMEM;
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ goto failed;
+ ap = host->ports[0];
+
+ ap->ops = &pcmcia_port_ops;
+ ap->pio_mask = 1; /* ISA so PIO 0 cycles */
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+ ap->ioaddr.cmd_addr = io_addr;
+ ap->ioaddr.altstatus_addr = ctl_addr;
+ ap->ioaddr.ctl_addr = ctl_addr;
+ ata_std_ports(&ap->ioaddr);
+
+ /* activate */
+ ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
+ IRQF_SHARED, &pcmcia_sht);
+ if (ret)
goto failed;
info->ndev = 1;
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 93bcdadb7be3..a61cbc110688 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_pdc2027x"
-#define DRV_VERSION "0.8"
+#define DRV_VERSION "0.9"
#undef PDC_DEBUG
#ifdef PDC_DEBUG
@@ -66,8 +66,10 @@ static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *e
static void pdc2027x_error_handler(struct ata_port *ap);
static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev);
static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
-static void pdc2027x_post_set_mode(struct ata_port *ap);
static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc);
+static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask);
+static int pdc2027x_cable_detect(struct ata_port *ap);
+static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed);
/*
* ATA Timing Tables based on 133MHz controller clock.
@@ -146,6 +148,7 @@ static struct scsi_host_template pdc2027x_sht = {
static struct ata_port_operations pdc2027x_pata100_ops = {
.port_disable = ata_port_disable,
+ .mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -166,8 +169,8 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = pdc2027x_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = pdc2027x_cable_detect,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -179,7 +182,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.port_disable = ata_port_disable,
.set_piomode = pdc2027x_set_piomode,
.set_dmamode = pdc2027x_set_dmamode,
- .post_set_mode = pdc2027x_post_set_mode,
+ .set_mode = pdc2027x_set_mode,
+ .mode_filter = pdc2027x_mode_filter,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -200,8 +204,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = pdc2027x_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = pdc2027x_cable_detect,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -212,7 +216,6 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
static struct ata_port_info pdc2027x_port_info[] = {
/* PDC_UDMA_100 */
{
- .sht = &pdc2027x_sht,
.flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
ATA_FLAG_MMIO,
.pio_mask = 0x1f, /* pio0-4 */
@@ -222,7 +225,6 @@ static struct ata_port_info pdc2027x_port_info[] = {
},
/* PDC_UDMA_133 */
{
- .sht = &pdc2027x_sht,
.flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
ATA_FLAG_MMIO,
.pio_mask = 0x1f, /* pio0-4 */
@@ -261,7 +263,7 @@ static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *ade
}
/**
- * pdc2027x_pata_cbl_detect - Probe host controller cable detect info
+ * pdc2027x_pata_cable_detect - Probe host controller cable detect info
* @ap: Port for which cable detect info is desired
*
* Read 80c cable indicator from Promise extended register.
@@ -270,7 +272,7 @@ static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *ade
* LOCKING:
* None (inherited from caller).
*/
-static void pdc2027x_cbl_detect(struct ata_port *ap)
+static int pdc2027x_cable_detect(struct ata_port *ap)
{
u32 cgcr;
@@ -281,13 +283,10 @@ static void pdc2027x_cbl_detect(struct ata_port *ap)
PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no);
- ap->cbl = ATA_CBL_PATA80;
- return;
-
+ return ATA_CBL_PATA80;
cbl40:
printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no);
- ap->cbl = ATA_CBL_PATA40;
- ap->udma_mask &= ATA_UDMA_MASK_40C;
+ return ATA_CBL_PATA40;
}
/**
@@ -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);
}
@@ -334,6 +332,32 @@ static void pdc2027x_error_handler(struct ata_port *ap)
}
/**
+ * pdc2720x_mode_filter - mode selection filter
+ * @adev: ATA device
+ * @mask: list of modes proposed
+ *
+ * Block UDMA on devices that cause trouble with this controller.
+ */
+
+static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ if (adev->class != ATA_DEV_ATA || adev->devno == 0 || pair == NULL)
+ return ata_pci_default_filter(adev, mask);
+
+ /* Check for slave of a Maxtor at UDMA6 */
+ ata_id_c_string(pair->id, model_num, ATA_ID_PROD,
+ ATA_ID_PROD_LEN + 1);
+ /* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */
+ if(strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6)
+ mask &= ~ (1 << (6 + ATA_SHIFT_UDMA));
+
+ return ata_pci_default_filter(adev, mask);
+}
+
+/**
* pdc2027x_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port to configure
* @adev: um
@@ -444,17 +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);
}
/**
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 0a1493398913..ee636beb05e1 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -22,45 +22,17 @@
#include <linux/libata.h>
#define DRV_NAME "pata_pdc202xx_old"
-#define DRV_VERSION "0.4.0"
+#define DRV_VERSION "0.4.2"
-/**
- * pdc2024x_pre_reset - probe begin
- * @ap: ATA port
- *
- * Set up cable type and use generic probe init
- */
-
-static int pdc2024x_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-
-static void pdc2024x_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, pdc2024x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-
-static int pdc2026x_pre_reset(struct ata_port *ap)
+static int pdc2026x_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u16 cis;
pci_read_config_word(pdev, 0x50, &cis);
if (cis & (1 << (10 + ap->port_no)))
- ap->cbl = ATA_CBL_PATA80;
- else
- ap->cbl = ATA_CBL_PATA40;
-
- return ata_std_prereset(ap);
-}
-
-static void pdc2026x_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, pdc2026x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+ return ATA_CBL_PATA80;
+ return ATA_CBL_PATA40;
}
/**
@@ -244,7 +216,6 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
/**
* pdc2026x_dev_config - device setup hook
- * @ap: ATA port
* @adev: newly found device
*
* Perform chip specific early setup. We need to lock the transfer
@@ -252,7 +223,7 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
* barf.
*/
-static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev)
+static void pdc2026x_dev_config(struct ata_device *adev)
{
adev->max_sectors = 256;
}
@@ -292,8 +263,9 @@ static struct ata_port_operations pdc2024x_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = pdc2024x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -326,8 +298,9 @@ static struct ata_port_operations pdc2026x_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = pdc2026x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = pdc2026x_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = pdc2026x_bmdma_start,
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 4b82a5435a4e..a0a650c7f272 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -80,13 +80,13 @@ static struct ata_port_operations pata_platform_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer_noirq,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -135,7 +135,8 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
static int __devinit pata_platform_probe(struct platform_device *pdev)
{
struct resource *io_res, *ctl_res;
- struct ata_probe_ent ae;
+ struct ata_host *host;
+ struct ata_port *ap;
unsigned int mmio;
/*
@@ -175,44 +176,41 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
/*
* Now that that's out of the way, wire up the port..
*/
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &pdev->dev;
- ae.port_ops = &pata_platform_port_ops;
- ae.sht = &pata_platform_sht;
- ae.n_ports = 1;
- ae.pio_mask = pio_mask;
- ae.irq = platform_get_irq(pdev, 0);
- ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+ ap = host->ports[0];
+
+ ap->ops = &pata_platform_port_ops;
+ ap->pio_mask = pio_mask;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
/*
* Handle the MMIO case
*/
if (mmio) {
- ae.port[0].cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
+ ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
io_res->end - io_res->start + 1);
- ae.port[0].ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
+ ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
ctl_res->end - ctl_res->start + 1);
} else {
- ae.port[0].cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
+ ap->ioaddr.cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
io_res->end - io_res->start + 1);
- ae.port[0].ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
+ ap->ioaddr.ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
ctl_res->end - ctl_res->start + 1);
}
- if (!ae.port[0].cmd_addr || !ae.port[0].ctl_addr) {
+ if (!ap->ioaddr.cmd_addr || !ap->ioaddr.ctl_addr) {
dev_err(&pdev->dev, "failed to map IO/CTL base\n");
return -ENOMEM;
}
- ae.port[0].altstatus_addr = ae.port[0].ctl_addr;
+ ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
- pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data);
+ pata_platform_setup_port(&ap->ioaddr, pdev->dev.platform_data);
- if (unlikely(ata_device_add(&ae) == 0))
- return -ENODEV;
-
- return 0;
+ /* activate */
+ return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
+ 0, &pata_platform_sht);
}
/**
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index c3810012f3f4..27685ce63ceb 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -183,13 +183,13 @@ static struct ata_port_operations qdi6500_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = qdi_qc_issue_prot,
.data_xfer = qdi_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -211,13 +211,13 @@ static struct ata_port_operations qdi6580_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = qdi_qc_issue_prot,
.data_xfer = qdi_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -238,8 +238,9 @@ static struct ata_port_operations qdi6580_port_ops = {
static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
{
- struct ata_probe_ent ae;
struct platform_device *pdev;
+ struct ata_host *host;
+ struct ata_port *ap;
void __iomem *io_addr, *ctl_addr;
int ret;
@@ -257,34 +258,31 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
if (!io_addr || !ctl_addr)
goto fail;
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &pdev->dev;
+ ret = -ENOMEM;
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ goto fail;
+ ap = host->ports[0];
if (type == 6580) {
- ae.port_ops = &qdi6580_port_ops;
- ae.pio_mask = 0x1F;
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ ap->ops = &qdi6580_port_ops;
+ ap->pio_mask = 0x1F;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
} else {
- ae.port_ops = &qdi6500_port_ops;
- ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
- ATA_FLAG_NO_IORDY;
+ ap->ops = &qdi6500_port_ops;
+ ap->pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */
+ ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
}
- ae.sht = &qdi_sht;
- ae.n_ports = 1;
- ae.irq = irq;
- ae.irq_flags = 0;
- ae.port[0].cmd_addr = io_addr;
- ae.port[0].altstatus_addr = ctl_addr;
- ae.port[0].ctl_addr = ctl_addr;
- ata_std_ports(&ae.port[0]);
+ ap->ioaddr.cmd_addr = io_addr;
+ ap->ioaddr.altstatus_addr = ctl_addr;
+ ap->ioaddr.ctl_addr = ctl_addr;
+ ata_std_ports(&ap->ioaddr);
/*
* Hook in a private data structure per channel
*/
- ae.private_data = &qdi_data[nr_qdi_host];
+ ap->private_data = &qdi_data[nr_qdi_host];
qdi_data[nr_qdi_host].timing = port;
qdi_data[nr_qdi_host].fast = fast;
@@ -292,8 +290,9 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io);
- ret = -ENODEV;
- if (!ata_device_add(&ae))
+ /* activate */
+ ret = ata_host_activate(host, irq, ata_interrupt, 0, &qdi_sht);
+ if (ret)
goto fail;
qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 9a9132c9e331..1c54673e008d 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -24,40 +24,12 @@
#include <linux/ata.h>
#define DRV_NAME "pata_radisys"
-#define DRV_VERSION "0.4.1"
-
-/**
- * radisys_probe_init - probe begin
- * @ap: ATA port
- *
- * Set up cable type and use generic probe init
- */
-
-static int radisys_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
-}
-
-
-/**
- * radisys_pata_error_handler - Probe specified port on PATA host controller
- * @ap: Port to probe
- * @classes:
- *
- * LOCKING:
- * None (inherited from caller).
- */
-
-static void radisys_pata_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, radisys_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
+#define DRV_VERSION "0.4.4"
/**
* radisys_set_piomode - Initialize host controller PATA PIO timings
- * @ap: Port whose timings we are configuring
- * @adev: um
+ * @ap: ATA port
+ * @adev: Device whose timings we are configuring
*
* Set PIO mode for device, in host controller PCI config space.
*
@@ -248,8 +220,9 @@ static const struct ata_port_operations radisys_pata_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = radisys_pata_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index f522daa2a6aa..85c45290eeee 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -25,31 +25,6 @@
/**
- * rz1000_prereset - probe begin
- * @ap: ATA port
- *
- * Set up cable type and use generics
- */
-
-static int rz1000_prereset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-/**
- * rz1000_error_handler - probe reset
- * @ap: ATA port
- *
- * Perform the ATA standard reset sequence
- */
-
-static void rz1000_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, rz1000_prereset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-/**
* rz1000_set_mode - mode setting function
* @ap: ATA interface
* @unused: returned device on set_mode failure
@@ -122,8 +97,9 @@ static struct ata_port_operations rz1000_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = rz1000_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 93b3ed0f9e8a..66e8ff467c8d 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -216,6 +216,7 @@ static struct ata_port_operations sc1200_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index f3ed141fdc0e..5df354d573e8 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -1016,7 +1016,6 @@ static const struct ata_port_operations scc_pata_ops = {
.error_handler = scc_error_handler,
.post_internal_cmd = scc_bmdma_stop,
- .irq_handler = ata_interrupt,
.irq_clear = scc_bmdma_irq_clear,
.irq_on = scc_irq_on,
.irq_ack = scc_irq_ack,
@@ -1027,7 +1026,6 @@ static const struct ata_port_operations scc_pata_ops = {
static struct ata_port_info scc_port_info[] = {
{
- .sht = &scc_sht,
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x00,
@@ -1040,10 +1038,10 @@ static struct ata_port_info scc_port_info[] = {
* scc_reset_controller - initialize SCC PATA controller.
*/
-static int scc_reset_controller(struct ata_probe_ent *probe_ent)
+static int scc_reset_controller(struct ata_host *host)
{
- void __iomem *ctrl_base = probe_ent->iomap[SCC_CTRL_BAR];
- void __iomem *bmid_base = probe_ent->iomap[SCC_BMID_BAR];
+ void __iomem *ctrl_base = host->iomap[SCC_CTRL_BAR];
+ void __iomem *bmid_base = host->iomap[SCC_BMID_BAR];
void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
void __iomem *mode_port = ctrl_base + SCC_CTL_MODEREG;
void __iomem *ecmode_port = ctrl_base + SCC_CTL_ECMODE;
@@ -1104,17 +1102,15 @@ static void scc_setup_ports (struct ata_ioports *ioaddr, void __iomem *base)
ioaddr->command_addr = ioaddr->cmd_addr + SCC_REG_CMD;
}
-static int scc_host_init(struct ata_probe_ent *probe_ent)
+static int scc_host_init(struct ata_host *host)
{
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+ struct pci_dev *pdev = to_pci_dev(host->dev);
int rc;
- rc = scc_reset_controller(probe_ent);
+ rc = scc_reset_controller(host);
if (rc)
return rc;
- probe_ent->n_ports = 1;
-
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
return rc;
@@ -1122,7 +1118,7 @@ static int scc_host_init(struct ata_probe_ent *probe_ent)
if (rc)
return rc;
- scc_setup_ports(&probe_ent->port[0], probe_ent->iomap[SCC_BMID_BAR]);
+ scc_setup_ports(&host->ports[0]->ioaddr, host->iomap[SCC_BMID_BAR]);
pci_set_master(pdev);
@@ -1145,14 +1141,18 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
unsigned int board_idx = (unsigned int) ent->driver_data;
+ const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL };
struct device *dev = &pdev->dev;
- struct ata_probe_ent *probe_ent;
int rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev,
"version " DRV_VERSION "\n");
+ host = ata_port_alloc_pinfo(&pdev->dev, ppi, 1);
+ if (!host)
+ return -ENOMEM;
+
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -1162,33 +1162,14 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent)
- return -ENOMEM;
-
- probe_ent->dev = dev;
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = scc_port_info[board_idx].sht;
- probe_ent->port_flags = scc_port_info[board_idx].flags;
- probe_ent->pio_mask = scc_port_info[board_idx].pio_mask;
- probe_ent->udma_mask = scc_port_info[board_idx].udma_mask;
- probe_ent->port_ops = scc_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- rc = scc_host_init(probe_ent);
+ rc = scc_host_init(host);
if (rc)
return rc;
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &scc_sht);
}
static struct pci_driver scc_pci_driver = {
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 598eef810a74..3956ef26936d 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -1,5 +1,5 @@
/*
- * ata-serverworks.c - Serverworks PATA for new ATA layer
+ * pata_serverworks.c - Serverworks PATA for new ATA layer
* (C) 2005 Red Hat Inc
* Alan Cox <alan@redhat.com>
*
@@ -137,14 +137,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,
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index dab2889a556f..6770820cfca9 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -33,7 +33,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_sil680"
-#define DRV_VERSION "0.4.5"
+#define DRV_VERSION "0.4.6"
/**
* sil680_selreg - return register base
@@ -91,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,
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 8dc3bc4f5863..a3fbcee6fb33 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -35,7 +35,7 @@
#include "sis.h"
#define DRV_NAME "pata_sis"
-#define DRV_VERSION "0.5.0"
+#define DRV_VERSION "0.5.1"
struct sis_chipset {
u16 device; /* PCI host ID */
@@ -86,106 +86,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,
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index b681441cfcb9..da9e22b25753 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -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,
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index 71418f2a0cdb..e618ffd6e944 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -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,
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 946ade0e1f1b..96b71791d2f4 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -62,7 +62,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_via"
-#define DRV_VERSION "0.2.1"
+#define DRV_VERSION "0.3.1"
/*
* The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
@@ -135,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,
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 6c111035fc84..cc4ad271afb5 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -8,7 +8,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
@@ -36,7 +35,7 @@ static int probe_winbond = 1;
static int probe_winbond;
#endif
-static spinlock_t winbond_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(winbond_lock);
static void winbond_writecfg(unsigned long port, u8 reg, u8 val)
{
@@ -152,13 +151,13 @@ static struct ata_port_operations winbond_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = winbond_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -179,11 +178,9 @@ static struct ata_port_operations winbond_port_ops = {
static __init int winbond_init_one(unsigned long port)
{
- struct ata_probe_ent ae;
struct platform_device *pdev;
- int ret;
u8 reg;
- int i;
+ int i, rc;
reg = winbond_readcfg(port, 0x81);
reg |= 0x80; /* jumpered mode off */
@@ -202,58 +199,56 @@ static __init int winbond_init_one(unsigned long port)
for (i = 0; i < 2 ; i ++) {
unsigned long cmd_port = 0x1F0 - (0x80 * i);
+ struct ata_host *host;
+ struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
- if (reg & (1 << i)) {
- /*
- * Fill in a probe structure first of all
- */
-
- pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
-
- cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
- ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
- if (!cmd_addr || !ctl_addr) {
- platform_device_unregister(pdev);
- return -ENOMEM;
- }
-
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &pdev->dev;
-
- ae.port_ops = &winbond_port_ops;
- ae.pio_mask = 0x1F;
-
- ae.sht = &winbond_sht;
-
- ae.n_ports = 1;
- ae.irq = 14 + i;
- ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- ae.port[0].cmd_addr = cmd_addr;
- ae.port[0].altstatus_addr = ctl_addr;
- ae.port[0].ctl_addr = ctl_addr;
- ata_std_ports(&ae.port[0]);
- /*
- * Hook in a private data structure per channel
- */
- ae.private_data = &winbond_data[nr_winbond_host];
- winbond_data[nr_winbond_host].config = port;
- winbond_data[nr_winbond_host].platform_dev = pdev;
-
- ret = ata_device_add(&ae);
- if (ret == 0) {
- platform_device_unregister(pdev);
- return -ENODEV;
- }
- winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev);
- }
+ if (!(reg & (1 << i)))
+ continue;
+
+ pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ rc = -ENOMEM;
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ goto err_unregister;
+
+ rc = -ENOMEM;
+ cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
+ ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+ if (!cmd_addr || !ctl_addr)
+ goto err_unregister;
+
+ ap = host->ports[0];
+ ap->ops = &winbond_port_ops;
+ ap->pio_mask = 0x1F;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+ ap->ioaddr.cmd_addr = cmd_addr;
+ ap->ioaddr.altstatus_addr = ctl_addr;
+ ap->ioaddr.ctl_addr = ctl_addr;
+ ata_std_ports(&ap->ioaddr);
+
+ /* hook in a private data structure per channel */
+ host->private_data = &winbond_data[nr_winbond_host];
+ winbond_data[nr_winbond_host].config = port;
+ winbond_data[nr_winbond_host].platform_dev = pdev;
+
+ /* activate */
+ rc = ata_host_activate(host, 14 + i, ata_interrupt, 0,
+ &winbond_sht);
+ if (rc)
+ goto err_unregister;
+
+ winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev);
}
return 0;
+
+ err_unregister:
+ platform_device_unregister(pdev);
+ return rc;
}
/**
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 5dd3ca8b5f29..52b69530ab29 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -52,9 +52,9 @@
/* macro to calculate base address for ADMA regs */
#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
-/* macro to obtain addresses from ata_host */
-#define ADMA_HOST_REGS(host,port_no) \
- ADMA_REGS((host)->iomap[ADMA_MMIO_BAR], port_no)
+/* macro to obtain addresses from ata_port */
+#define ADMA_PORT_REGS(ap) \
+ ADMA_REGS((ap)->host->iomap[ADMA_MMIO_BAR], ap->port_no)
enum {
ADMA_MMIO_BAR = 4,
@@ -128,7 +128,6 @@ struct adma_port_priv {
static int adma_ata_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
-static irqreturn_t adma_intr (int irq, void *dev_instance);
static int adma_port_start(struct ata_port *ap);
static void adma_host_stop(struct ata_host *host);
static void adma_port_stop(struct ata_port *ap);
@@ -172,7 +171,6 @@ static const struct ata_port_operations adma_ata_ops = {
.qc_issue = adma_qc_issue,
.eng_timeout = adma_eng_timeout,
.data_xfer = ata_data_xfer,
- .irq_handler = adma_intr,
.irq_clear = adma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -186,7 +184,6 @@ static const struct ata_port_operations adma_ata_ops = {
static struct ata_port_info adma_port_info[] = {
/* board_1841_idx */
{
- .sht = &adma_ata_sht,
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
ATA_FLAG_PIO_POLLING,
@@ -229,8 +226,10 @@ static void adma_irq_clear(struct ata_port *ap)
/* nothing */
}
-static void adma_reset_engine(void __iomem *chan)
+static void adma_reset_engine(struct ata_port *ap)
{
+ void __iomem *chan = ADMA_PORT_REGS(ap);
+
/* reset ADMA to idle state */
writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
udelay(2);
@@ -241,14 +240,14 @@ static void adma_reset_engine(void __iomem *chan)
static void adma_reinit_engine(struct ata_port *ap)
{
struct adma_port_priv *pp = ap->private_data;
- void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+ void __iomem *chan = ADMA_PORT_REGS(ap);
/* mask/clear ATA interrupts */
writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
ata_check_status(ap);
/* reset the ADMA engine */
- adma_reset_engine(chan);
+ adma_reset_engine(ap);
/* set in-FIFO threshold to 0x100 */
writew(0x100, chan + ADMA_FIFO_IN);
@@ -268,7 +267,7 @@ static void adma_reinit_engine(struct ata_port *ap)
static inline void adma_enter_reg_mode(struct ata_port *ap)
{
- void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+ void __iomem *chan = ADMA_PORT_REGS(ap);
writew(aPIOMD4, chan + ADMA_CONTROL);
readb(chan + ADMA_STATUS); /* flush */
@@ -415,7 +414,7 @@ static void adma_qc_prep(struct ata_queued_cmd *qc)
static inline void adma_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+ void __iomem *chan = ADMA_PORT_REGS(ap);
VPRINTK("ENTER, ap %p\n", ap);
@@ -453,7 +452,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host)
struct ata_port *ap = host->ports[port_no];
struct adma_port_priv *pp;
struct ata_queued_cmd *qc;
- void __iomem *chan = ADMA_HOST_REGS(host, port_no);
+ void __iomem *chan = ADMA_PORT_REGS(ap);
u8 status = readb(chan + ADMA_STATUS);
if (status == 0)
@@ -575,7 +574,7 @@ static int adma_port_start(struct ata_port *ap)
static void adma_port_stop(struct ata_port *ap)
{
- adma_reset_engine(ADMA_HOST_REGS(ap->host, ap->port_no));
+ adma_reset_engine(ap);
}
static void adma_host_stop(struct ata_host *host)
@@ -583,21 +582,19 @@ static void adma_host_stop(struct ata_host *host)
unsigned int port_no;
for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_reset_engine(ADMA_HOST_REGS(host, port_no));
+ adma_reset_engine(host->ports[port_no]);
}
-static void adma_host_init(unsigned int chip_id,
- struct ata_probe_ent *probe_ent)
+static void adma_host_init(struct ata_host *host, unsigned int chip_id)
{
unsigned int port_no;
- void __iomem *mmio_base = probe_ent->iomap[ADMA_MMIO_BAR];
/* enable/lock aGO operation */
- writeb(7, mmio_base + ADMA_MODE_LOCK);
+ writeb(7, host->iomap[ADMA_MMIO_BAR] + ADMA_MODE_LOCK);
/* reset the ADMA logic */
for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_reset_engine(ADMA_REGS(mmio_base, port_no));
+ adma_reset_engine(host->ports[port_no]);
}
static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
@@ -623,14 +620,21 @@ static int adma_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- void __iomem *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data;
+ const struct ata_port_info *ppi[] = { &adma_port_info[board_idx], NULL };
+ struct ata_host *host;
+ void __iomem *mmio_base;
int rc, port_no;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* alloc host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, ADMA_PORTS);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -641,46 +645,23 @@ static int adma_ata_init_one(struct pci_dev *pdev,
rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME);
if (rc)
return rc;
- mmio_base = pcim_iomap_table(pdev)[ADMA_MMIO_BAR];
+ host->iomap = pcim_iomap_table(pdev);
+ mmio_base = host->iomap[ADMA_MMIO_BAR];
rc = adma_set_dma_masks(pdev, mmio_base);
if (rc)
return rc;
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = adma_port_info[board_idx].sht;
- probe_ent->port_flags = adma_port_info[board_idx].flags;
- probe_ent->pio_mask = adma_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = adma_port_info[board_idx].udma_mask;
- probe_ent->port_ops = adma_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->n_ports = ADMA_PORTS;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
- adma_ata_setup_port(&probe_ent->port[port_no],
+ for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
+ adma_ata_setup_port(&host->ports[port_no]->ioaddr,
ADMA_ATA_REGS(mmio_base, port_no));
- }
-
- pci_set_master(pdev);
/* initialize adapter */
- adma_host_init(board_idx, probe_ent);
+ adma_host_init(host, board_idx);
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, adma_intr, IRQF_SHARED,
+ &adma_ata_sht);
}
static int __init adma_ata_init(void)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 1e21688bfcf2..f099a1d83a00 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -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[] = {
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index a65ba636aaa8..cb9b9ac12b4c 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -253,10 +253,7 @@ enum {
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
enum {
- /* Our DMA boundary is determined by an ePRD being unable to handle
- * anything larger than 64KB
- */
- MV_DMA_BOUNDARY = 0xffffU,
+ MV_DMA_BOUNDARY = 0xffffffffU,
EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
@@ -350,7 +347,6 @@ static void mv_port_stop(struct ata_port *ap);
static void mv_qc_prep(struct ata_queued_cmd *qc);
static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t mv_interrupt(int irq, void *dev_instance);
static void mv_eng_timeout(struct ata_port *ap);
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -384,10 +380,10 @@ static struct scsi_host_template mv_sht = {
.queuecommand = ata_scsi_queuecmd,
.can_queue = MV_USE_Q_DEPTH,
.this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = MV_MAX_SG_CT / 2,
+ .sg_tablesize = MV_MAX_SG_CT,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .use_clustering = 1,
.proc_name = DRV_NAME,
.dma_boundary = MV_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
@@ -405,6 +401,7 @@ static const struct ata_port_operations mv5_ops = {
.dev_select = ata_std_dev_select,
.phy_reset = mv_phy_reset,
+ .cable_detect = ata_cable_sata,
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
@@ -412,7 +409,6 @@ static const struct ata_port_operations mv5_ops = {
.eng_timeout = mv_eng_timeout,
- .irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -434,6 +430,7 @@ static const struct ata_port_operations mv6_ops = {
.dev_select = ata_std_dev_select,
.phy_reset = mv_phy_reset,
+ .cable_detect = ata_cable_sata,
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
@@ -441,7 +438,6 @@ static const struct ata_port_operations mv6_ops = {
.eng_timeout = mv_eng_timeout,
- .irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -463,6 +459,7 @@ static const struct ata_port_operations mv_iie_ops = {
.dev_select = ata_std_dev_select,
.phy_reset = mv_phy_reset,
+ .cable_detect = ata_cable_sata,
.qc_prep = mv_qc_prep_iie,
.qc_issue = mv_qc_issue,
@@ -470,7 +467,6 @@ static const struct ata_port_operations mv_iie_ops = {
.eng_timeout = mv_eng_timeout,
- .irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -484,35 +480,30 @@ static const struct ata_port_operations mv_iie_ops = {
static const struct ata_port_info mv_port_info[] = {
{ /* chip_504x */
- .sht = &mv_sht,
.flags = MV_COMMON_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv5_ops,
},
{ /* chip_508x */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv5_ops,
},
{ /* chip_5080 */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv5_ops,
},
{ /* chip_604x */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv6_ops,
},
{ /* chip_608x */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio0-4 */
@@ -520,14 +511,12 @@ static const struct ata_port_info mv_port_info[] = {
.port_ops = &mv6_ops,
},
{ /* chip_6042 */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv_iie_ops,
},
{ /* chip_7042 */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
@@ -551,6 +540,9 @@ static const struct pci_device_id mv_pci_tbl[] = {
{ PCI_VDEVICE(TTI, 0x2310), chip_7042 },
+ /* add Marvell 7042 support */
+ { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
+
{ } /* terminate list */
};
@@ -585,6 +577,39 @@ static const struct mv_hw_ops mv6xxx_ops = {
static int msi; /* Use PCI msi; either zero (off, default) or non-zero */
+/* move to PCI layer or libata core? */
+static int pci_go_64(struct pci_dev *pdev)
+{
+ int rc;
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "64-bit DMA enable failed\n");
+ return rc;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
/*
* Functions
*/
@@ -798,20 +823,18 @@ static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
- if (0xffffffffU != ofs) {
+ if (0xffffffffU != ofs)
return readl(mv_ap_base(ap) + ofs);
- } else {
+ else
return (u32) ofs;
- }
}
static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
- if (0xffffffffU != ofs) {
+ if (0xffffffffU != ofs)
writelfl(val, mv_ap_base(ap) + ofs);
- }
}
static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
@@ -959,38 +982,30 @@ static void mv_port_stop(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-static void mv_fill_sg(struct ata_queued_cmd *qc)
+static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
{
struct mv_port_priv *pp = qc->ap->private_data;
- unsigned int i = 0;
+ unsigned int n_sg = 0;
struct scatterlist *sg;
+ struct mv_sg *mv_sg;
+ mv_sg = pp->sg_tbl;
ata_for_each_sg(sg, qc) {
- dma_addr_t addr;
- u32 sg_len, len, offset;
-
- addr = sg_dma_address(sg);
- sg_len = sg_dma_len(sg);
-
- while (sg_len) {
- offset = addr & MV_DMA_BOUNDARY;
- len = sg_len;
- if ((offset + sg_len) > 0x10000)
- len = 0x10000 - offset;
+ dma_addr_t addr = sg_dma_address(sg);
+ u32 sg_len = sg_dma_len(sg);
- pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff);
- pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
- pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff);
+ mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
+ mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
+ mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff);
- sg_len -= len;
- addr += len;
+ if (ata_sg_is_last(sg, qc))
+ mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
- if (!sg_len && ata_sg_is_last(sg, qc))
- pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
-
- i++;
- }
+ mv_sg++;
+ n_sg++;
}
+
+ return n_sg;
}
static inline unsigned mv_inc_q_index(unsigned index)
@@ -1320,17 +1335,15 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
int shift, port, port0, hard_port, handled;
unsigned int err_mask;
- if (hc == 0) {
+ if (hc == 0)
port0 = 0;
- } else {
+ else
port0 = MV_PORTS_PER_HC;
- }
/* we'll need the HC success int register in most cases */
hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- if (hc_irq_cause) {
+ if (hc_irq_cause)
writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
- }
VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
hc,relevant,hc_irq_cause);
@@ -1425,9 +1438,8 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
/* check the cases where we either have nothing pending or have read
* a bogus register value which can indicate HW removal or PCI fault
*/
- if (!irq_stat || (0xffffffffU == irq_stat)) {
+ if (!irq_stat || (0xffffffffU == irq_stat))
return IRQ_NONE;
- }
n_hcs = mv_get_hc_count(host->ports[0]->flags);
spin_lock(&host->lock);
@@ -1952,7 +1964,6 @@ comreset_retry:
ata_port_disable(ap);
return;
}
- ap->cbl = ATA_CBL_SATA;
/* even after SStatus reflects that device is ready,
* it seems to take a while for link to be fully
@@ -2077,9 +2088,10 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
}
-static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
- unsigned int board_idx)
+static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ struct mv_host_priv *hpriv = host->private_data;
u8 rev_id;
u32 hp_flags = hpriv->hp_flags;
@@ -2177,8 +2189,8 @@ static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
/**
* mv_init_host - Perform some early initialization of the host.
- * @pdev: host PCI device
- * @probe_ent: early data struct representing the host
+ * @host: ATA host to initialize
+ * @board_idx: controller index
*
* If possible, do an early global reset of the host. Then do
* our port init and clear/unmask all/relevant host interrupts.
@@ -2186,24 +2198,23 @@ static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
* LOCKING:
* Inherited from caller.
*/
-static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
- unsigned int board_idx)
+static int mv_init_host(struct ata_host *host, unsigned int board_idx)
{
int rc = 0, n_hc, port, hc;
- void __iomem *mmio = probe_ent->iomap[MV_PRIMARY_BAR];
- struct mv_host_priv *hpriv = probe_ent->private_data;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+ struct mv_host_priv *hpriv = host->private_data;
/* global interrupt mask */
writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
- rc = mv_chip_id(pdev, hpriv, board_idx);
+ rc = mv_chip_id(host, board_idx);
if (rc)
goto done;
- n_hc = mv_get_hc_count(probe_ent->port_flags);
- probe_ent->n_ports = MV_PORTS_PER_HC * n_hc;
+ n_hc = mv_get_hc_count(host->ports[0]->flags);
- for (port = 0; port < probe_ent->n_ports; port++)
+ for (port = 0; port < host->n_ports; port++)
hpriv->ops->read_preamp(hpriv, port, mmio);
rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
@@ -2214,7 +2225,7 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
hpriv->ops->reset_bus(pdev, mmio);
hpriv->ops->enable_leds(hpriv, mmio);
- for (port = 0; port < probe_ent->n_ports; port++) {
+ for (port = 0; port < host->n_ports; port++) {
if (IS_60XX(hpriv)) {
void __iomem *port_mmio = mv_port_base(mmio, port);
@@ -2227,9 +2238,9 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
hpriv->ops->phy_errata(hpriv, mmio, port);
}
- for (port = 0; port < probe_ent->n_ports; port++) {
+ for (port = 0; port < host->n_ports; port++) {
void __iomem *port_mmio = mv_port_base(mmio, port);
- mv_port_init(&probe_ent->port[port], port_mmio);
+ mv_port_init(&host->ports[port]->ioaddr, port_mmio);
}
for (hc = 0; hc < n_hc; hc++) {
@@ -2268,17 +2279,17 @@ done:
/**
* mv_print_info - Dump key info to kernel log for perusal.
- * @probe_ent: early data struct representing the host
+ * @host: ATA host to print info about
*
* FIXME: complete this.
*
* LOCKING:
* Inherited from caller.
*/
-static void mv_print_info(struct ata_probe_ent *probe_ent)
+static void mv_print_info(struct ata_host *host)
{
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- struct mv_host_priv *hpriv = probe_ent->private_data;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ struct mv_host_priv *hpriv = host->private_data;
u8 rev_id, scc;
const char *scc_s;
@@ -2297,7 +2308,7 @@ static void mv_print_info(struct ata_probe_ent *probe_ent)
dev_printk(KERN_INFO, &pdev->dev,
"%u slots %u ports %s mode IRQ via %s\n",
- (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports,
+ (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
}
@@ -2312,50 +2323,42 @@ static void mv_print_info(struct ata_probe_ent *probe_ent)
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
- struct device *dev = &pdev->dev;
- struct ata_probe_ent *probe_ent;
- struct mv_host_priv *hpriv;
unsigned int board_idx = (unsigned int)ent->driver_data;
- int rc;
+ const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
+ struct ata_host *host;
+ struct mv_host_priv *hpriv;
+ int n_ports, rc;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+ /* allocate host */
+ n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!host || !hpriv)
+ return -ENOMEM;
+ host->private_data = hpriv;
+
+ /* acquire resources */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- pci_set_master(pdev);
rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
if (rc == -EBUSY)
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv)
- return -ENOMEM;
-
- probe_ent->sht = mv_port_info[board_idx].sht;
- probe_ent->port_flags = mv_port_info[board_idx].flags;
- probe_ent->pio_mask = mv_port_info[board_idx].pio_mask;
- probe_ent->udma_mask = mv_port_info[board_idx].udma_mask;
- probe_ent->port_ops = mv_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
- probe_ent->private_data = hpriv;
+ rc = pci_go_64(pdev);
+ if (rc)
+ return rc;
/* initialize adapter */
- rc = mv_init_host(pdev, probe_ent, board_idx);
+ rc = mv_init_host(host, board_idx);
if (rc)
return rc;
@@ -2364,13 +2367,11 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_intx(pdev, 1);
mv_dump_pci_cfg(pdev, 0x68);
- mv_print_info(probe_ent);
+ mv_print_info(host);
- if (ata_device_add(probe_ent) == 0)
- return -ENODEV;
-
- devm_kfree(dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
+ &mv_sht);
}
static int __init mv_init(void)
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 9d9670a9b117..02169740ed24 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -260,6 +260,7 @@ static int nv_adma_port_resume(struct ata_port *ap);
static void nv_adma_error_handler(struct ata_port *ap);
static void nv_adma_host_stop(struct ata_host *host);
static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
enum nv_host_type
{
@@ -368,7 +369,6 @@ static const struct ata_port_operations nv_generic_ops = {
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.data_xfer = ata_data_xfer,
- .irq_handler = nv_generic_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -395,7 +395,6 @@ static const struct ata_port_operations nv_nf2_ops = {
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.data_xfer = ata_data_xfer,
- .irq_handler = nv_nf2_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -422,7 +421,6 @@ static const struct ata_port_operations nv_ck804_ops = {
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.data_xfer = ata_data_xfer,
- .irq_handler = nv_ck804_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -435,7 +433,7 @@ static const struct ata_port_operations nv_ck804_ops = {
static const struct ata_port_operations nv_adma_ops = {
.port_disable = ata_port_disable,
.tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
+ .tf_read = nv_adma_tf_read,
.check_atapi_dma = nv_adma_check_atapi_dma,
.exec_command = ata_exec_command,
.check_status = ata_check_status,
@@ -451,7 +449,6 @@ static const struct ata_port_operations nv_adma_ops = {
.error_handler = nv_adma_error_handler,
.post_internal_cmd = nv_adma_post_internal_cmd,
.data_xfer = ata_data_xfer,
- .irq_handler = nv_adma_interrupt,
.irq_clear = nv_adma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -476,6 +473,7 @@ static struct ata_port_info nv_port_info[] = {
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_generic_ops,
+ .irq_handler = nv_generic_interrupt,
},
/* nforce2/3 */
{
@@ -486,6 +484,7 @@ static struct ata_port_info nv_port_info[] = {
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_nf2_ops,
+ .irq_handler = nv_nf2_interrupt,
},
/* ck804 */
{
@@ -496,6 +495,7 @@ static struct ata_port_info nv_port_info[] = {
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_ck804_ops,
+ .irq_handler = nv_ck804_interrupt,
},
/* ADMA */
{
@@ -507,6 +507,7 @@ static struct ata_port_info nv_port_info[] = {
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_adma_ops,
+ .irq_handler = nv_adma_interrupt,
},
};
@@ -667,6 +668,18 @@ static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc)
return !(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE);
}
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ /* Since commands where a result TF is requested are not
+ executed in ADMA mode, the only time this function will be called
+ in ADMA mode will be if a command fails. In this case we
+ don't care about going into register mode with ADMA commands
+ pending, as the commands will all shortly be aborted anyway. */
+ nv_adma_register_mode(ap);
+
+ ata_tf_read(ap, tf);
+}
+
static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
{
unsigned int idx = 0;
@@ -738,19 +751,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
return 1;
}
- if (flags & NV_CPB_RESP_DONE) {
+ if (likely(flags & NV_CPB_RESP_DONE)) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
VPRINTK("CPB flags done, flags=0x%x\n", flags);
if (likely(qc)) {
- /* Grab the ATA port status for non-NCQ commands.
- For NCQ commands the current status may have nothing to do with
- the command just completed. */
- if (qc->tf.protocol != ATA_PROT_NCQ) {
- u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4));
- qc->err_mask |= ac_err_mask(ata_status);
- }
- DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num,
- qc->err_mask);
+ DPRINTK("Completing qc from tag %d\n",cpb_num);
ata_qc_complete(qc);
} else {
struct ata_eh_info *ehi = &ap->eh_info;
@@ -1074,14 +1079,14 @@ static int nv_adma_port_resume(struct ata_port *ap)
}
#endif
-static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
+static void nv_adma_setup_port(struct ata_port *ap)
{
- void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR];
- struct ata_ioports *ioport = &probe_ent->port[port];
+ void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+ struct ata_ioports *ioport = &ap->ioaddr;
VPRINTK("ENTER\n");
- mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE;
+ mmio += NV_ADMA_PORT + ap->port_no * NV_ADMA_PORT_SIZE;
ioport->cmd_addr = mmio;
ioport->data_addr = mmio + (ATA_REG_DATA * 4);
@@ -1098,9 +1103,9 @@ static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int por
ioport->ctl_addr = mmio + 0x20;
}
-static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
+static int nv_adma_host_init(struct ata_host *host)
{
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+ struct pci_dev *pdev = to_pci_dev(host->dev);
unsigned int i;
u32 tmp32;
@@ -1115,8 +1120,8 @@ static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
- for (i = 0; i < probe_ent->n_ports; i++)
- nv_adma_setup_port(probe_ent, i);
+ for (i = 0; i < host->n_ports; i++)
+ nv_adma_setup_port(host->ports[i]);
return 0;
}
@@ -1167,9 +1172,11 @@ static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
struct nv_adma_port_priv *pp = qc->ap->private_data;
/* ADMA engine can only be used for non-ATAPI DMA commands,
- or interrupt-driven no-data commands. */
+ or interrupt-driven no-data commands, where a result taskfile
+ is not required. */
if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
- (qc->tf.flags & ATA_TFLAG_POLLING))
+ (qc->tf.flags & ATA_TFLAG_POLLING) ||
+ (qc->flags & ATA_QCFLAG_RESULT_TF))
return 1;
if((qc->flags & ATA_QCFLAG_DMAMAP) ||
@@ -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)
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 2339813ce9f6..f56549b90aa6 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -45,10 +45,11 @@
#include "sata_promise.h"
#define DRV_NAME "sata_promise"
-#define DRV_VERSION "2.00"
+#define DRV_VERSION "2.05"
enum {
+ PDC_MAX_PORTS = 4,
PDC_MMIO_BAR = 3,
/* register offsets */
@@ -70,14 +71,31 @@ enum {
PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */
- PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
- (1<<8) | (1<<9) | (1<<10),
+ /* PDC_GLOBAL_CTL bit definitions */
+ PDC_PH_ERR = (1 << 8), /* PCI error while loading packet */
+ PDC_SH_ERR = (1 << 9), /* PCI error while loading S/G table */
+ PDC_DH_ERR = (1 << 10), /* PCI error while loading data */
+ PDC2_HTO_ERR = (1 << 12), /* host bus timeout */
+ PDC2_ATA_HBA_ERR = (1 << 13), /* error during SATA DATA FIS transmission */
+ PDC2_ATA_DMA_CNT_ERR = (1 << 14), /* DMA DATA FIS size differs from S/G count */
+ PDC_OVERRUN_ERR = (1 << 19), /* S/G byte count larger than HD requires */
+ PDC_UNDERRUN_ERR = (1 << 20), /* S/G byte count less than HD requires */
+ PDC_DRIVE_ERR = (1 << 21), /* drive error */
+ PDC_PCI_SYS_ERR = (1 << 22), /* PCI system error */
+ PDC1_PCI_PARITY_ERR = (1 << 23), /* PCI parity error (from SATA150 driver) */
+ PDC1_ERR_MASK = PDC1_PCI_PARITY_ERR,
+ PDC2_ERR_MASK = PDC2_HTO_ERR | PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR,
+ PDC_ERR_MASK = (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC_OVERRUN_ERR
+ | PDC_UNDERRUN_ERR | PDC_DRIVE_ERR | PDC_PCI_SYS_ERR
+ | PDC1_ERR_MASK | PDC2_ERR_MASK),
board_2037x = 0, /* FastTrak S150 TX2plus */
- board_20319 = 1, /* FastTrak S150 TX4 */
- board_20619 = 2, /* FastTrak TX4000 */
- board_2057x = 3, /* SATAII150 Tx2plus */
- board_40518 = 4, /* SATAII150 Tx4 */
+ board_2037x_pata = 1, /* FastTrak S150 TX2plus PATA port */
+ board_20319 = 2, /* FastTrak S150 TX4 */
+ board_20619 = 3, /* FastTrak TX4000 */
+ board_2057x = 4, /* SATAII150 Tx2plus */
+ board_2057x_pata = 5, /* SATAII150 Tx2plus */
+ board_40518 = 6, /* SATAII150 Tx4 */
PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */
@@ -100,8 +118,10 @@ enum {
ATA_FLAG_MMIO |
ATA_FLAG_PIO_POLLING,
- /* hp->flags bits */
- PDC_FLAG_GEN_II = (1 << 0),
+ /* ap->flags bits */
+ PDC_FLAG_GEN_II = (1 << 24),
+ PDC_FLAG_SATA_PATA = (1 << 25), /* supports SATA + PATA */
+ PDC_FLAG_4_PORTS = (1 << 26), /* 4 ports */
};
@@ -110,28 +130,25 @@ struct pdc_port_priv {
dma_addr_t pkt_dma;
};
-struct pdc_host_priv {
- unsigned long flags;
- unsigned long port_flags[ATA_MAX_PORTS];
-};
-
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc_interrupt (int irq, void *dev_instance);
-static int pdc_port_start(struct ata_port *ap);
+static int pdc_common_port_start(struct ata_port *ap);
+static int pdc_sata_port_start(struct ata_port *ap);
static void pdc_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
-static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc);
+static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc);
static void pdc_irq_clear(struct ata_port *ap);
static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
static void pdc_freeze(struct ata_port *ap);
static void pdc_thaw(struct ata_port *ap);
-static void pdc_error_handler(struct ata_port *ap);
+static void pdc_pata_error_handler(struct ata_port *ap);
+static void pdc_sata_error_handler(struct ata_port *ap);
static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
-
+static int pdc_pata_cable_detect(struct ata_port *ap);
+static int pdc_sata_cable_detect(struct ata_port *ap);
static struct scsi_host_template pdc_ata_sht = {
.module = THIS_MODULE,
@@ -164,17 +181,17 @@ static const struct ata_port_operations pdc_sata_ops = {
.qc_issue = pdc_qc_issue_prot,
.freeze = pdc_freeze,
.thaw = pdc_thaw,
- .error_handler = pdc_error_handler,
+ .error_handler = pdc_sata_error_handler,
.post_internal_cmd = pdc_post_internal_cmd,
+ .cable_detect = pdc_sata_cable_detect,
.data_xfer = ata_data_xfer,
- .irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
- .port_start = pdc_port_start,
+ .port_start = pdc_sata_port_start,
};
/* First-generation chips need a more restrictive ->check_atapi_dma op */
@@ -185,23 +202,23 @@ static const struct ata_port_operations pdc_old_sata_ops = {
.check_status = ata_check_status,
.exec_command = pdc_exec_command_mmio,
.dev_select = ata_std_dev_select,
- .check_atapi_dma = pdc_old_check_atapi_dma,
+ .check_atapi_dma = pdc_old_sata_check_atapi_dma,
.qc_prep = pdc_qc_prep,
.qc_issue = pdc_qc_issue_prot,
.freeze = pdc_freeze,
.thaw = pdc_thaw,
- .error_handler = pdc_error_handler,
+ .error_handler = pdc_sata_error_handler,
.post_internal_cmd = pdc_post_internal_cmd,
+ .cable_detect = pdc_sata_cable_detect,
.data_xfer = ata_data_xfer,
- .irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
- .port_start = pdc_port_start,
+ .port_start = pdc_sata_port_start,
};
static const struct ata_port_operations pdc_pata_ops = {
@@ -217,32 +234,41 @@ static const struct ata_port_operations pdc_pata_ops = {
.qc_issue = pdc_qc_issue_prot,
.freeze = pdc_freeze,
.thaw = pdc_thaw,
- .error_handler = pdc_error_handler,
+ .error_handler = pdc_pata_error_handler,
.post_internal_cmd = pdc_post_internal_cmd,
+ .cable_detect = pdc_pata_cable_detect,
.data_xfer = ata_data_xfer,
- .irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
- .port_start = pdc_port_start,
+ .port_start = pdc_common_port_start,
};
static const struct ata_port_info pdc_port_info[] = {
/* board_2037x */
{
- .sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+ PDC_FLAG_SATA_PATA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &pdc_old_sata_ops,
},
+ /* board_2037x_pata */
+ {
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_pata_ops,
+ },
+
/* board_20319 */
{
- .sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+ PDC_FLAG_4_PORTS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -251,8 +277,8 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_20619 */
{
- .sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
+ PDC_FLAG_4_PORTS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -261,18 +287,28 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_2057x */
{
- .sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+ PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &pdc_sata_ops,
},
+ /* board_2057x_pata */
+ {
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+ PDC_FLAG_GEN_II,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_pata_ops,
+ },
+
/* board_40518 */
{
- .sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+ PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -313,18 +349,12 @@ static struct pci_driver pdc_ata_pci_driver = {
};
-static int pdc_port_start(struct ata_port *ap)
+static int pdc_common_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
- struct pdc_host_priv *hp = ap->host->private_data;
struct pdc_port_priv *pp;
int rc;
- /* fix up port flags and cable type for SATA+PATA chips */
- ap->flags |= hp->port_flags[ap->port_no];
- if (ap->flags & ATA_FLAG_SATA)
- ap->cbl = ATA_CBL_SATA;
-
rc = ata_port_start(ap);
if (rc)
return rc;
@@ -339,8 +369,19 @@ static int pdc_port_start(struct ata_port *ap)
ap->private_data = pp;
+ return 0;
+}
+
+static int pdc_sata_port_start(struct ata_port *ap)
+{
+ int rc;
+
+ rc = pdc_common_port_start(ap);
+ if (rc)
+ return rc;
+
/* fix up PHYMODE4 align timing */
- if ((hp->flags & PDC_FLAG_GEN_II) && sata_scr_valid(ap)) {
+ if (ap->flags & PDC_FLAG_GEN_II) {
void __iomem *mmio = (void __iomem *) ap->ioaddr.scr_addr;
unsigned int tmp;
@@ -374,23 +415,25 @@ static void pdc_reset_port(struct ata_port *ap)
readl(mmio); /* flush */
}
-static void pdc_pata_cbl_detect(struct ata_port *ap)
+static int pdc_pata_cable_detect(struct ata_port *ap)
{
u8 tmp;
void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
tmp = readb(mmio);
+ if (tmp & 0x01)
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+}
- if (tmp & 0x01) {
- ap->cbl = ATA_CBL_PATA40;
- ap->udma_mask &= ATA_UDMA_MASK_40C;
- } else
- ap->cbl = ATA_CBL_PATA80;
+static int pdc_sata_cable_detect(struct ata_port *ap)
+{
+ return ATA_CBL_SATA;
}
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
- if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
+ if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -399,7 +442,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
u32 val)
{
- if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
+ if (sc_reg > SCR_CONTROL)
return;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -555,52 +598,79 @@ static void pdc_thaw(struct ata_port *ap)
readl(mmio + PDC_CTLSTAT); /* flush */
}
-static int pdc_pre_reset(struct ata_port *ap)
-{
- if (!sata_scr_valid(ap))
- pdc_pata_cbl_detect(ap);
- return ata_std_prereset(ap);
-}
-
-static void pdc_error_handler(struct ata_port *ap)
+static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset)
{
- ata_reset_fn_t hardreset;
-
if (!(ap->pflags & ATA_PFLAG_FROZEN))
pdc_reset_port(ap);
- hardreset = NULL;
- if (sata_scr_valid(ap))
- hardreset = sata_std_hardreset;
-
/* perform recovery */
- ata_do_eh(ap, pdc_pre_reset, ata_std_softreset, hardreset,
+ ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
ata_std_postreset);
}
+static void pdc_pata_error_handler(struct ata_port *ap)
+{
+ pdc_common_error_handler(ap, NULL);
+}
+
+static void pdc_sata_error_handler(struct ata_port *ap)
+{
+ pdc_common_error_handler(ap, sata_std_hardreset);
+}
+
static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- if (qc->flags & ATA_QCFLAG_FAILED)
- qc->err_mask |= AC_ERR_OTHER;
-
/* make DMA engine forget about the failed command */
- if (qc->err_mask)
+ if (qc->flags & ATA_QCFLAG_FAILED)
pdc_reset_port(ap);
}
+static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u32 port_status, u32 err_mask)
+{
+ struct ata_eh_info *ehi = &ap->eh_info;
+ unsigned int ac_err_mask = 0;
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "port_status 0x%08x", port_status);
+ port_status &= err_mask;
+
+ if (port_status & PDC_DRIVE_ERR)
+ ac_err_mask |= AC_ERR_DEV;
+ if (port_status & (PDC_OVERRUN_ERR | PDC_UNDERRUN_ERR))
+ ac_err_mask |= AC_ERR_HSM;
+ if (port_status & (PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR))
+ ac_err_mask |= AC_ERR_ATA_BUS;
+ if (port_status & (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC2_HTO_ERR
+ | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
+ ac_err_mask |= AC_ERR_HOST_BUS;
+
+ if (sata_scr_valid(ap))
+ ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+
+ qc->err_mask |= ac_err_mask;
+
+ pdc_reset_port(ap);
+}
+
static inline unsigned int pdc_host_intr( struct ata_port *ap,
struct ata_queued_cmd *qc)
{
unsigned int handled = 0;
- u32 tmp;
- void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+ u32 port_status, err_mask;
- tmp = readl(mmio);
- if (tmp & PDC_ERR_MASK) {
- qc->err_mask |= AC_ERR_DEV;
- pdc_reset_port(ap);
+ err_mask = PDC_ERR_MASK;
+ if (ap->flags & PDC_FLAG_GEN_II)
+ err_mask &= ~PDC1_ERR_MASK;
+ else
+ err_mask &= ~PDC2_ERR_MASK;
+ port_status = readl(port_mmio + PDC_GLOBAL_CTL);
+ if (unlikely(port_status & err_mask)) {
+ pdc_error_intr(ap, qc, port_status, err_mask);
+ return 1;
}
switch (qc->tf.protocol) {
@@ -767,44 +837,40 @@ static int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
return pio;
}
-static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc)
+static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc)
{
- struct ata_port *ap = qc->ap;
-
/* First generation chips cannot use ATAPI DMA on SATA ports */
- if (sata_scr_valid(ap))
- return 1;
- return pdc_check_atapi_dma(qc);
+ return 1;
}
-static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base,
- void __iomem *scr_addr)
+static void pdc_ata_setup_port(struct ata_port *ap,
+ void __iomem *base, void __iomem *scr_addr)
{
- port->cmd_addr = base;
- port->data_addr = base;
- port->feature_addr =
- port->error_addr = base + 0x4;
- port->nsect_addr = base + 0x8;
- port->lbal_addr = base + 0xc;
- port->lbam_addr = base + 0x10;
- port->lbah_addr = base + 0x14;
- port->device_addr = base + 0x18;
- port->command_addr =
- port->status_addr = base + 0x1c;
- port->altstatus_addr =
- port->ctl_addr = base + 0x38;
- port->scr_addr = scr_addr;
+ ap->ioaddr.cmd_addr = base;
+ ap->ioaddr.data_addr = base;
+ ap->ioaddr.feature_addr =
+ ap->ioaddr.error_addr = base + 0x4;
+ ap->ioaddr.nsect_addr = base + 0x8;
+ ap->ioaddr.lbal_addr = base + 0xc;
+ ap->ioaddr.lbam_addr = base + 0x10;
+ ap->ioaddr.lbah_addr = base + 0x14;
+ ap->ioaddr.device_addr = base + 0x18;
+ ap->ioaddr.command_addr =
+ ap->ioaddr.status_addr = base + 0x1c;
+ ap->ioaddr.altstatus_addr =
+ ap->ioaddr.ctl_addr = base + 0x38;
+ ap->ioaddr.scr_addr = scr_addr;
}
-static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+static void pdc_host_init(struct ata_host *host)
{
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
- struct pdc_host_priv *hp = pe->private_data;
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II;
int hotplug_offset;
u32 tmp;
- if (hp->flags & PDC_FLAG_GEN_II)
+ if (is_gen2)
hotplug_offset = PDC2_SATA_PLUG_CSR;
else
hotplug_offset = PDC_SATA_PLUG_CSR;
@@ -818,7 +884,7 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
/* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */
tmp = readl(mmio + PDC_FLASH_CTL);
tmp |= 0x02000; /* bit 13 (enable bmr burst) */
- if (!(hp->flags & PDC_FLAG_GEN_II))
+ if (!is_gen2)
tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */
writel(tmp, mmio + PDC_FLASH_CTL);
@@ -831,7 +897,7 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
writel(tmp | 0xff0000, mmio + hotplug_offset);
/* don't initialise TBG or SLEW on 2nd generation chips */
- if (hp->flags & PDC_FLAG_GEN_II)
+ if (is_gen2)
return;
/* reduce TBG clock to 133 Mhz. */
@@ -853,16 +919,16 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent;
- struct pdc_host_priv *hp;
+ const struct ata_port_info *pi = &pdc_port_info[ent->driver_data];
+ const struct ata_port_info *ppi[PDC_MAX_PORTS];
+ struct ata_host *host;
void __iomem *base;
- unsigned int board_idx = (unsigned int) ent->driver_data;
- int rc;
- u8 tmp;
+ int n_ports, i, rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* enable and acquire resources */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -872,89 +938,49 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
pcim_pin_device(pdev);
if (rc)
return rc;
+ base = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
-
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
+ /* determine port configuration and setup host */
+ n_ports = 2;
+ if (pi->flags & PDC_FLAG_4_PORTS)
+ n_ports = 4;
+ for (i = 0; i < n_ports; i++)
+ ppi[i] = pi;
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
+ if (pi->flags & PDC_FLAG_SATA_PATA) {
+ u8 tmp = readb(base + PDC_FLASH_CTL+1);
+ if (!(tmp & 0x80)) {
+ ppi[n_ports++] = pi + 1;
+ dev_printk(KERN_INFO, &pdev->dev, "PATA port found\n");
+ }
+ }
- hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL);
- if (hp == NULL)
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ if (!host) {
+ dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");
return -ENOMEM;
-
- probe_ent->private_data = hp;
-
- probe_ent->sht = pdc_port_info[board_idx].sht;
- probe_ent->port_flags = pdc_port_info[board_idx].flags;
- probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
- probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- base = probe_ent->iomap[PDC_MMIO_BAR];
-
- pdc_ata_setup_port(&probe_ent->port[0], base + 0x200, base + 0x400);
- pdc_ata_setup_port(&probe_ent->port[1], base + 0x280, base + 0x500);
-
- /* notice 4-port boards */
- switch (board_idx) {
- case board_40518:
- hp->flags |= PDC_FLAG_GEN_II;
- /* Fall through */
- case board_20319:
- probe_ent->n_ports = 4;
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, base + 0x600);
- pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, base + 0x700);
- break;
- case board_2057x:
- hp->flags |= PDC_FLAG_GEN_II;
- /* Fall through */
- case board_2037x:
- /* TX2plus boards also have a PATA port */
- tmp = readb(base + PDC_FLASH_CTL+1);
- if (!(tmp & 0x80)) {
- probe_ent->n_ports = 3;
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
- hp->port_flags[2] = ATA_FLAG_SLAVE_POSS;
- printk(KERN_INFO DRV_NAME " PATA port found\n");
- } else
- probe_ent->n_ports = 2;
- hp->port_flags[0] = ATA_FLAG_SATA;
- hp->port_flags[1] = ATA_FLAG_SATA;
- break;
- case board_20619:
- probe_ent->n_ports = 4;
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
- pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, NULL);
- break;
- default:
- BUG();
- break;
}
+ host->iomap = pcim_iomap_table(pdev);
- pci_set_master(pdev);
+ for (i = 0; i < host->n_ports; i++)
+ pdc_ata_setup_port(host->ports[i],
+ base + 0x200 + i * 0x80,
+ base + 0x400 + i * 0x100);
/* initialize adapter */
- pdc_host_init(board_idx, probe_ent);
+ pdc_host_init(host);
- if (!ata_device_add(probe_ent))
- return -ENODEV;
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ /* start host, request IRQ and attach */
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, pdc_interrupt, IRQF_SHARED,
+ &pdc_ata_sht);
}
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 8786b45f291b..f5a05de0093d 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -114,7 +114,6 @@ struct qs_port_priv {
static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t qs_intr (int irq, void *dev_instance);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host);
static void qs_phy_reset(struct ata_port *ap);
@@ -158,7 +157,6 @@ static const struct ata_port_operations qs_ata_ops = {
.qc_issue = qs_qc_issue,
.data_xfer = ata_data_xfer,
.eng_timeout = qs_eng_timeout,
- .irq_handler = qs_intr,
.irq_clear = qs_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -173,7 +171,6 @@ static const struct ata_port_operations qs_ata_ops = {
static const struct ata_port_info qs_port_info[] = {
/* board_2068_idx */
{
- .sht = &qs_ata_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET |
//FIXME ATA_FLAG_SRST |
@@ -530,16 +527,16 @@ static void qs_host_stop(struct ata_host *host)
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
}
-static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+static void qs_host_init(struct ata_host *host, unsigned int chip_id)
{
- void __iomem *mmio_base = pe->iomap[QS_MMIO_BAR];
+ void __iomem *mmio_base = host->iomap[QS_MMIO_BAR];
unsigned int port_no;
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
/* reset each channel in turn */
- for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
u8 __iomem *chan = mmio_base + (port_no * 0x4000);
writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1);
writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
@@ -547,7 +544,7 @@ static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
}
writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
- for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
u8 __iomem *chan = mmio_base + (port_no * 0x4000);
/* set FIFO depths to same settings as Windows driver */
writew(32, chan + QS_CFC_HUFT);
@@ -607,14 +604,20 @@ static int qs_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent;
- void __iomem * const *iomap;
unsigned int board_idx = (unsigned int) ent->driver_data;
+ const struct ata_port_info *ppi[] = { &qs_port_info[board_idx], NULL };
+ struct ata_host *host;
int rc, port_no;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* alloc host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, QS_PORTS);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -625,47 +628,24 @@ static int qs_ata_init_one(struct pci_dev *pdev,
rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME);
if (rc)
return rc;
- iomap = pcim_iomap_table(pdev);
+ host->iomap = pcim_iomap_table(pdev);
- rc = qs_set_dma_masks(pdev, iomap[QS_MMIO_BAR]);
+ rc = qs_set_dma_masks(pdev, host->iomap[QS_MMIO_BAR]);
if (rc)
return rc;
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = qs_port_info[board_idx].sht;
- probe_ent->port_flags = qs_port_info[board_idx].flags;
- probe_ent->pio_mask = qs_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = qs_port_info[board_idx].udma_mask;
- probe_ent->port_ops = qs_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = iomap;
- probe_ent->n_ports = QS_PORTS;
-
- for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
void __iomem *chan =
- probe_ent->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
- qs_ata_setup_port(&probe_ent->port[port_no], chan);
+ host->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
+ qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan);
}
- pci_set_master(pdev);
-
/* initialize adapter */
- qs_host_init(board_idx, probe_ent);
+ qs_host_init(host, board_idx);
- if (ata_device_add(probe_ent) != QS_PORTS)
- return -EIO;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, qs_intr, IRQF_SHARED,
+ &qs_ata_sht);
}
static int __init qs_ata_init(void)
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 917b7ea4ef7c..0a1e417f309c 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil"
-#define DRV_VERSION "2.1"
+#define DRV_VERSION "2.2"
enum {
SIL_MMIO_BAR = 5,
@@ -114,11 +114,10 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM
static int sil_pci_device_resume(struct pci_dev *pdev);
#endif
-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
+static void sil_dev_config(struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static void sil_post_set_mode (struct ata_port *ap);
-static irqreturn_t sil_interrupt(int irq, void *dev_instance);
+static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap);
@@ -197,7 +196,7 @@ static const struct ata_port_operations sil_ops = {
.check_status = ata_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .post_set_mode = sil_post_set_mode,
+ .set_mode = sil_set_mode,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
@@ -209,7 +208,6 @@ static const struct ata_port_operations sil_ops = {
.thaw = sil_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = sil_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -221,7 +219,6 @@ static const struct ata_port_operations sil_ops = {
static const struct ata_port_info sil_port_info[] = {
/* sil_3112 */
{
- .sht = &sil_sht,
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -230,7 +227,6 @@ static const struct ata_port_info sil_port_info[] = {
},
/* sil_3112_no_sata_irq */
{
- .sht = &sil_sht,
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
SIL_FLAG_NO_SATA_IRQ,
.pio_mask = 0x1f, /* pio0-4 */
@@ -240,7 +236,6 @@ static const struct ata_port_info sil_port_info[] = {
},
/* sil_3512 */
{
- .sht = &sil_sht,
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -249,7 +244,6 @@ static const struct ata_port_info sil_port_info[] = {
},
/* sil_3114 */
{
- .sht = &sil_sht,
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -297,7 +291,16 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
return cache_line;
}
-static void sil_post_set_mode (struct ata_port *ap)
+/**
+ * sil_set_mode - wrap set_mode functions
+ * @ap: port to set up
+ * @r_failed: returned device when we fail
+ *
+ * Wrap the libata method for device setup as after the setup we need
+ * to inspect the results and do some configuration work
+ */
+
+static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed)
{
struct ata_host *host = ap->host;
struct ata_device *dev;
@@ -305,6 +308,11 @@ static void sil_post_set_mode (struct ata_port *ap)
void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
u32 tmp, dev_mode[2];
unsigned int i;
+ int rc;
+
+ rc = ata_do_set_mode(ap, r_failed);
+ if (rc)
+ return rc;
for (i = 0; i < 2; i++) {
dev = &ap->device[i];
@@ -323,6 +331,7 @@ static void sil_post_set_mode (struct ata_port *ap)
tmp |= (dev_mode[1] << 4);
writel(tmp, addr);
readl(addr); /* flush */
+ return 0;
}
static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
@@ -521,7 +530,6 @@ static void sil_thaw(struct ata_port *ap)
/**
* sil_dev_config - Apply device/host-specific errata fixups
- * @ap: Port containing device to be examined
* @dev: Device to be examined
*
* After the IDENTIFY [PACKET] DEVICE step is complete, and a
@@ -548,8 +556,9 @@ static void sil_thaw(struct ata_port *ap)
* appreciated.
* - But then again UDMA5 is hardly anything to complain about
*/
-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void sil_dev_config(struct ata_device *dev)
{
+ struct ata_port *ap = dev->ap;
int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
unsigned int n, quirks = 0;
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -583,10 +592,10 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
}
}
-static void sil_init_controller(struct pci_dev *pdev,
- int n_ports, unsigned long port_flags,
- void __iomem *mmio_base)
+static void sil_init_controller(struct ata_host *host)
{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
u8 cls;
u32 tmp;
int i;
@@ -596,7 +605,7 @@ static void sil_init_controller(struct pci_dev *pdev,
if (cls) {
cls >>= 3;
cls++; /* cls = (line_size/8)+1 */
- for (i = 0; i < n_ports; i++)
+ for (i = 0; i < host->n_ports; i++)
writew(cls << 8 | cls,
mmio_base + sil_port[i].fifo_cfg);
} else
@@ -604,10 +613,10 @@ static void sil_init_controller(struct pci_dev *pdev,
"cache line size not set. Driver may not function\n");
/* Apply R_ERR on DMA activate FIS errata workaround */
- if (port_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+ if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) {
int cnt;
- for (i = 0, cnt = 0; i < n_ports; i++) {
+ for (i = 0, cnt = 0; i < host->n_ports; i++) {
tmp = readl(mmio_base + sil_port[i].sfis_cfg);
if ((tmp & 0x3) != 0x01)
continue;
@@ -620,7 +629,7 @@ static void sil_init_controller(struct pci_dev *pdev,
}
}
- if (n_ports == 4) {
+ if (host->n_ports == 4) {
/* flip the magic "make 4 ports work" bit */
tmp = readl(mmio_base + sil_port[2].bmdma);
if ((tmp & SIL_INTR_STEERING) == 0)
@@ -632,15 +641,26 @@ static void sil_init_controller(struct pci_dev *pdev,
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct device *dev = &pdev->dev;
- struct ata_probe_ent *probe_ent;
+ int board_id = ent->driver_data;
+ const struct ata_port_info *ppi[] = { &sil_port_info[board_id], NULL };
+ struct ata_host *host;
void __iomem *mmio_base;
- int rc;
+ int n_ports, rc;
unsigned int i;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* allocate host */
+ n_ports = 2;
+ if (board_id == sil_3114)
+ n_ports = 4;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -650,6 +670,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
@@ -658,45 +679,25 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
+ mmio_base = host->iomap[SIL_MMIO_BAR];
- INIT_LIST_HEAD(&probe_ent->node);
- probe_ent->dev = pci_dev_to_dev(pdev);
- probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
- probe_ent->sht = sil_port_info[ent->driver_data].sht;
- probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2;
- probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask;
- probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask;
- probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->port_flags = sil_port_info[ent->driver_data].flags;
-
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- mmio_base = probe_ent->iomap[SIL_MMIO_BAR];
-
- for (i = 0; i < probe_ent->n_ports; i++) {
- probe_ent->port[i].cmd_addr = mmio_base + sil_port[i].tf;
- probe_ent->port[i].altstatus_addr =
- probe_ent->port[i].ctl_addr = mmio_base + sil_port[i].ctl;
- probe_ent->port[i].bmdma_addr = mmio_base + sil_port[i].bmdma;
- probe_ent->port[i].scr_addr = mmio_base + sil_port[i].scr;
- ata_std_ports(&probe_ent->port[i]);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+
+ ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
+ ioaddr->altstatus_addr =
+ ioaddr->ctl_addr = mmio_base + sil_port[i].ctl;
+ ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
+ ioaddr->scr_addr = mmio_base + sil_port[i].scr;
+ ata_std_ports(ioaddr);
}
- sil_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
- mmio_base);
+ /* initialize and activate */
+ sil_init_controller(host);
pci_set_master(pdev);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, sil_interrupt, IRQF_SHARED,
+ &sil_sht);
}
#ifdef CONFIG_PM
@@ -709,8 +710,7 @@ static int sil_pci_device_resume(struct pci_dev *pdev)
if (rc)
return rc;
- sil_init_controller(pdev, host->n_ports, host->ports[0]->flags,
- host->iomap[SIL_MMIO_BAR]);
+ sil_init_controller(host);
ata_host_resume(host);
return 0;
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 5614df8c1ce2..e6223ba667da 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -323,7 +323,7 @@ struct sil24_port_priv {
struct ata_taskfile tf; /* Cached taskfile registers */
};
-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
+static void sil24_dev_config(struct ata_device *dev);
static u8 sil24_check_status(struct ata_port *ap);
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
@@ -331,7 +331,6 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
static void sil24_irq_clear(struct ata_port *ap);
-static irqreturn_t sil24_interrupt(int irq, void *dev_instance);
static void sil24_freeze(struct ata_port *ap);
static void sil24_thaw(struct ata_port *ap);
static void sil24_error_handler(struct ata_port *ap);
@@ -401,7 +400,6 @@ static const struct ata_port_operations sil24_ops = {
.qc_prep = sil24_qc_prep,
.qc_issue = sil24_qc_issue,
- .irq_handler = sil24_interrupt,
.irq_clear = sil24_irq_clear,
.irq_on = ata_dummy_irq_on,
.irq_ack = ata_dummy_irq_ack,
@@ -424,10 +422,9 @@ static const struct ata_port_operations sil24_ops = {
#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30)
#define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1)
-static struct ata_port_info sil24_port_info[] = {
+static const struct ata_port_info sil24_port_info[] = {
/* sil_3124 */
{
- .sht = &sil24_sht,
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
SIL24_FLAG_PCIX_IRQ_WOC,
.pio_mask = 0x1f, /* pio0-4 */
@@ -437,7 +434,6 @@ static struct ata_port_info sil24_port_info[] = {
},
/* sil_3132 */
{
- .sht = &sil24_sht,
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -446,7 +442,6 @@ static struct ata_port_info sil24_port_info[] = {
},
/* sil_3131/sil_3531 */
{
- .sht = &sil24_sht,
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -462,9 +457,9 @@ static int sil24_tag(int tag)
return tag;
}
-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void sil24_dev_config(struct ata_device *dev)
{
- void __iomem *port = ap->ioaddr.cmd_addr;
+ void __iomem *port = dev->ap->ioaddr.cmd_addr;
if (dev->cdb_len == 16)
writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -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);
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index a787f0d4a5ba..d8ee062e82fc 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -121,7 +121,6 @@ static const struct ata_port_operations sis_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -131,7 +130,6 @@ static const struct ata_port_operations sis_ops = {
};
static struct ata_port_info sis_port_info = {
- .sht = &sis_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f,
.mwdma_mask = 0x7,
@@ -256,12 +254,13 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- int rc;
+ struct ata_port_info pi = sis_port_info;
+ const struct ata_port_info *ppi[2] = { &pi, &pi };
+ struct ata_host *host;
u32 genctl, val;
- struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi };
u8 pmr;
u8 port2_start = 0x20;
+ int rc;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
@@ -270,19 +269,6 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pcim_pin_device(pdev);
- return rc;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
-
/* check and see if the SCRs are in IO space or PCI cfg space */
pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
@@ -349,30 +335,26 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
- probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent)
- return -ENOMEM;
+ rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
+ if (rc)
+ return rc;
- if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) {
+ if (!(pi.flags & SIS_FLAG_CFGSCR)) {
void __iomem *mmio;
- mmio = pcim_iomap(pdev, SIS_SCR_PCI_BAR, 0);
- if (!mmio)
- return -ENOMEM;
+ rc = pcim_iomap_regions(pdev, 1 << SIS_SCR_PCI_BAR, DRV_NAME);
+ if (rc)
+ return rc;
+ mmio = host->iomap[SIS_SCR_PCI_BAR];
- probe_ent->port[0].scr_addr = mmio;
- probe_ent->port[1].scr_addr = mmio + port2_start;
+ host->ports[0]->ioaddr.scr_addr = mmio;
+ host->ports[1]->ioaddr.scr_addr = mmio + port2_start;
}
pci_set_master(pdev);
pci_intx(pdev, 1);
-
- if (!ata_device_add(probe_ent))
- return -EIO;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
-
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &sis_sht);
}
static int __init sis_init(void)
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index b121195cc598..cc07aac10e8c 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -56,7 +56,9 @@
#define DRV_VERSION "2.1"
enum {
- K2_FLAG_NO_ATAPI_DMA = (1 << 29),
+ /* ap->flags bits */
+ K2_FLAG_SATA_8_PORTS = (1 << 24),
+ K2_FLAG_NO_ATAPI_DMA = (1 << 25),
/* Taskfile registers offsets */
K2_SATA_TF_CMD_OFFSET = 0x00,
@@ -90,17 +92,6 @@ enum {
board_svw8 = 1,
};
-static const struct k2_board_info {
- unsigned int n_ports;
- unsigned long port_flags;
-} k2_board_info[] = {
- /* board_svw4 */
- { 4, K2_FLAG_NO_ATAPI_DMA },
-
- /* board_svw8 */
- { 8, K2_FLAG_NO_ATAPI_DMA },
-};
-
static u8 k2_stat_check_status(struct ata_port *ap);
@@ -354,7 +345,6 @@ static const struct ata_port_operations k2_sata_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -363,6 +353,28 @@ static const struct ata_port_operations k2_sata_ops = {
.port_start = ata_port_start,
};
+static const struct ata_port_info k2_port_info[] = {
+ /* board_svw4 */
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &k2_sata_ops,
+ },
+ /* board_svw8 */
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA |
+ K2_FLAG_SATA_8_PORTS,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &k2_sata_ops,
+ },
+};
+
static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET;
@@ -386,17 +398,24 @@ static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct device *dev = &pdev->dev;
- struct ata_probe_ent *probe_ent;
+ const struct ata_port_info *ppi[] =
+ { &k2_port_info[ent->driver_data], NULL };
+ struct ata_host *host;
void __iomem *mmio_base;
- const struct k2_board_info *board_info =
- &k2_board_info[ent->driver_data];
- int rc;
- int i;
+ int n_ports, i, rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* allocate host */
+ n_ports = 4;
+ if (ppi[0]->flags & K2_FLAG_SATA_8_PORTS)
+ n_ports = 8;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ if (!host)
+ return -ENOMEM;
+
/*
* If this driver happens to only be useful on Apple's K2, then
* we should check that here as it has a normal Serverworks ID
@@ -404,6 +423,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
rc = pcim_enable_device(pdev);
if (rc)
return rc;
+
/*
* Check if we have resources mapped at all (second function may
* have been disabled by firmware)
@@ -417,6 +437,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
+ mmio_base = host->iomap[5];
+
+ /* different controllers have different number of ports - currently 4 or 8 */
+ /* All ports are on the same function. Multi-function device is no
+ * longer available. This should not be seen in any system. */
+ for (i = 0; i < host->n_ports; i++)
+ k2_sata_setup_port(&host->ports[i]->ioaddr,
+ mmio_base + i * K2_SATA_PORT_OFFSET);
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
@@ -425,38 +454,6 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
if (rc)
return rc;
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = &k2_sata_sht;
- probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | board_info->port_flags;
- probe_ent->port_ops = &k2_sata_ops;
- probe_ent->n_ports = 4;
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- /* We don't care much about the PIO/UDMA masks, but the core won't like us
- * if we don't fill these
- */
- probe_ent->pio_mask = 0x1f;
- probe_ent->mwdma_mask = 0x7;
- probe_ent->udma_mask = 0x7f;
-
- mmio_base = probe_ent->iomap[5];
-
- /* different controllers have different number of ports - currently 4 or 8 */
- /* All ports are on the same function. Multi-function device is no
- * longer available. This should not be seen in any system. */
- for (i = 0; i < board_info->n_ports; i++)
- k2_sata_setup_port(&probe_ent->port[i],
- mmio_base + i * K2_SATA_PORT_OFFSET);
-
/* Clear a magic bit in SCR1 according to Darwin, those help
* some funky seagate drives (though so far, those were already
* set by the firmware on the machines I had access to)
@@ -469,12 +466,8 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
pci_set_master(pdev);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &k2_sata_sht);
}
/* 0x240 is device ID for Apple K2 device
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 1a081c3a8c06..3a4f44559d0a 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -151,24 +151,23 @@ struct pdc_host_priv {
static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance);
static void pdc_eng_timeout(struct ata_port *ap);
static void pdc_20621_phy_reset (struct ata_port *ap);
static int pdc_port_start(struct ata_port *ap);
static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
+static unsigned int pdc20621_dimm_init(struct ata_host *host);
+static int pdc20621_detect_dimm(struct ata_host *host);
+static unsigned int pdc20621_i2c_read(struct ata_host *host,
u32 device, u32 subaddr, u32 *pdata);
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
+static int pdc20621_prog_dimm0(struct ata_host *host);
+static unsigned int pdc20621_prog_dimm_global(struct ata_host *host);
#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
+static void pdc20621_get_from_dimm(struct ata_host *host,
void *psource, u32 offset, u32 size);
#endif
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
+static void pdc20621_put_to_dimm(struct ata_host *host,
void *psource, u32 offset, u32 size);
static void pdc20621_irq_clear(struct ata_port *ap);
static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
@@ -204,7 +203,6 @@ static const struct ata_port_operations pdc_20621_ops = {
.qc_issue = pdc20621_qc_issue_prot,
.data_xfer = ata_data_xfer,
.eng_timeout = pdc_eng_timeout,
- .irq_handler = pdc20621_interrupt,
.irq_clear = pdc20621_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -214,7 +212,6 @@ static const struct ata_port_operations pdc_20621_ops = {
static const struct ata_port_info pdc_port_info[] = {
/* board_20621 */
{
- .sht = &pdc_sata_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SRST | ATA_FLAG_MMIO |
ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
@@ -882,15 +879,15 @@ static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base)
#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
+static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
u32 offset, u32 size)
{
u32 window_size;
u16 idx;
u8 page_mask;
long dist;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
- void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -937,15 +934,15 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
#endif
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
+static void pdc20621_put_to_dimm(struct ata_host *host, void *psource,
u32 offset, u32 size)
{
u32 window_size;
u16 idx;
u8 page_mask;
long dist;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
- void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -987,10 +984,10 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
}
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
+static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device,
u32 subaddr, u32 *pdata)
{
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
u32 i2creg = 0;
u32 status;
u32 count =0;
@@ -1023,17 +1020,17 @@ static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
}
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
+static int pdc20621_detect_dimm(struct ata_host *host)
{
u32 data=0 ;
- if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
if (data == 100)
return 100;
} else
return 0;
- if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
+ if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
if(data <= 0x75)
return 133;
} else
@@ -1043,13 +1040,13 @@ static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
}
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
+static int pdc20621_prog_dimm0(struct ata_host *host)
{
u32 spd0[50];
u32 data = 0;
int size, i;
u8 bdimmsize;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
static const struct {
unsigned int reg;
unsigned int ofs;
@@ -1072,7 +1069,7 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
mmio += PDC_CHIP0_OFS;
for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
pdc_i2c_read_data[i].reg,
&spd0[pdc_i2c_read_data[i].ofs]);
@@ -1108,11 +1105,11 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
}
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
+static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
{
u32 data, spd0;
int error, i;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1129,7 +1126,7 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
/* Turn on for ECC */
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_TYPE, &spd0);
if (spd0 == 0x02) {
data |= (0x01 << 16);
@@ -1156,7 +1153,7 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
}
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
+static unsigned int pdc20621_dimm_init(struct ata_host *host)
{
int speed, size, length;
u32 addr,spd0,pci_status;
@@ -1166,7 +1163,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
u32 ticks=0;
u32 clock=0;
u32 fparam=0;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1225,18 +1222,18 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
Read SPD of DIMM by I2C interface,
and program the DIMM Module Controller.
*/
- if (!(speed = pdc20621_detect_dimm(pe))) {
+ if (!(speed = pdc20621_detect_dimm(host))) {
printk(KERN_ERR "Detect Local DIMM Fail\n");
return 1; /* DIMM error */
}
VPRINTK("Local DIMM Speed = %d\n", speed);
/* Programming DIMM0 Module Control Register (index_CID0:80h) */
- size = pdc20621_prog_dimm0(pe);
+ size = pdc20621_prog_dimm0(host);
VPRINTK("Local DIMM Size = %dMB\n",size);
/* Programming DIMM Module Global Control Register (index_CID0:88h) */
- if (pdc20621_prog_dimm_global(pe)) {
+ if (pdc20621_prog_dimm_global(host)) {
printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
return 1;
}
@@ -1249,20 +1246,20 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
'9','8','0','3','1','6','1','2',0,0};
u8 test_parttern2[40] = {0};
- pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
- pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
+ pdc20621_put_to_dimm(host, (void *) test_parttern2, 0x10040, 40);
+ pdc20621_put_to_dimm(host, (void *) test_parttern2, 0x40, 40);
- pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+ pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x10040, 40);
+ pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
+ pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x10040,
40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
- pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+ pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x40, 40);
+ pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
}
@@ -1270,14 +1267,14 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
/* ECC initiliazation. */
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_TYPE, &spd0);
if (spd0 == 0x02) {
VPRINTK("Start ECC initialization\n");
addr = 0;
length = size * 1024 * 1024;
while (addr < length) {
- pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
+ pdc20621_put_to_dimm(host, (void *) &tmp, addr,
sizeof(u32));
addr += sizeof(u32);
}
@@ -1287,10 +1284,10 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
}
-static void pdc_20621_init(struct ata_probe_ent *pe)
+static void pdc_20621_init(struct ata_host *host)
{
u32 tmp;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1321,15 +1318,25 @@ static void pdc_20621_init(struct ata_probe_ent *pe)
static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent;
+ const struct ata_port_info *ppi[] =
+ { &pdc_port_info[ent->driver_data], NULL };
+ struct ata_host *host;
void __iomem *base;
struct pdc_host_priv *hpriv;
- unsigned int board_idx = (unsigned int) ent->driver_data;
int rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* allocate host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!host || !hpriv)
+ return -ENOMEM;
+
+ host->private_data = hpriv;
+
+ /* acquire resources and fill host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -1340,7 +1347,15 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
+
+ base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
+ pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200);
+ pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280);
+ pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300);
+ pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380);
+ /* configure and activate */
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
return rc;
@@ -1348,50 +1363,13 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
if (rc)
return rc;
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
+ if (pdc20621_dimm_init(host))
return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv)
- return -ENOMEM;
-
- probe_ent->sht = pdc_port_info[board_idx].sht;
- probe_ent->port_flags = pdc_port_info[board_idx].flags;
- probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
- probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- probe_ent->private_data = hpriv;
- base = probe_ent->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
-
- probe_ent->n_ports = 4;
- pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
- pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
- pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
- pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
+ pdc_20621_init(host);
pci_set_master(pdev);
-
- /* initialize adapter */
- /* initialize local dimm */
- if (pdc20621_dimm_init(probe_ent))
- return -ENOMEM;
- pdc_20621_init(probe_ent);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, pdc20621_interrupt,
+ IRQF_SHARED, &pdc_sata_sht);
}
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index d659ace80f4f..f74e383de083 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -115,7 +115,6 @@ static const struct ata_port_operations uli_ops = {
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -127,7 +126,6 @@ static const struct ata_port_operations uli_ops = {
};
static struct ata_port_info uli_port_info = {
- .sht = &uli_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_IGN_SIMPLEX,
.pio_mask = 0x1f, /* pio0-4 */
@@ -185,12 +183,13 @@ static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent;
- struct ata_port_info *ppi[2];
- int rc;
+ const struct ata_port_info *ppi[] = { &uli_port_info, NULL };
unsigned int board_idx = (unsigned int) ent->driver_data;
+ struct ata_host *host;
struct uli_priv *hpriv;
void __iomem * const *iomap;
+ struct ata_ioports *ioaddr;
+ int n_ports, rc;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
@@ -199,54 +198,42 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pcim_pin_device(pdev);
- return rc;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ n_ports = 2;
+ if (board_idx == uli_5287)
+ n_ports = 4;
+ rc = ata_pci_prepare_native_host(pdev, ppi, n_ports, &host);
if (rc)
return rc;
- ppi[0] = ppi[1] = &uli_port_info;
- probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent)
- return -ENOMEM;
-
hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
+ host->private_data = hpriv;
- probe_ent->private_data = hpriv;
-
- iomap = pcim_iomap_table(pdev);
+ iomap = host->iomap;
switch (board_idx) {
case uli_5287:
hpriv->scr_cfg_addr[0] = ULI5287_BASE;
hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
- probe_ent->n_ports = 4;
- probe_ent->port[2].cmd_addr = iomap[0] + 8;
- probe_ent->port[2].altstatus_addr =
- probe_ent->port[2].ctl_addr = (void __iomem *)
+ ioaddr = &host->ports[2]->ioaddr;
+ ioaddr->cmd_addr = iomap[0] + 8;
+ ioaddr->altstatus_addr =
+ ioaddr->ctl_addr = (void __iomem *)
((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4;
- probe_ent->port[2].bmdma_addr = iomap[4] + 16;
+ ioaddr->bmdma_addr = iomap[4] + 16;
hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
+ ata_std_ports(ioaddr);
- probe_ent->port[3].cmd_addr = iomap[2] + 8;
- probe_ent->port[3].altstatus_addr =
- probe_ent->port[3].ctl_addr = (void __iomem *)
+ ioaddr = &host->ports[3]->ioaddr;
+ ioaddr->cmd_addr = iomap[2] + 8;
+ ioaddr->altstatus_addr =
+ ioaddr->ctl_addr = (void __iomem *)
((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4;
- probe_ent->port[3].bmdma_addr = iomap[4] + 24;
+ ioaddr->bmdma_addr = iomap[4] + 24;
hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
-
- ata_std_ports(&probe_ent->port[2]);
- ata_std_ports(&probe_ent->port[3]);
+ ata_std_ports(ioaddr);
break;
case uli_5289:
@@ -266,12 +253,8 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
pci_intx(pdev, 1);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &uli_sht);
}
static int __init uli_init(void)
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 598e6a26a481..1d855f55f5f7 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -64,8 +64,6 @@ enum {
PORT0 = (1 << 1),
PORT1 = (1 << 0),
ALL_PORTS = PORT0 | PORT1,
- PATA_PORT = 2, /* PATA is port 2 */
- N_PORTS = 3,
NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
@@ -78,11 +76,9 @@ static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap);
static void vt6420_error_handler(struct ata_port *ap);
-static void vt6421_sata_error_handler(struct ata_port *ap);
-static void vt6421_pata_error_handler(struct ata_port *ap);
+static int vt6421_pata_cable_detect(struct ata_port *ap);
static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
-static int vt6421_port_start(struct ata_port *ap);
static const struct pci_device_id svia_pci_tbl[] = {
{ PCI_VDEVICE(VIA, 0x5337), vt6420 },
@@ -141,7 +137,6 @@ static const struct ata_port_operations vt6420_sata_ops = {
.error_handler = vt6420_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -172,15 +167,15 @@ static const struct ata_port_operations vt6421_pata_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = vt6421_pata_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = vt6421_pata_cable_detect,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
- .port_start = vt6421_port_start,
+ .port_start = ata_port_start,
};
static const struct ata_port_operations vt6421_sata_ops = {
@@ -203,10 +198,10 @@ static const struct ata_port_operations vt6421_sata_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = vt6421_sata_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_sata,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -214,11 +209,10 @@ static const struct ata_port_operations vt6421_sata_ops = {
.scr_read = svia_scr_read,
.scr_write = svia_scr_write,
- .port_start = vt6421_port_start,
+ .port_start = ata_port_start,
};
-static struct ata_port_info vt6420_port_info = {
- .sht = &svia_sht,
+static const struct ata_port_info vt6420_port_info = {
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
@@ -226,6 +220,22 @@ static struct ata_port_info vt6420_port_info = {
.port_ops = &vt6420_sata_ops,
};
+static struct ata_port_info vt6421_sport_info = {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &vt6421_sata_ops,
+};
+
+static struct ata_port_info vt6421_pport_info = {
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0,
+ .udma_mask = 0x7f,
+ .port_ops = &vt6421_pata_ops,
+};
+
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
MODULE_LICENSE("GPL");
@@ -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)
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 170bad1b415b..80126f835d32 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -333,7 +333,6 @@ static const struct ata_port_operations vsc_sata_ops = {
.thaw = vsc_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = vsc_sata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -367,30 +366,50 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
+ static const struct ata_port_info pi = {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &vsc_sata_ops,
+ };
+ const struct ata_port_info *ppi[] = { &pi, NULL };
static int printed_version;
- struct ata_probe_ent *probe_ent;
+ struct ata_host *host;
void __iomem *mmio_base;
- int rc;
+ int i, rc;
u8 cls;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* allocate host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
+ if (!host)
+ return -ENOMEM;
+
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- /*
- * Check if we have needed resource mapped.
- */
+ /* check if we have needed resource mapped */
if (pci_resource_len(pdev, 0) == 0)
return -ENODEV;
+ /* map IO regions and intialize host accordingly */
rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME);
if (rc == -EBUSY)
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
+
+ mmio_base = host->iomap[VSC_MMIO_BAR];
+
+ for (i = 0; i < host->n_ports; i++)
+ vsc_sata_setup_port(&host->ports[i]->ioaddr,
+ mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET);
/*
* Use 32 bit DMA mask, because 64 bit address support is poor.
@@ -402,12 +421,6 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
if (rc)
return rc;
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
/*
* Due to a bug in the chip, the default cache line size can't be
* used (unless the default is non-zero).
@@ -418,33 +431,6 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
if (pci_enable_msi(pdev) == 0)
pci_intx(pdev, 0);
- else
- probe_ent->irq_flags = IRQF_SHARED;
-
- probe_ent->sht = &vsc_sata_sht;
- probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO;
- probe_ent->port_ops = &vsc_sata_ops;
- probe_ent->n_ports = 4;
- probe_ent->irq = pdev->irq;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- /* We don't care much about the PIO/UDMA masks, but the core won't like us
- * if we don't fill these
- */
- probe_ent->pio_mask = 0x1f;
- probe_ent->mwdma_mask = 0x07;
- probe_ent->udma_mask = 0x7f;
-
- mmio_base = probe_ent->iomap[VSC_MMIO_BAR];
-
- /* We have 4 ports per PCI function */
- vsc_sata_setup_port(&probe_ent->port[0], mmio_base + 1 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[1], mmio_base + 2 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[2], mmio_base + 3 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[3], mmio_base + 4 * VSC_SATA_PORT_OFFSET);
-
- pci_set_master(pdev);
/*
* Config offset 0x98 is "Extended Control and Status Register 0"
@@ -454,11 +440,9 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
*/
pci_write_config_dword(pdev, 0x98, 0);
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, vsc_sata_interrupt,
+ IRQF_SHARED, &vsc_sata_sht);
}
static const struct pci_device_id vsc_sata_pci_tbl[] = {
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
index 8dcf9d20f449..c70d52ace8b2 100644
--- a/drivers/char/briq_panel.c
+++ b/drivers/char/briq_panel.c
@@ -202,13 +202,16 @@ static struct miscdevice briq_panel_miscdev = {
static int __init briq_panel_init(void)
{
- struct device_node *root = find_path_device("/");
+ struct device_node *root = of_find_node_by_path("/");
const char *machine;
int i;
machine = get_property(root, "model", NULL);
- if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0)
+ if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
+ of_node_put(root);
return -ENODEV;
+ }
+ of_node_put(root);
printk(KERN_INFO
"briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index a0a88aa23f5b..0f9ed7b46a6d 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -47,8 +47,6 @@
#define HVC_MAJOR 229
#define HVC_MINOR 0
-#define TIMEOUT (10)
-
/*
* Wait this long per iteration while trying to push buffered data to the
* hypervisor before allowing the tty to complete a close operation.
@@ -104,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)
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index f144a947bd17..ec420fe8a908 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -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;
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index f9c00844d2bf..94a542e20efb 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -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;
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index 50315d6364fd..d5a752da322f 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -1279,8 +1279,8 @@ static int __init hvsi_console_init(void)
struct hvsi_struct *hp;
const uint32_t *vtermno, *irq;
- vtermno = get_property(vty, "reg", NULL);
- irq = get_property(vty, "interrupts", NULL);
+ vtermno = of_get_property(vty, "reg", NULL);
+ irq = of_get_property(vty, "interrupts", NULL);
if (!vtermno || !irq)
continue;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 78237577b05a..3ef593a9015f 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -1,6 +1,8 @@
/*
* Sony Programmable I/O Control Device driver for VAIO
*
+ * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
+ *
* Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
*
* Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
@@ -95,6 +97,11 @@ module_param(useinput, int, 0444);
MODULE_PARM_DESC(useinput,
"set this if you would like sonypi to feed events to the input subsystem");
+static int check_ioport = 1;
+module_param(check_ioport, int, 0444);
+MODULE_PARM_DESC(check_ioport,
+ "set this to 0 if you think the automatic ioport check for sony-laptop is wrong");
+
#define SONYPI_DEVICE_MODEL_TYPE1 1
#define SONYPI_DEVICE_MODEL_TYPE2 2
#define SONYPI_DEVICE_MODEL_TYPE3 3
@@ -477,7 +484,7 @@ static struct sonypi_device {
u16 evtype_offset;
int camera_power;
int bluetooth_power;
- struct semaphore lock;
+ struct mutex lock;
struct kfifo *fifo;
spinlock_t fifo_lock;
wait_queue_head_t fifo_proc_list;
@@ -884,7 +891,7 @@ int sonypi_camera_command(int command, u8 value)
if (!camera)
return -EIO;
- down(&sonypi_device.lock);
+ mutex_lock(&sonypi_device.lock);
switch (command) {
case SONYPI_COMMAND_SETCAMERA:
@@ -919,7 +926,7 @@ int sonypi_camera_command(int command, u8 value)
command);
break;
}
- up(&sonypi_device.lock);
+ mutex_unlock(&sonypi_device.lock);
return 0;
}
@@ -938,20 +945,20 @@ static int sonypi_misc_fasync(int fd, struct file *filp, int on)
static int sonypi_misc_release(struct inode *inode, struct file *file)
{
sonypi_misc_fasync(-1, file, 0);
- down(&sonypi_device.lock);
+ mutex_lock(&sonypi_device.lock);
sonypi_device.open_count--;
- up(&sonypi_device.lock);
+ mutex_unlock(&sonypi_device.lock);
return 0;
}
static int sonypi_misc_open(struct inode *inode, struct file *file)
{
- down(&sonypi_device.lock);
+ mutex_lock(&sonypi_device.lock);
/* Flush input queue on first open */
if (!sonypi_device.open_count)
kfifo_reset(sonypi_device.fifo);
sonypi_device.open_count++;
- up(&sonypi_device.lock);
+ mutex_unlock(&sonypi_device.lock);
return 0;
}
@@ -1001,7 +1008,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
u8 val8;
u16 val16;
- down(&sonypi_device.lock);
+ mutex_lock(&sonypi_device.lock);
switch (cmd) {
case SONYPI_IOCGBRT:
if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) {
@@ -1101,7 +1108,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
default:
ret = -EINVAL;
}
- up(&sonypi_device.lock);
+ mutex_unlock(&sonypi_device.lock);
return ret;
}
@@ -1260,6 +1267,28 @@ static int __devinit sonypi_create_input_devices(void)
static int __devinit sonypi_setup_ioports(struct sonypi_device *dev,
const struct sonypi_ioport_list *ioport_list)
{
+ /* try to detect if sony-laptop is being used and thus
+ * has already requested one of the known ioports.
+ * As in the deprecated check_region this is racy has we have
+ * multiple ioports available and one of them can be requested
+ * between this check and the subsequent request. Anyway, as an
+ * attempt to be some more user-friendly as we currently are,
+ * this is enough.
+ */
+ const struct sonypi_ioport_list *check = ioport_list;
+ while (check_ioport && check->port1) {
+ if (!request_region(check->port1,
+ sonypi_device.region_size,
+ "Sony Programable I/O Device Check")) {
+ printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? "
+ "if not use check_ioport=0\n",
+ check->port1);
+ return -EBUSY;
+ }
+ release_region(check->port1, sonypi_device.region_size);
+ check++;
+ }
+
while (ioport_list->port1) {
if (request_region(ioport_list->port1,
@@ -1321,6 +1350,10 @@ static int __devinit sonypi_probe(struct platform_device *dev)
struct pci_dev *pcidev;
int error;
+ printk(KERN_WARNING "sonypi: please try the sony-laptop module instead "
+ "and report failures, see also "
+ "http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n");
+
spin_lock_init(&sonypi_device.fifo_lock);
sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
&sonypi_device.fifo_lock);
@@ -1330,7 +1363,7 @@ static int __devinit sonypi_probe(struct platform_device *dev)
}
init_waitqueue_head(&sonypi_device.fifo_proc_list);
- init_MUTEX(&sonypi_device.lock);
+ mutex_init(&sonypi_device.lock);
sonypi_device.bluetooth_power = -1;
if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
index aefd683c60b7..3c852009196e 100644
--- a/drivers/char/tpm/tpm_atmel.h
+++ b/drivers/char/tpm/tpm_atmel.h
@@ -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);
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index e812aa129e28..60198a78974c 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -548,7 +548,7 @@ config MV64X60_WDT
depends on WATCHDOG && MV64X60
config BOOKE_WDT
- tristate "PowerPC Book-E Watchdog Timer"
+ bool "PowerPC Book-E Watchdog Timer"
depends on WATCHDOG && (BOOKE || 4xx)
---help---
Please see Documentation/watchdog/watchdog-api.txt for
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 5ac309ee7f05..5cfcff532545 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -26,7 +26,7 @@
/*
* The I/O port the PMTMR resides at.
* The location is detected during setup_arch(),
- * in arch/i386/acpi/boot.c
+ * in arch/i386/kernel/acpi/boot.c
*/
u32 pmtmr_ioport __read_mostly;
diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c
index f1f0f5d0442c..f5ebad561412 100644
--- a/drivers/hwmon/ams/ams-core.c
+++ b/drivers/hwmon/ams/ams-core.c
@@ -141,10 +141,10 @@ static void ams_worker(struct work_struct *work)
int ams_sensor_attach(void)
{
int result;
- u32 *prop;
+ const u32 *prop;
/* Get orientation */
- prop = (u32*)get_property(ams_info.of_node, "orientation", NULL);
+ prop = get_property(ams_info.of_node, "orientation", NULL);
if (!prop)
return -ENODEV;
ams_info.orient1 = *prop;
diff --git a/drivers/hwmon/ams/ams-i2c.c b/drivers/hwmon/ams/ams-i2c.c
index 0d24bdfea53e..485d333bcb3e 100644
--- a/drivers/hwmon/ams/ams-i2c.c
+++ b/drivers/hwmon/ams/ams-i2c.c
@@ -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;
diff --git a/drivers/hwmon/ams/ams-pmu.c b/drivers/hwmon/ams/ams-pmu.c
index 4636ae031a53..1b01c215bfe7 100644
--- a/drivers/hwmon/ams/ams-pmu.c
+++ b/drivers/hwmon/ams/ams-pmu.c
@@ -146,7 +146,7 @@ static void ams_pmu_exit(void)
int __init ams_pmu_init(struct device_node *np)
{
- u32 *prop;
+ const u32 *prop;
int result;
mutex_lock(&ams_info.lock);
@@ -160,7 +160,7 @@ int __init ams_pmu_init(struct device_node *np)
ams_info.bustype = BUS_HOST;
/* Get PMU command, should be 0x4e, but we can never know */
- prop = (u32*)get_property(ams_info.of_node, "reg", NULL);
+ prop = get_property(ams_info.of_node, "reg", NULL);
if (!prop) {
result = -ENODEV;
goto exit;
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 3b23d677cb86..4700085ba834 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -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);
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index f729eebf771f..adfea3c7c62a 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -90,7 +90,7 @@ static int autopoll_devs;
int __adb_probe_sync;
#ifdef CONFIG_PM
-static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static void adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
static struct pmu_sleep_notifier adb_sleep_notifier = {
adb_notify_sleep,
SLEEP_LEVEL_ADB,
@@ -340,11 +340,9 @@ __initcall(adb_init);
/*
* notify clients before sleep and reset bus afterwards
*/
-int
+void
adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
{
- int ret;
-
switch (when) {
case PBOOK_SLEEP_REQUEST:
adb_got_sleep = 1;
@@ -353,22 +351,8 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
/* Stop autopoll */
if (adb_controller->autopoll)
adb_controller->autopoll(0);
- ret = blocking_notifier_call_chain(&adb_client_list,
- ADB_MSG_POWERDOWN, NULL);
- if (ret & NOTIFY_STOP_MASK) {
- up(&adb_probe_mutex);
- return PBOOK_SLEEP_REFUSE;
- }
- break;
- case PBOOK_SLEEP_REJECT:
- if (adb_got_sleep) {
- adb_got_sleep = 0;
- up(&adb_probe_mutex);
- adb_reset_bus();
- }
- break;
-
- case PBOOK_SLEEP_NOW:
+ blocking_notifier_call_chain(&adb_client_list,
+ ADB_MSG_POWERDOWN, NULL);
break;
case PBOOK_WAKE:
adb_got_sleep = 0;
@@ -376,14 +360,13 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
adb_reset_bus();
break;
}
- return PBOOK_SLEEP_OK;
}
#endif /* CONFIG_PM */
static int
do_adb_reset_bus(void)
{
- int ret, nret;
+ int ret;
if (adb_controller == NULL)
return -ENXIO;
@@ -391,13 +374,8 @@ do_adb_reset_bus(void)
if (adb_controller->autopoll)
adb_controller->autopoll(0);
- nret = blocking_notifier_call_chain(&adb_client_list,
- ADB_MSG_PRE_RESET, NULL);
- if (nret & NOTIFY_STOP_MASK) {
- if (adb_controller->autopoll)
- adb_controller->autopoll(autopoll_devs);
- return -EBUSY;
- }
+ blocking_notifier_call_chain(&adb_client_list,
+ ADB_MSG_PRE_RESET, NULL);
if (sleepy_trackpad) {
/* Let the trackpad settle down */
@@ -427,10 +405,8 @@ do_adb_reset_bus(void)
}
up(&adb_handler_sem);
- nret = blocking_notifier_call_chain(&adb_client_list,
- ADB_MSG_POST_RESET, NULL);
- if (nret & NOTIFY_STOP_MASK)
- return -EBUSY;
+ blocking_notifier_call_chain(&adb_client_list,
+ ADB_MSG_POST_RESET, NULL);
return ret;
}
diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c
index cdd5a0f72e3c..e54c4d9f6365 100644
--- a/drivers/macintosh/ans-lcd.c
+++ b/drivers/macintosh/ans-lcd.c
@@ -145,11 +145,12 @@ anslcd_init(void)
int retval;
struct device_node* node;
- node = find_devices("lcd");
- if (!node || !node->parent)
- return -ENODEV;
- if (strcmp(node->parent->name, "gc"))
+ node = of_find_node_by_name(NULL, "lcd");
+ if (!node || !node->parent || strcmp(node->parent->name, "gc")) {
+ of_node_put(node);
return -ENODEV;
+ }
+ of_node_put(node);
anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20);
diff --git a/drivers/macintosh/apm_emu.c b/drivers/macintosh/apm_emu.c
index c5e4d43f97fc..cdb0bead9917 100644
--- a/drivers/macintosh/apm_emu.c
+++ b/drivers/macintosh/apm_emu.c
@@ -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
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index c1fd816e9f09..1599dc34f15f 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -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;
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index 026b67f4f659..79119f56e82d 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -82,7 +82,14 @@ struct adb_driver macio_adb_driver = {
int macio_probe(void)
{
- return find_compatible_devices("adb", "chrp,adb0")? 0: -ENODEV;
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, "adb", "chrp,adb0");
+ if (np) {
+ of_node_put(np);
+ return 0;
+ }
+ return -ENODEV;
}
int macio_init(void)
@@ -91,12 +98,14 @@ int macio_init(void)
struct resource r;
unsigned int irq;
- adbs = find_compatible_devices("adb", "chrp,adb0");
+ adbs = of_find_compatible_node(NULL, "adb", "chrp,adb0");
if (adbs == 0)
return -ENXIO;
- if (of_address_to_resource(adbs, 0, &r))
+ if (of_address_to_resource(adbs, 0, &r)) {
+ of_node_put(adbs);
return -ENXIO;
+ }
adb = ioremap(r.start, sizeof(struct adb_regs));
out_8(&adb->ctrl.r, 0);
@@ -107,6 +116,7 @@ int macio_init(void)
out_8(&adb->autopoll.r, APE);
irq = irq_of_parse_and_map(adbs, 0);
+ of_node_put(adbs);
if (request_irq(irq, macio_adb_interrupt, 0, "ADB", (void *)0)) {
printk(KERN_ERR "ADB: can't get irq %d\n", irq);
return -EAGAIN;
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index d56216067549..c96b7fe882a4 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -134,108 +134,12 @@ static int macio_device_resume(struct device * dev)
return 0;
}
-static int macio_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
-{
- struct macio_dev * macio_dev;
- struct of_device * of;
- char *scratch;
- const char *compat, *compat2;
-
- int i = 0;
- int length, cplen, cplen2, seen = 0;
-
- if (!dev)
- return -ENODEV;
-
- macio_dev = to_macio_device(dev);
- if (!macio_dev)
- return -ENODEV;
-
- of = &macio_dev->ofdev;
-
- /* stuff we want to pass to /sbin/hotplug */
- envp[i++] = scratch = buffer;
- length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name);
- ++length;
- buffer_size -= length;
- if ((buffer_size <= 0) || (i >= num_envp))
- return -ENOMEM;
- scratch += length;
-
- envp[i++] = scratch;
- length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type);
- ++length;
- buffer_size -= length;
- if ((buffer_size <= 0) || (i >= num_envp))
- return -ENOMEM;
- scratch += length;
-
- /* Since the compatible field can contain pretty much anything
- * it's not really legal to split it out with commas. We split it
- * up using a number of environment variables instead. */
-
- compat = get_property(of->node, "compatible", &cplen);
- compat2 = compat;
- cplen2= cplen;
- while (compat && cplen > 0) {
- envp[i++] = scratch;
- length = scnprintf (scratch, buffer_size,
- "OF_COMPATIBLE_%d=%s", seen, compat);
- ++length;
- buffer_size -= length;
- if ((buffer_size <= 0) || (i >= num_envp))
- return -ENOMEM;
- scratch += length;
- length = strlen (compat) + 1;
- compat += length;
- cplen -= length;
- seen++;
- }
-
- envp[i++] = scratch;
- length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen);
- ++length;
- buffer_size -= length;
- if ((buffer_size <= 0) || (i >= num_envp))
- return -ENOMEM;
- scratch += length;
-
- envp[i++] = scratch;
- length = scnprintf (scratch, buffer_size, "MODALIAS=of:N%sT%s",
- of->node->name, of->node->type);
- /* overwrite '\0' */
- buffer_size -= length;
- if ((buffer_size <= 0) || (i >= num_envp))
- return -ENOMEM;
- scratch += length;
-
- if (!compat2) {
- compat2 = "";
- cplen2 = 1;
- }
- while (cplen2 > 0) {
- length = snprintf (scratch, buffer_size, "C%s", compat2);
- buffer_size -= length;
- if (buffer_size <= 0)
- return -ENOMEM;
- scratch += length;
- length = strlen (compat2) + 1;
- compat2 += length;
- cplen2 -= length;
- }
-
- envp[i] = NULL;
-
- return 0;
-}
-
extern struct device_attribute macio_dev_attrs[];
struct bus_type macio_bus_type = {
.name = "macio",
.match = macio_bus_match,
- .uevent = macio_uevent,
+ .uevent = of_device_uevent,
.probe = macio_device_probe,
.remove = macio_device_remove,
.shutdown = macio_device_shutdown,
@@ -491,7 +395,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
#endif
MAX_NODE_NAME_SIZE, np->name);
} else {
- reg = get_property(np, "reg", NULL);
+ reg = of_get_property(np, "reg", NULL);
sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s",
chip->lbus.index,
reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c
index 8566bdfdd4b8..cc8267912656 100644
--- a/drivers/macintosh/macio_sysfs.c
+++ b/drivers/macintosh/macio_sysfs.c
@@ -21,7 +21,7 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
int length = 0;
of = &to_macio_device (dev)->ofdev;
- compat = get_property(of->node, "compatible", &cplen);
+ compat = of_get_property(of->node, "compatible", &cplen);
if (!compat) {
*buf = '\0';
return 0;
@@ -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;
}
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index f83fad2a3ff4..4177ff004753 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -387,7 +387,7 @@ static int __devinit rackmeter_probe(struct macio_dev* mdev,
if (strcmp(np->name, "lightshow") == 0)
break;
if ((strcmp(np->name, "sound") == 0) &&
- get_property(np, "virtual", NULL) != NULL)
+ of_get_property(np, "virtual", NULL) != NULL)
break;
}
if (np == NULL) {
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index c9f3dc4fd3ee..a98a328b1cfc 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -491,7 +491,7 @@ int __init smu_init (void)
printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n");
goto fail;
}
- data = get_property(smu->db_node, "reg", NULL);
+ data = of_get_property(smu->db_node, "reg", NULL);
if (data == NULL) {
of_node_put(smu->db_node);
smu->db_node = NULL;
@@ -512,7 +512,7 @@ int __init smu_init (void)
smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt");
if (smu->msg_node == NULL)
break;
- data = get_property(smu->msg_node, "reg", NULL);
+ data = of_get_property(smu->msg_node, "reg", NULL);
if (data == NULL) {
of_node_put(smu->msg_node);
smu->msg_node = NULL;
@@ -952,7 +952,7 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
prop->name = ((char *)prop) + tlen - 18;
sprintf(prop->name, "sdb-partition-%02x", id);
prop->length = len;
- prop->value = (unsigned char *)hdr;
+ prop->value = hdr;
prop->next = NULL;
/* Read the datablock */
@@ -1004,7 +1004,7 @@ const struct smu_sdbp_header *__smu_get_sdb_partition(int id,
} else
mutex_lock(&smu_part_access);
- part = get_property(smu->of_node, pname, size);
+ part = of_get_property(smu->of_node, pname, size);
if (part == NULL) {
DPRINTK("trying to extract from SMU ...\n");
part = smu_create_sdb_partition(id);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index a7ce55926638..228903403cfc 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -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)
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index 2e4ad44a8636..78ff18617139 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -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);
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index a1d3a987cb3a..35233de460ad 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -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") )
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index d58fcf6cca0a..76d21775fc35 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -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;
diff --git a/drivers/macintosh/via-pmu-led.c b/drivers/macintosh/via-pmu-led.c
index 179af10105d9..fc89a7047cd0 100644
--- a/drivers/macintosh/via-pmu-led.c
+++ b/drivers/macintosh/via-pmu-led.c
@@ -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;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index b6073bdb50c3..1729d3fd7a11 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -289,7 +289,7 @@ int __init find_via_pmu(void)
if (vias == NULL)
return 0;
- reg = get_property(vias, "reg", NULL);
+ reg = of_get_property(vias, "reg", NULL);
if (reg == NULL) {
printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
goto fail;
@@ -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();
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 3f7967feaf5b..ab4d1b63f63e 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -176,7 +176,7 @@ static int wf_lm75_attach(struct i2c_adapter *adapter)
for (dev = NULL;
(dev = of_get_next_child(busnode, dev)) != NULL;) {
const char *loc =
- get_property(dev, "hwsensor-location", NULL);
+ of_get_property(dev, "hwsensor-location", NULL);
u8 addr;
/* We must re-match the adapter in order to properly check
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index eae1189d6c41..eaa74afa175b 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -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);
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 31b750d61206..ff398adc0283 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -167,7 +167,7 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
if (fct == NULL)
return NULL;
fct->ctrl.ops = &smu_fan_ops;
- l = get_property(node, "location", NULL);
+ l = of_get_property(node, "location", NULL);
if (l == NULL)
goto fail;
@@ -224,17 +224,17 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
goto fail;
/* Get min & max values*/
- v = get_property(node, "min-value", NULL);
+ v = of_get_property(node, "min-value", NULL);
if (v == NULL)
goto fail;
fct->min = *v;
- v = get_property(node, "max-value", NULL);
+ v = of_get_property(node, "max-value", NULL);
if (v == NULL)
goto fail;
fct->max = *v;
/* Get "reg" value */
- reg = get_property(node, "reg", NULL);
+ reg = of_get_property(node, "reg", NULL);
if (reg == NULL)
goto fail;
fct->reg = *reg;
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 83f79de7174b..9a6c2cf8fd0e 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -241,7 +241,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
char *name;
int vsens[2], isens[2];
- reg = get_property(dev, "reg", NULL);
+ reg = of_get_property(dev, "reg", NULL);
if (reg == NULL)
return;
addr = *reg;
@@ -268,9 +268,9 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
isens[0] = isens[1] = -1;
child = NULL;
while ((child = of_get_next_child(dev, child)) != NULL) {
- reg = get_property(child, "reg", NULL);
- type = get_property(child, "device_type", NULL);
- loc = get_property(child, "location", NULL);
+ reg = of_get_property(child, "reg", NULL);
+ type = of_get_property(child, "device_type", NULL);
+ loc = of_get_property(child, "location", NULL);
if (reg == NULL || loc == NULL)
continue;
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index 01b4c50143dd..9c567b93f417 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -204,8 +204,8 @@ static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL);
if (ads == NULL)
return NULL;
- c = get_property(node, "device_type", NULL);
- l = get_property(node, "location", NULL);
+ c = of_get_property(node, "device_type", NULL);
+ l = of_get_property(node, "location", NULL);
if (c == NULL || l == NULL)
goto fail;
@@ -255,7 +255,7 @@ static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
} else
goto fail;
- v = get_property(node, "reg", NULL);
+ v = of_get_property(node, "reg", NULL);
if (v == NULL)
goto fail;
ads->reg = *v;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 4c2471ee054a..d8121234c347 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -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;
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 4eb73d395213..8bdc8a87b249 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -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;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 3668b170ea68..11a98df298ec 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1012,7 +1012,7 @@ static struct mapped_device *alloc_dev(int minor)
if (!md->tio_pool)
goto bad3;
- md->bs = bioset_create(16, 16, 4);
+ md->bs = bioset_create(16, 16);
if (!md->bs)
goto bad_no_bioset;
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 639e8b6c35b1..bc773781993a 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -577,14 +577,14 @@ config VIDEO_ZORAN_AVS6EYES
config VIDEO_MEYE
tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
- depends on PCI && SONYPI && VIDEO_V4L1
+ depends on PCI && SONY_LAPTOP && VIDEO_V4L1
---help---
This is the video4linux driver for the Motion Eye camera found
in the Vaio Picturebook laptops. Please read the material in
<file:Documentation/video4linux/meye.txt> for more information.
- If you say Y or M here, you need to say Y or M to "Sony Programmable
- I/O Control Device" in the character device section.
+ If you say Y or M here, you need to say Y or M to "Sony Laptop
+ Extras" in the misc device section.
To compile this driver as a module, choose M here: the
module will be called meye.
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 98681da5e3b9..664aba8b4d85 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -925,13 +925,13 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV)
return -EINVAL;
mutex_lock(&meye.lock);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS,
p->brightness >> 10);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE,
p->hue >> 10);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR,
p->colour >> 10);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST,
p->contrast >> 10);
meye.picture = *p;
mutex_unlock(&meye.lock);
@@ -1043,11 +1043,11 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
meye.params.quality != jp->quality)
mchip_hic_stop(); /* need restart */
meye.params = *jp;
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
meye.params.sharpness);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
meye.params.agc);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
meye.params.picture);
mutex_unlock(&meye.lock);
break;
@@ -1287,38 +1287,38 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
mutex_lock(&meye.lock);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERABRIGHTNESS, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
meye.picture.brightness = c->value << 10;
break;
case V4L2_CID_HUE:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERAHUE, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
meye.picture.hue = c->value << 10;
break;
case V4L2_CID_CONTRAST:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERACONTRAST, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
meye.picture.contrast = c->value << 10;
break;
case V4L2_CID_SATURATION:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERACOLOR, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
meye.picture.colour = c->value << 10;
break;
case V4L2_CID_AGC:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERAAGC, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
meye.params.agc = c->value;
break;
case V4L2_CID_SHARPNESS:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERASHARPNESS, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
meye.params.sharpness = c->value;
break;
case V4L2_CID_PICTURE:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERAPICTURE, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
meye.params.picture = c->value;
break;
case V4L2_CID_JPEGQUAL:
@@ -1848,7 +1848,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
memcpy(meye.video_dev, &meye_template, sizeof(meye_template));
meye.video_dev->dev = &meye.mchip_dev->dev;
- if ((ret = sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 1))) {
+ if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
printk(KERN_ERR "meye: unable to power on the camera\n");
printk(KERN_ERR "meye: did you enable the camera in "
"sonypi using the module options ?\n");
@@ -1928,13 +1928,13 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
meye.params.picture = 0;
meye.params.framerate = 0;
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, 32);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, 32);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, 32);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, 32);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, 32);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, 0);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, 48);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, 32);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, 32);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, 32);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, 32);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, 32);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
printk(KERN_INFO "meye: Motion Eye Camera Driver v%s.\n",
MEYE_DRIVER_VERSION);
@@ -1953,7 +1953,7 @@ outremap:
outregions:
pci_disable_device(meye.mchip_dev);
outenabledev:
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
outsonypienable:
kfifo_free(meye.doneq);
outkfifoalloc2:
@@ -1986,7 +1986,7 @@ static void __devexit meye_remove(struct pci_dev *pcidev)
pci_disable_device(meye.mchip_dev);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
kfifo_free(meye.doneq);
kfifo_free(meye.grabq);
diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h
index ea107cb5c845..323d0074120d 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/video/meye.h
@@ -255,7 +255,7 @@
/****************************************************************************/
/* Sony Programmable I/O Controller for accessing the camera commands */
-#include <linux/sonypi.h>
+#include <linux/sony-laptop.h>
/* private API definitions */
#include <linux/meye.h>
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index fe184f93c016..1455a8f4e930 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -2160,7 +2160,7 @@ static int find_planb(void)
if (!machine_is(powermac))
return 0;
- planb_devices = find_devices("planb");
+ planb_devices = of_find_node_by_name(NULL, "planb");
if (planb_devices == 0) {
planb_num=0;
printk(KERN_WARNING "PlanB: no device found!\n");
@@ -2175,12 +2175,14 @@ static int find_planb(void)
if (planb_devices->n_addrs != 1) {
printk (KERN_WARNING "PlanB: expecting 1 address for planb "
"(got %d)", planb_devices->n_addrs);
+ of_node_put(planb_devices);
return 0;
}
if (planb_devices->n_intrs == 0) {
printk(KERN_WARNING "PlanB: no intrs for device %s\n",
planb_devices->full_name);
+ of_node_put(planb_devices);
return 0;
} else {
irq = planb_devices->intrs[0].line;
@@ -2202,6 +2204,7 @@ static int find_planb(void)
confreg = planb_devices->addrs[0].space & 0xff;
old_base = planb_devices->addrs[0].address;
new_base = 0xf1000000;
+ of_node_put(planb_devices);
DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
"membase 0x%x (base reg. 0x%x)\n",
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 80b199fa0aa9..a3c525b2616a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -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
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7793ccd79049..e32516459138 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -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
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 4b232124a1ab..65c32a95e121 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -3,7 +3,7 @@
*
*
* Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
- * Copyright (C) 2006 Corentin Chary
+ * Copyright (C) 2006-2007 Corentin Chary
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -48,7 +48,7 @@
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
-#define ASUS_LAPTOP_VERSION "0.40"
+#define ASUS_LAPTOP_VERSION "0.41"
#define ASUS_HOTK_NAME "Asus Laptop Support"
#define ASUS_HOTK_CLASS "hotkey"
@@ -81,7 +81,8 @@
#define TLED_ON 0x08 //touchpad LED
#define RLED_ON 0x10 //Record LED
#define PLED_ON 0x20 //Phone LED
-#define LCD_ON 0x40 //LCD backlight
+#define GLED_ON 0x40 //Gaming LED
+#define LCD_ON 0x80 //LCD backlight
#define ASUS_LOG ASUS_HOTK_FILE ": "
#define ASUS_ERR KERN_ERR ASUS_LOG
@@ -94,6 +95,19 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
MODULE_DESCRIPTION(ASUS_HOTK_NAME);
MODULE_LICENSE("GPL");
+/* WAPF defines the behavior of the Fn+Fx wlan key
+ * The significance of values is yet to be found, but
+ * most of the time:
+ * 0x0 will do nothing
+ * 0x1 will allow to control the device with Fn+Fx key.
+ * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key
+ * 0x5 like 0x1 or 0x4
+ * So, if something doesn't work as you want, just try other values =)
+ */
+static uint wapf = 1;
+module_param(wapf, uint, 0644);
+MODULE_PARM_DESC(wapf, "WAPF value");
+
#define ASUS_HANDLE(object, paths...) \
static acpi_handle object##_handle = NULL; \
static char *object##_paths[] = { paths }
@@ -103,6 +117,7 @@ ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");
ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */
ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */
+ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */
/* LEDD */
ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
@@ -221,6 +236,7 @@ ASUS_LED(mled, "mail");
ASUS_LED(tled, "touchpad");
ASUS_LED(rled, "record");
ASUS_LED(pled, "phone");
+ASUS_LED(gled, "gaming");
/*
* This function evaluates an ACPI method, given an int as parameter, the
@@ -245,32 +261,19 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
return (status == AE_OK);
}
-static int read_acpi_int(acpi_handle handle, const char *method, int *val,
- struct acpi_object_list *params)
-{
- struct acpi_buffer output;
- union acpi_object out_obj;
- acpi_status status;
-
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
-
- status = acpi_evaluate_object(handle, (char *)method, params, &output);
- *val = out_obj.integer.value;
- return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
-}
-
static int read_wireless_status(int mask)
{
- int status;
+ ulong status;
+ acpi_status rv = AE_OK;
if (!wireless_status_handle)
return (hotk->status & mask) ? 1 : 0;
- if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) {
- return (status & mask) ? 1 : 0;
- } else
+ rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status);
+ if (ACPI_FAILURE(rv))
printk(ASUS_WARNING "Error reading Wireless status\n");
+ else
+ return (status & mask) ? 1 : 0;
return (hotk->status & mask) ? 1 : 0;
}
@@ -285,19 +288,28 @@ static int read_status(int mask)
return (hotk->status & mask) ? 1 : 0;
}
-static void write_status(acpi_handle handle, int out, int mask, int invert)
+static void write_status(acpi_handle handle, int out, int mask)
{
hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
- if (invert) /* invert target value */
+ switch (mask) {
+ case MLED_ON:
out = !out & 0x1;
+ break;
+ case GLED_ON:
+ out = (out & 0x1) + 1;
+ break;
+ default:
+ out &= 0x1;
+ break;
+ }
if (handle && !write_acpi_int(handle, NULL, out, NULL))
- printk(ASUS_WARNING " write failed\n");
+ printk(ASUS_WARNING " write failed %x\n", mask);
}
/* /sys/class/led handlers */
-#define ASUS_LED_HANDLER(object, mask, invert) \
+#define ASUS_LED_HANDLER(object, mask) \
static void object##_led_set(struct led_classdev *led_cdev, \
enum led_brightness value) \
{ \
@@ -307,13 +319,14 @@ static void write_status(acpi_handle handle, int out, int mask, int invert)
static void object##_led_update(struct work_struct *ignored) \
{ \
int value = object##_led_wk; \
- write_status(object##_set_handle, value, (mask), (invert)); \
+ write_status(object##_set_handle, value, (mask)); \
}
-ASUS_LED_HANDLER(mled, MLED_ON, 1);
-ASUS_LED_HANDLER(pled, PLED_ON, 0);
-ASUS_LED_HANDLER(rled, RLED_ON, 0);
-ASUS_LED_HANDLER(tled, TLED_ON, 0);
+ASUS_LED_HANDLER(mled, MLED_ON);
+ASUS_LED_HANDLER(pled, PLED_ON);
+ASUS_LED_HANDLER(rled, RLED_ON);
+ASUS_LED_HANDLER(tled, TLED_ON);
+ASUS_LED_HANDLER(gled, GLED_ON);
static int get_lcd_state(void)
{
@@ -338,7 +351,7 @@ static int set_lcd_state(int value)
printk(ASUS_WARNING "Error switching LCD\n");
}
- write_status(NULL, lcd, LCD_ON, 0);
+ write_status(NULL, lcd, LCD_ON);
return 0;
}
@@ -354,9 +367,11 @@ static void lcd_blank(int blank)
static int read_brightness(struct backlight_device *bd)
{
- int value;
+ ulong value;
+ acpi_status rv = AE_OK;
- if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL))
+ rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
+ if (ACPI_FAILURE(rv))
printk(ASUS_WARNING "Error reading brightness\n");
return value;
@@ -403,8 +418,10 @@ static ssize_t show_infos(struct device *dev,
struct device_attribute *attr, char *page)
{
int len = 0;
- int temp;
+ ulong temp;
char buf[16]; //enough for all info
+ acpi_status rv = AE_OK;
+
/*
* We use the easy way, we don't care of off and count, so we don't set eof
* to 1
@@ -418,9 +435,10 @@ static ssize_t show_infos(struct device *dev,
* bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
* The significance of others is yet to be found.
*/
- if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL))
- len +=
- sprintf(page + len, "SFUN value : 0x%04x\n", temp);
+ rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
+ if (!ACPI_FAILURE(rv))
+ len += sprintf(page + len, "SFUN value : 0x%04x\n",
+ (uint) temp);
/*
* Another value for userspace: the ASYM method returns 0x02 for
* battery low and 0x04 for battery critical, its readings tend to be
@@ -428,9 +446,10 @@ static ssize_t show_infos(struct device *dev,
* Note: since not all the laptops provide this method, errors are
* silently ignored.
*/
- if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL))
- len +=
- sprintf(page + len, "ASYM value : 0x%04x\n", temp);
+ rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
+ if (!ACPI_FAILURE(rv))
+ len += sprintf(page + len, "ASYM value : 0x%04x\n",
+ (uint) temp);
if (asus_info) {
snprintf(buf, 16, "%d", asus_info->length);
len += sprintf(page + len, "DSDT length : %s\n", buf);
@@ -465,7 +484,7 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
}
static ssize_t store_status(const char *buf, size_t count,
- acpi_handle handle, int mask, int invert)
+ acpi_handle handle, int mask)
{
int rv, value;
int out = 0;
@@ -474,7 +493,7 @@ static ssize_t store_status(const char *buf, size_t count,
if (rv > 0)
out = value ? 1 : 0;
- write_status(handle, out, mask, invert);
+ write_status(handle, out, mask);
return rv;
}
@@ -515,7 +534,7 @@ static ssize_t show_wlan(struct device *dev,
static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- return store_status(buf, count, wl_switch_handle, WL_ON, 0);
+ return store_status(buf, count, wl_switch_handle, WL_ON);
}
/*
@@ -531,7 +550,7 @@ static ssize_t store_bluetooth(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
- return store_status(buf, count, bt_switch_handle, BT_ON, 0);
+ return store_status(buf, count, bt_switch_handle, BT_ON);
}
/*
@@ -547,12 +566,15 @@ static void set_display(int value)
static int read_display(void)
{
- int value = 0;
+ ulong value = 0;
+ acpi_status rv = AE_OK;
/* In most of the case, we know how to set the display, but sometime
we can't read it */
if (display_get_handle) {
- if (!read_acpi_int(display_get_handle, NULL, &value, NULL))
+ rv = acpi_evaluate_integer(display_get_handle, NULL,
+ NULL, &value);
+ if (ACPI_FAILURE(rv))
printk(ASUS_WARNING "Error reading display status\n");
}
@@ -656,10 +678,10 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
* switched
*/
if (event == ATKD_LCD_ON) {
- write_status(NULL, 1, LCD_ON, 0);
+ write_status(NULL, 1, LCD_ON);
lcd_blank(FB_BLANK_UNBLANK);
} else if (event == ATKD_LCD_OFF) {
- write_status(NULL, 0, LCD_ON, 0);
+ write_status(NULL, 0, LCD_ON);
lcd_blank(FB_BLANK_POWERDOWN);
}
@@ -771,7 +793,7 @@ static int asus_hotk_get_info(void)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL;
- int bsts_result, hwrs_result;
+ ulong bsts_result, hwrs_result;
char *string = NULL;
acpi_status status;
@@ -794,11 +816,16 @@ static int asus_hotk_get_info(void)
}
/* This needs to be called for some laptops to init properly */
- if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL))
+ status =
+ acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result);
+ if (ACPI_FAILURE(status))
printk(ASUS_WARNING "Error calling BSTS\n");
else if (bsts_result)
printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
- bsts_result);
+ (uint) bsts_result);
+
+ /* This too ... */
+ write_acpi_int(hotk->handle, "CWAP", wapf, NULL);
/*
* Try to match the object returned by INIT to the specific model.
@@ -831,6 +858,7 @@ static int asus_hotk_get_info(void)
ASUS_HANDLE_INIT(tled_set);
ASUS_HANDLE_INIT(rled_set);
ASUS_HANDLE_INIT(pled_set);
+ ASUS_HANDLE_INIT(gled_set);
ASUS_HANDLE_INIT(ledd_set);
@@ -840,7 +868,9 @@ static int asus_hotk_get_info(void)
* The significance of others is yet to be found.
* If we don't find the method, we assume the device are present.
*/
- if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL))
+ status =
+ acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result);
+ if (ACPI_FAILURE(status))
hwrs_result = WL_HWRS | BT_HWRS;
if (hwrs_result & WL_HWRS)
@@ -928,11 +958,15 @@ static int asus_hotk_add(struct acpi_device *device)
asus_hotk_found = 1;
/* WLED and BLED are on by default */
- write_status(bt_switch_handle, 1, BT_ON, 0);
- write_status(wl_switch_handle, 1, WL_ON, 0);
+ write_status(bt_switch_handle, 1, BT_ON);
+ write_status(wl_switch_handle, 1, WL_ON);
+
+ /* If the h/w switch is off, we need to check the real status */
+ write_status(NULL, read_status(BT_ON), BT_ON);
+ write_status(NULL, read_status(WL_ON), WL_ON);
/* LCD Backlight is on by default */
- write_status(NULL, 1, LCD_ON, 0);
+ write_status(NULL, 1, LCD_ON);
/* LED display is off by default */
hotk->ledd_status = 0xFFF;
@@ -991,6 +1025,7 @@ static void asus_led_exit(void)
ASUS_LED_UNREGISTER(tled);
ASUS_LED_UNREGISTER(pled);
ASUS_LED_UNREGISTER(rled);
+ ASUS_LED_UNREGISTER(gled);
destroy_workqueue(led_workqueue);
}
@@ -1062,6 +1097,10 @@ static int asus_led_init(struct device *dev)
if (rv)
return rv;
+ rv = ASUS_LED_REGISTER(gled, dev);
+ if (rv)
+ return rv;
+
led_workqueue = create_singlethread_workqueue("led_workqueue");
if (!led_workqueue)
return -ENOMEM;
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index ac708bc2f9f3..c15c1f61bd1b 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -1,5 +1,5 @@
/*
- * ACPI Sony Notebook Control Driver (SNC)
+ * ACPI Sony Notebook Control Driver (SNC and SPIC)
*
* Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
* Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
@@ -7,6 +7,25 @@
* Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
* which are copyrighted by their respective authors.
*
+ * The SNY6001 driver part is based on the sonypi driver which includes
+ * material from:
+ *
+ * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ *
+ * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
+ *
+ * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
+ *
+ * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -31,40 +50,404 @@
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/err.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/kfifo.h>
+#include <linux/workqueue.h>
+#include <linux/acpi.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
+#include <linux/sonypi.h>
+#include <linux/sony-laptop.h>
+#ifdef CONFIG_SONY_LAPTOP_OLD
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#endif
-#define ACPI_SNC_CLASS "sony"
-#define ACPI_SNC_HID "SNY5001"
-#define ACPI_SNC_DRIVER_NAME "ACPI Sony Notebook Control Driver v0.4"
+#define DRV_PFX "sony-laptop: "
+#define dprintk(msg...) do { \
+ if (debug) printk(KERN_WARNING DRV_PFX msg); \
+} while (0)
-/* the device uses 1-based values, while the backlight subsystem uses
- 0-based values */
-#define SONY_MAX_BRIGHTNESS 8
+#define SONY_LAPTOP_DRIVER_VERSION "0.5"
+
+#define SONY_NC_CLASS "sony-nc"
+#define SONY_NC_HID "SNY5001"
+#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver"
-#define LOG_PFX KERN_WARNING "sony-laptop: "
+#define SONY_PIC_CLASS "sony-pic"
+#define SONY_PIC_HID "SNY6001"
+#define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver"
MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
-MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME);
+MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
MODULE_LICENSE("GPL");
+MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION);
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
"the development of this driver");
-static ssize_t sony_acpi_show(struct device *, struct device_attribute *,
+static int no_spic; /* = 0 */
+module_param(no_spic, int, 0444);
+MODULE_PARM_DESC(no_spic,
+ "set this if you don't want to enable the SPIC device");
+
+static int compat; /* = 0 */
+module_param(compat, int, 0444);
+MODULE_PARM_DESC(compat,
+ "set this if you want to enable backward compatibility mode");
+
+static unsigned long mask = 0xffffffff;
+module_param(mask, ulong, 0644);
+MODULE_PARM_DESC(mask,
+ "set this to the mask of event you want to enable (see doc)");
+
+static int camera; /* = 0 */
+module_param(camera, int, 0444);
+MODULE_PARM_DESC(camera,
+ "set this to 1 to enable Motion Eye camera controls "
+ "(only use it if you have a C1VE or C1VN model)");
+
+#ifdef CONFIG_SONY_LAPTOP_OLD
+static int minor = -1;
+module_param(minor, int, 0);
+MODULE_PARM_DESC(minor,
+ "minor number of the misc device for the SPIC compatibility code, "
+ "default is -1 (automatic)");
+#endif
+
+/*********** Input Devices ***********/
+
+#define SONY_LAPTOP_BUF_SIZE 128
+struct sony_laptop_input_s {
+ atomic_t users;
+ struct input_dev *jog_dev;
+ struct input_dev *key_dev;
+ struct kfifo *fifo;
+ spinlock_t fifo_lock;
+ struct workqueue_struct *wq;
+};
+static struct sony_laptop_input_s sony_laptop_input = {
+ .users = ATOMIC_INIT(0),
+};
+
+struct sony_laptop_keypress {
+ struct input_dev *dev;
+ int key;
+};
+
+/* Correspondance table between sonypi events and input layer events */
+static struct {
+ int sonypiev;
+ int inputev;
+} sony_laptop_inputkeys[] = {
+ { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
+ { SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
+ { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
+ { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
+ { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
+ { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
+ { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
+ { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
+ { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
+ { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
+ { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
+ { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
+ { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
+ { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
+ { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
+ { SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
+ { SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
+ { SONYPI_EVENT_FNKEY_D, KEY_FN_D },
+ { SONYPI_EVENT_FNKEY_E, KEY_FN_E },
+ { SONYPI_EVENT_FNKEY_F, KEY_FN_F },
+ { SONYPI_EVENT_FNKEY_S, KEY_FN_S },
+ { SONYPI_EVENT_FNKEY_B, KEY_FN_B },
+ { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
+ { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
+ { SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
+ { SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
+ { SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
+ { SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
+ { SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
+ { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
+ { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
+ { 0, 0 },
+};
+
+/* release buttons after a short delay if pressed */
+static void do_sony_laptop_release_key(struct work_struct *work)
+{
+ struct sony_laptop_keypress kp;
+
+ while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
+ sizeof(kp)) == sizeof(kp)) {
+ msleep(10);
+ input_report_key(kp.dev, kp.key, 0);
+ input_sync(kp.dev);
+ }
+}
+static DECLARE_WORK(sony_laptop_release_key_work,
+ do_sony_laptop_release_key);
+
+/* forward event to the input subsytem */
+static void sony_laptop_report_input_event(u8 event)
+{
+ struct input_dev *jog_dev = sony_laptop_input.jog_dev;
+ struct input_dev *key_dev = sony_laptop_input.key_dev;
+ struct sony_laptop_keypress kp = { NULL };
+ int i;
+
+ if (event == SONYPI_EVENT_FNKEY_RELEASED) {
+ /* Nothing, not all VAIOs generate this event */
+ return;
+ }
+
+ /* report events */
+ switch (event) {
+ /* jog_dev events */
+ case SONYPI_EVENT_JOGDIAL_UP:
+ case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
+ input_report_rel(jog_dev, REL_WHEEL, 1);
+ input_sync(jog_dev);
+ return;
+
+ case SONYPI_EVENT_JOGDIAL_DOWN:
+ case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
+ input_report_rel(jog_dev, REL_WHEEL, -1);
+ input_sync(jog_dev);
+ return;
+
+ /* key_dev events */
+ case SONYPI_EVENT_JOGDIAL_PRESSED:
+ kp.key = BTN_MIDDLE;
+ kp.dev = jog_dev;
+ break;
+
+ default:
+ for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
+ if (event == sony_laptop_inputkeys[i].sonypiev) {
+ kp.dev = key_dev;
+ kp.key = sony_laptop_inputkeys[i].inputev;
+ break;
+ }
+ break;
+ }
+
+ if (kp.dev) {
+ input_report_key(kp.dev, kp.key, 1);
+ input_sync(kp.dev);
+ kfifo_put(sony_laptop_input.fifo,
+ (unsigned char *)&kp, sizeof(kp));
+
+ if (!work_pending(&sony_laptop_release_key_work))
+ queue_work(sony_laptop_input.wq,
+ &sony_laptop_release_key_work);
+ } else
+ dprintk("unknown input event %.2x\n", event);
+}
+
+static int sony_laptop_setup_input(void)
+{
+ struct input_dev *jog_dev;
+ struct input_dev *key_dev;
+ int i;
+ int error;
+
+ /* don't run again if already initialized */
+ if (atomic_add_return(1, &sony_laptop_input.users) > 1)
+ return 0;
+
+ /* kfifo */
+ spin_lock_init(&sony_laptop_input.fifo_lock);
+ sony_laptop_input.fifo =
+ kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
+ &sony_laptop_input.fifo_lock);
+ if (IS_ERR(sony_laptop_input.fifo)) {
+ printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+ error = PTR_ERR(sony_laptop_input.fifo);
+ goto err_dec_users;
+ }
+
+ /* init workqueue */
+ sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");
+ if (!sony_laptop_input.wq) {
+ printk(KERN_ERR DRV_PFX
+ "Unabe to create workqueue.\n");
+ error = -ENXIO;
+ goto err_free_kfifo;
+ }
+
+ /* input keys */
+ key_dev = input_allocate_device();
+ if (!key_dev) {
+ error = -ENOMEM;
+ goto err_destroy_wq;
+ }
+
+ key_dev->name = "Sony Vaio Keys";
+ key_dev->id.bustype = BUS_ISA;
+ key_dev->id.vendor = PCI_VENDOR_ID_SONY;
+
+ /* Initialize the Input Drivers: special keys */
+ key_dev->evbit[0] = BIT(EV_KEY);
+ for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
+ if (sony_laptop_inputkeys[i].inputev)
+ set_bit(sony_laptop_inputkeys[i].inputev,
+ key_dev->keybit);
+
+ error = input_register_device(key_dev);
+ if (error)
+ goto err_free_keydev;
+
+ sony_laptop_input.key_dev = key_dev;
+
+ /* jogdial */
+ jog_dev = input_allocate_device();
+ if (!jog_dev) {
+ error = -ENOMEM;
+ goto err_unregister_keydev;
+ }
+
+ jog_dev->name = "Sony Vaio Jogdial";
+ jog_dev->id.bustype = BUS_ISA;
+ jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
+
+ jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
+ jog_dev->relbit[0] = BIT(REL_WHEEL);
+
+ error = input_register_device(jog_dev);
+ if (error)
+ goto err_free_jogdev;
+
+ sony_laptop_input.jog_dev = jog_dev;
+
+ return 0;
+
+err_free_jogdev:
+ input_free_device(jog_dev);
+
+err_unregister_keydev:
+ input_unregister_device(key_dev);
+ /* to avoid kref underflow below at input_free_device */
+ key_dev = NULL;
+
+err_free_keydev:
+ input_free_device(key_dev);
+
+err_destroy_wq:
+ destroy_workqueue(sony_laptop_input.wq);
+
+err_free_kfifo:
+ kfifo_free(sony_laptop_input.fifo);
+
+err_dec_users:
+ atomic_dec(&sony_laptop_input.users);
+ return error;
+}
+
+static void sony_laptop_remove_input(void)
+{
+ /* cleanup only after the last user has gone */
+ if (!atomic_dec_and_test(&sony_laptop_input.users))
+ return;
+
+ /* flush workqueue first */
+ flush_workqueue(sony_laptop_input.wq);
+
+ /* destroy input devs */
+ input_unregister_device(sony_laptop_input.key_dev);
+ sony_laptop_input.key_dev = NULL;
+
+ if (sony_laptop_input.jog_dev) {
+ input_unregister_device(sony_laptop_input.jog_dev);
+ sony_laptop_input.jog_dev = NULL;
+ }
+
+ destroy_workqueue(sony_laptop_input.wq);
+ kfifo_free(sony_laptop_input.fifo);
+}
+
+/*********** Platform Device ***********/
+
+static atomic_t sony_pf_users = ATOMIC_INIT(0);
+static struct platform_driver sony_pf_driver = {
+ .driver = {
+ .name = "sony-laptop",
+ .owner = THIS_MODULE,
+ }
+};
+static struct platform_device *sony_pf_device;
+
+static int sony_pf_add(void)
+{
+ int ret = 0;
+
+ /* don't run again if already initialized */
+ if (atomic_add_return(1, &sony_pf_users) > 1)
+ return 0;
+
+ ret = platform_driver_register(&sony_pf_driver);
+ if (ret)
+ goto out;
+
+ sony_pf_device = platform_device_alloc("sony-laptop", -1);
+ if (!sony_pf_device) {
+ ret = -ENOMEM;
+ goto out_platform_registered;
+ }
+
+ ret = platform_device_add(sony_pf_device);
+ if (ret)
+ goto out_platform_alloced;
+
+ return 0;
+
+ out_platform_alloced:
+ platform_device_put(sony_pf_device);
+ sony_pf_device = NULL;
+ out_platform_registered:
+ platform_driver_unregister(&sony_pf_driver);
+ out:
+ atomic_dec(&sony_pf_users);
+ return ret;
+}
+
+static void sony_pf_remove(void)
+{
+ /* deregister only after the last user has gone */
+ if (!atomic_dec_and_test(&sony_pf_users))
+ return;
+
+ platform_device_del(sony_pf_device);
+ platform_device_put(sony_pf_device);
+ platform_driver_unregister(&sony_pf_driver);
+}
+
+/*********** SNC (SNY5001) Device ***********/
+
+/* the device uses 1-based values, while the backlight subsystem uses
+ 0-based values */
+#define SONY_MAX_BRIGHTNESS 8
+
+#define SNC_VALIDATE_IN 0
+#define SNC_VALIDATE_OUT 1
+
+static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
char *);
-static ssize_t sony_acpi_store(struct device *, struct device_attribute *,
+static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
const char *, size_t);
static int boolean_validate(const int, const int);
static int brightness_default_validate(const int, const int);
-#define SNC_VALIDATE_IN 0
-#define SNC_VALIDATE_OUT 1
-
-struct sony_acpi_value {
+struct sony_nc_value {
char *name; /* name of the entry */
char **acpiget; /* names of the ACPI get function */
char **acpiset; /* names of the ACPI set function */
@@ -75,65 +458,65 @@ struct sony_acpi_value {
struct device_attribute devattr; /* sysfs atribute */
};
-#define HANDLE_NAMES(_name, _values...) \
+#define SNC_HANDLE_NAMES(_name, _values...) \
static char *snc_##_name[] = { _values, NULL }
-#define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \
+#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
{ \
.name = __stringify(_name), \
.acpiget = _getters, \
.acpiset = _setters, \
.validate = _validate, \
.debug = _debug, \
- .devattr = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \
+ .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
}
-#define SONY_ACPI_VALUE_NULL { .name = NULL }
+#define SNC_HANDLE_NULL { .name = NULL }
-HANDLE_NAMES(fnkey_get, "GHKE");
+SNC_HANDLE_NAMES(fnkey_get, "GHKE");
-HANDLE_NAMES(brightness_def_get, "GPBR");
-HANDLE_NAMES(brightness_def_set, "SPBR");
+SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
+SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
-HANDLE_NAMES(cdpower_get, "GCDP");
-HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
+SNC_HANDLE_NAMES(cdpower_get, "GCDP");
+SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
-HANDLE_NAMES(audiopower_get, "GAZP");
-HANDLE_NAMES(audiopower_set, "AZPW");
+SNC_HANDLE_NAMES(audiopower_get, "GAZP");
+SNC_HANDLE_NAMES(audiopower_set, "AZPW");
-HANDLE_NAMES(lanpower_get, "GLNP");
-HANDLE_NAMES(lanpower_set, "LNPW");
+SNC_HANDLE_NAMES(lanpower_get, "GLNP");
+SNC_HANDLE_NAMES(lanpower_set, "LNPW");
-HANDLE_NAMES(PID_get, "GPID");
+SNC_HANDLE_NAMES(PID_get, "GPID");
-HANDLE_NAMES(CTR_get, "GCTR");
-HANDLE_NAMES(CTR_set, "SCTR");
+SNC_HANDLE_NAMES(CTR_get, "GCTR");
+SNC_HANDLE_NAMES(CTR_set, "SCTR");
-HANDLE_NAMES(PCR_get, "GPCR");
-HANDLE_NAMES(PCR_set, "SPCR");
+SNC_HANDLE_NAMES(PCR_get, "GPCR");
+SNC_HANDLE_NAMES(PCR_set, "SPCR");
-HANDLE_NAMES(CMI_get, "GCMI");
-HANDLE_NAMES(CMI_set, "SCMI");
+SNC_HANDLE_NAMES(CMI_get, "GCMI");
+SNC_HANDLE_NAMES(CMI_set, "SCMI");
-static struct sony_acpi_value sony_acpi_values[] = {
- SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get,
+static struct sony_nc_value sony_nc_values[] = {
+ SNC_HANDLE(brightness_default, snc_brightness_def_get,
snc_brightness_def_set, brightness_default_validate, 0),
- SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0),
- SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
- SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set,
+ SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
+ SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
+ SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
boolean_validate, 0),
- SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set,
+ SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
boolean_validate, 1),
/* unknown methods */
- SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1),
- SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
- SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
- SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
- SONY_ACPI_VALUE_NULL
+ SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
+ SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
+ SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
+ SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
+ SNC_HANDLE_NULL
};
-static acpi_handle sony_acpi_handle;
-static struct acpi_device *sony_acpi_acpi_device = NULL;
+static acpi_handle sony_nc_acpi_handle;
+static struct acpi_device *sony_nc_acpi_device = NULL;
/*
* acpi_evaluate_object wrappers
@@ -153,7 +536,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
return 0;
}
- printk(LOG_PFX "acpi_callreadfunc failed\n");
+ printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n");
return -1;
}
@@ -179,7 +562,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
if (status == AE_OK) {
if (result != NULL) {
if (out_obj.type != ACPI_TYPE_INTEGER) {
- printk(LOG_PFX "acpi_evaluate_object bad "
+ printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad "
"return type\n");
return -1;
}
@@ -188,13 +571,13 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
return 0;
}
- printk(LOG_PFX "acpi_evaluate_object failed\n");
+ printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n");
return -1;
}
/*
- * sony_acpi_values input/output validate functions
+ * sony_nc_values input/output validate functions
*/
/* brightness_default_validate:
@@ -229,19 +612,19 @@ static int boolean_validate(const int direction, const int value)
}
/*
- * Sysfs show/store common to all sony_acpi_values
+ * Sysfs show/store common to all sony_nc_values
*/
-static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
+static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
char *buffer)
{
int value;
- struct sony_acpi_value *item =
- container_of(attr, struct sony_acpi_value, devattr);
+ struct sony_nc_value *item =
+ container_of(attr, struct sony_nc_value, devattr);
if (!*item->acpiget)
return -EIO;
- if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0)
+ if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0)
return -EIO;
if (item->validate)
@@ -250,13 +633,13 @@ static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
return snprintf(buffer, PAGE_SIZE, "%d\n", value);
}
-static ssize_t sony_acpi_store(struct device *dev,
+static ssize_t sony_nc_sysfs_store(struct device *dev,
struct device_attribute *attr,
const char *buffer, size_t count)
{
int value;
- struct sony_acpi_value *item =
- container_of(attr, struct sony_acpi_value, devattr);
+ struct sony_nc_value *item =
+ container_of(attr, struct sony_nc_value, devattr);
if (!item->acpiset)
return -EIO;
@@ -272,118 +655,20 @@ static ssize_t sony_acpi_store(struct device *dev,
if (value < 0)
return value;
- if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0)
+ if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0)
return -EIO;
item->value = value;
item->valid = 1;
return count;
}
-/*
- * Platform device
- */
-static struct platform_driver sncpf_driver = {
- .driver = {
- .name = "sony-laptop",
- .owner = THIS_MODULE,
- }
-};
-static struct platform_device *sncpf_device;
-
-static int sony_snc_pf_add(void)
-{
- acpi_handle handle;
- struct sony_acpi_value *item;
- int ret = 0;
-
- ret = platform_driver_register(&sncpf_driver);
- if (ret)
- goto out;
-
- sncpf_device = platform_device_alloc("sony-laptop", -1);
- if (!sncpf_device) {
- ret = -ENOMEM;
- goto out_platform_registered;
- }
-
- ret = platform_device_add(sncpf_device);
- if (ret)
- goto out_platform_alloced;
-
- for (item = sony_acpi_values; item->name; ++item) {
-
- if (!debug && item->debug)
- continue;
-
- /* find the available acpiget as described in the DSDT */
- for (; item->acpiget && *item->acpiget; ++item->acpiget) {
- if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
- *item->acpiget,
- &handle))) {
- if (debug)
- printk(LOG_PFX "Found %s getter: %s\n",
- item->name, *item->acpiget);
- item->devattr.attr.mode |= S_IRUGO;
- break;
- }
- }
-
- /* find the available acpiset as described in the DSDT */
- for (; item->acpiset && *item->acpiset; ++item->acpiset) {
- if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
- *item->acpiset,
- &handle))) {
- if (debug)
- printk(LOG_PFX "Found %s setter: %s\n",
- item->name, *item->acpiset);
- item->devattr.attr.mode |= S_IWUSR;
- break;
- }
- }
-
- if (item->devattr.attr.mode != 0) {
- ret =
- device_create_file(&sncpf_device->dev,
- &item->devattr);
- if (ret)
- goto out_sysfs;
- }
- }
-
- return 0;
-
- out_sysfs:
- for (item = sony_acpi_values; item->name; ++item) {
- device_remove_file(&sncpf_device->dev, &item->devattr);
- }
- platform_device_del(sncpf_device);
- out_platform_alloced:
- platform_device_put(sncpf_device);
- out_platform_registered:
- platform_driver_unregister(&sncpf_driver);
- out:
- return ret;
-}
-
-static void sony_snc_pf_remove(void)
-{
- struct sony_acpi_value *item;
-
- for (item = sony_acpi_values; item->name; ++item) {
- device_remove_file(&sncpf_device->dev, &item->devattr);
- }
-
- platform_device_del(sncpf_device);
- platform_device_put(sncpf_device);
- platform_driver_unregister(&sncpf_driver);
-}
/*
* Backlight device
*/
static int sony_backlight_update_status(struct backlight_device *bd)
{
- return acpi_callsetfunc(sony_acpi_handle, "SBRT",
+ return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
bd->props.brightness + 1, NULL);
}
@@ -391,7 +676,7 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
{
int value;
- if (acpi_callgetfunc(sony_acpi_handle, "GBRT", &value))
+ if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
return 0;
/* brightness levels are 1-based, while backlight ones are 0-based */
return value - 1;
@@ -408,9 +693,9 @@ static struct backlight_ops sony_backlight_ops = {
*/
static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
{
- if (debug)
- printk(LOG_PFX "sony_acpi_notify, event: %d\n", event);
- acpi_bus_generate_event(sony_acpi_acpi_device, 1, event);
+ dprintk("sony_acpi_notify, event: %d\n", event);
+ sony_laptop_report_input_event(event);
+ acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
}
static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -422,7 +707,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
node = (struct acpi_namespace_node *)handle;
operand = (union acpi_operand_object *)node->object;
- printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
+ printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
(u32) operand->method.param_count);
return AE_OK;
@@ -431,16 +716,16 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
/*
* ACPI device
*/
-static int sony_acpi_resume(struct acpi_device *device)
+static int sony_nc_resume(struct acpi_device *device)
{
- struct sony_acpi_value *item;
+ struct sony_nc_value *item;
- for (item = sony_acpi_values; item->name; item++) {
+ for (item = sony_nc_values; item->name; item++) {
int ret;
if (!item->valid)
continue;
- ret = acpi_callsetfunc(sony_acpi_handle, *item->acpiset,
+ ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
item->value, NULL);
if (ret < 0) {
printk("%s: %d\n", __FUNCTION__, ret);
@@ -450,42 +735,55 @@ static int sony_acpi_resume(struct acpi_device *device)
return 0;
}
-static int sony_acpi_add(struct acpi_device *device)
+static int sony_nc_add(struct acpi_device *device)
{
acpi_status status;
int result = 0;
acpi_handle handle;
+ struct sony_nc_value *item;
+
+ printk(KERN_INFO DRV_PFX "%s v%s.\n",
+ SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
- sony_acpi_acpi_device = device;
+ sony_nc_acpi_device = device;
+ strcpy(acpi_device_class(device), "sony/hotkey");
- sony_acpi_handle = device->handle;
+ sony_nc_acpi_handle = device->handle;
if (debug) {
- status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle,
+ status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
1, sony_walk_callback, NULL, NULL);
if (ACPI_FAILURE(status)) {
- printk(LOG_PFX "unable to walk acpi resources\n");
+ printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n");
result = -ENODEV;
goto outwalk;
}
}
- status = acpi_install_notify_handler(sony_acpi_handle,
+ /* setup input devices and helper fifo */
+ result = sony_laptop_setup_input();
+ if (result) {
+ printk(KERN_ERR DRV_PFX
+ "Unabe to create input devices.\n");
+ goto outwalk;
+ }
+
+ status = acpi_install_notify_handler(sony_nc_acpi_handle,
ACPI_DEVICE_NOTIFY,
sony_acpi_notify, NULL);
if (ACPI_FAILURE(status)) {
- printk(LOG_PFX "unable to install notify handler\n");
+ printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
result = -ENODEV;
- goto outwalk;
+ goto outinput;
}
- if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, "GBRT", &handle))) {
+ if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) {
sony_backlight_device = backlight_device_register("sony", NULL,
NULL,
&sony_backlight_ops);
if (IS_ERR(sony_backlight_device)) {
- printk(LOG_PFX "unable to register backlight device\n");
+ printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
sony_backlight_device = NULL;
} else {
sony_backlight_device->props.brightness =
@@ -497,68 +795,1497 @@ static int sony_acpi_add(struct acpi_device *device)
}
- if (sony_snc_pf_add())
+ result = sony_pf_add();
+ if (result)
goto outbacklight;
- printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n");
+ /* create sony_pf sysfs attributes related to the SNC device */
+ for (item = sony_nc_values; item->name; ++item) {
+
+ if (!debug && item->debug)
+ continue;
+
+ /* find the available acpiget as described in the DSDT */
+ for (; item->acpiget && *item->acpiget; ++item->acpiget) {
+ if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
+ *item->acpiget,
+ &handle))) {
+ dprintk("Found %s getter: %s\n",
+ item->name, *item->acpiget);
+ item->devattr.attr.mode |= S_IRUGO;
+ break;
+ }
+ }
+
+ /* find the available acpiset as described in the DSDT */
+ for (; item->acpiset && *item->acpiset; ++item->acpiset) {
+ if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
+ *item->acpiset,
+ &handle))) {
+ dprintk("Found %s setter: %s\n",
+ item->name, *item->acpiset);
+ item->devattr.attr.mode |= S_IWUSR;
+ break;
+ }
+ }
+
+ if (item->devattr.attr.mode != 0) {
+ result =
+ device_create_file(&sony_pf_device->dev,
+ &item->devattr);
+ if (result)
+ goto out_sysfs;
+ }
+ }
return 0;
+ out_sysfs:
+ for (item = sony_nc_values; item->name; ++item) {
+ device_remove_file(&sony_pf_device->dev, &item->devattr);
+ }
+ sony_pf_remove();
+
outbacklight:
if (sony_backlight_device)
backlight_device_unregister(sony_backlight_device);
- status = acpi_remove_notify_handler(sony_acpi_handle,
+ status = acpi_remove_notify_handler(sony_nc_acpi_handle,
ACPI_DEVICE_NOTIFY,
sony_acpi_notify);
if (ACPI_FAILURE(status))
- printk(LOG_PFX "unable to remove notify handler\n");
+ printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
+
+ outinput:
+ sony_laptop_remove_input();
+
outwalk:
return result;
}
-static int sony_acpi_remove(struct acpi_device *device, int type)
+static int sony_nc_remove(struct acpi_device *device, int type)
{
acpi_status status;
+ struct sony_nc_value *item;
if (sony_backlight_device)
backlight_device_unregister(sony_backlight_device);
- sony_acpi_acpi_device = NULL;
+ sony_nc_acpi_device = NULL;
- status = acpi_remove_notify_handler(sony_acpi_handle,
+ status = acpi_remove_notify_handler(sony_nc_acpi_handle,
ACPI_DEVICE_NOTIFY,
sony_acpi_notify);
if (ACPI_FAILURE(status))
- printk(LOG_PFX "unable to remove notify handler\n");
+ printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
- sony_snc_pf_remove();
+ for (item = sony_nc_values; item->name; ++item) {
+ device_remove_file(&sony_pf_device->dev, &item->devattr);
+ }
- printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n");
+ sony_pf_remove();
+ sony_laptop_remove_input();
+ dprintk(SONY_NC_DRIVER_NAME " removed.\n");
return 0;
}
-static struct acpi_driver sony_acpi_driver = {
- .name = ACPI_SNC_DRIVER_NAME,
- .class = ACPI_SNC_CLASS,
- .ids = ACPI_SNC_HID,
+static struct acpi_driver sony_nc_driver = {
+ .name = SONY_NC_DRIVER_NAME,
+ .class = SONY_NC_CLASS,
+ .ids = SONY_NC_HID,
+ .owner = THIS_MODULE,
.ops = {
- .add = sony_acpi_add,
- .remove = sony_acpi_remove,
- .resume = sony_acpi_resume,
+ .add = sony_nc_add,
+ .remove = sony_nc_remove,
+ .resume = sony_nc_resume,
},
};
-static int __init sony_acpi_init(void)
+/*********** SPIC (SNY6001) Device ***********/
+
+#define SONYPI_DEVICE_TYPE1 0x00000001
+#define SONYPI_DEVICE_TYPE2 0x00000002
+#define SONYPI_DEVICE_TYPE3 0x00000004
+
+#define SONY_PIC_EV_MASK 0xff
+
+struct sony_pic_ioport {
+ struct acpi_resource_io io;
+ struct list_head list;
+};
+
+struct sony_pic_irq {
+ struct acpi_resource_irq irq;
+ struct list_head list;
+};
+
+struct sony_pic_dev {
+ int model;
+ u8 camera_power;
+ u8 bluetooth_power;
+ u8 wwan_power;
+ struct acpi_device *acpi_dev;
+ struct sony_pic_irq *cur_irq;
+ struct sony_pic_ioport *cur_ioport;
+ struct list_head interrupts;
+ struct list_head ioports;
+ struct mutex lock;
+};
+
+static struct sony_pic_dev spic_dev = {
+ .interrupts = LIST_HEAD_INIT(spic_dev.interrupts),
+ .ioports = LIST_HEAD_INIT(spic_dev.ioports),
+};
+
+/* Event masks */
+#define SONYPI_JOGGER_MASK 0x00000001
+#define SONYPI_CAPTURE_MASK 0x00000002
+#define SONYPI_FNKEY_MASK 0x00000004
+#define SONYPI_BLUETOOTH_MASK 0x00000008
+#define SONYPI_PKEY_MASK 0x00000010
+#define SONYPI_BACK_MASK 0x00000020
+#define SONYPI_HELP_MASK 0x00000040
+#define SONYPI_LID_MASK 0x00000080
+#define SONYPI_ZOOM_MASK 0x00000100
+#define SONYPI_THUMBPHRASE_MASK 0x00000200
+#define SONYPI_MEYE_MASK 0x00000400
+#define SONYPI_MEMORYSTICK_MASK 0x00000800
+#define SONYPI_BATTERY_MASK 0x00001000
+#define SONYPI_WIRELESS_MASK 0x00002000
+
+struct sonypi_event {
+ u8 data;
+ u8 event;
+};
+
+/* The set of possible button release events */
+static struct sonypi_event sonypi_releaseev[] = {
+ { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
+ { 0, 0 }
+};
+
+/* The set of possible jogger events */
+static struct sonypi_event sonypi_joggerev[] = {
+ { 0x1f, SONYPI_EVENT_JOGDIAL_UP },
+ { 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
+ { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
+ { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
+ { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
+ { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
+ { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
+ { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
+ { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
+ { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
+ { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
+ { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
+ { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
+ { 0, 0 }
+};
+
+/* The set of possible capture button events */
+static struct sonypi_event sonypi_captureev[] = {
+ { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
+ { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
+ { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
+ { 0, 0 }
+};
+
+/* The set of possible fnkeys events */
+static struct sonypi_event sonypi_fnkeyev[] = {
+ { 0x10, SONYPI_EVENT_FNKEY_ESC },
+ { 0x11, SONYPI_EVENT_FNKEY_F1 },
+ { 0x12, SONYPI_EVENT_FNKEY_F2 },
+ { 0x13, SONYPI_EVENT_FNKEY_F3 },
+ { 0x14, SONYPI_EVENT_FNKEY_F4 },
+ { 0x15, SONYPI_EVENT_FNKEY_F5 },
+ { 0x16, SONYPI_EVENT_FNKEY_F6 },
+ { 0x17, SONYPI_EVENT_FNKEY_F7 },
+ { 0x18, SONYPI_EVENT_FNKEY_F8 },
+ { 0x19, SONYPI_EVENT_FNKEY_F9 },
+ { 0x1a, SONYPI_EVENT_FNKEY_F10 },
+ { 0x1b, SONYPI_EVENT_FNKEY_F11 },
+ { 0x1c, SONYPI_EVENT_FNKEY_F12 },
+ { 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x21, SONYPI_EVENT_FNKEY_1 },
+ { 0x22, SONYPI_EVENT_FNKEY_2 },
+ { 0x31, SONYPI_EVENT_FNKEY_D },
+ { 0x32, SONYPI_EVENT_FNKEY_E },
+ { 0x33, SONYPI_EVENT_FNKEY_F },
+ { 0x34, SONYPI_EVENT_FNKEY_S },
+ { 0x35, SONYPI_EVENT_FNKEY_B },
+ { 0x36, SONYPI_EVENT_FNKEY_ONLY },
+ { 0, 0 }
+};
+
+/* The set of possible program key events */
+static struct sonypi_event sonypi_pkeyev[] = {
+ { 0x01, SONYPI_EVENT_PKEY_P1 },
+ { 0x02, SONYPI_EVENT_PKEY_P2 },
+ { 0x04, SONYPI_EVENT_PKEY_P3 },
+ { 0x5c, SONYPI_EVENT_PKEY_P1 },
+ { 0, 0 }
+};
+
+/* The set of possible bluetooth events */
+static struct sonypi_event sonypi_blueev[] = {
+ { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
+ { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
+ { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
+ { 0, 0 }
+};
+
+/* The set of possible wireless events */
+static struct sonypi_event sonypi_wlessev[] = {
+ { 0x59, SONYPI_EVENT_WIRELESS_ON },
+ { 0x5a, SONYPI_EVENT_WIRELESS_OFF },
+ { 0, 0 }
+};
+
+/* The set of possible back button events */
+static struct sonypi_event sonypi_backev[] = {
+ { 0x20, SONYPI_EVENT_BACK_PRESSED },
+ { 0, 0 }
+};
+
+/* The set of possible help button events */
+static struct sonypi_event sonypi_helpev[] = {
+ { 0x3b, SONYPI_EVENT_HELP_PRESSED },
+ { 0, 0 }
+};
+
+
+/* The set of possible lid events */
+static struct sonypi_event sonypi_lidev[] = {
+ { 0x51, SONYPI_EVENT_LID_CLOSED },
+ { 0x50, SONYPI_EVENT_LID_OPENED },
+ { 0, 0 }
+};
+
+/* The set of possible zoom events */
+static struct sonypi_event sonypi_zoomev[] = {
+ { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
+ { 0, 0 }
+};
+
+/* The set of possible thumbphrase events */
+static struct sonypi_event sonypi_thumbphraseev[] = {
+ { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
+ { 0, 0 }
+};
+
+/* The set of possible motioneye camera events */
+static struct sonypi_event sonypi_meyeev[] = {
+ { 0x00, SONYPI_EVENT_MEYE_FACE },
+ { 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
+ { 0, 0 }
+};
+
+/* The set of possible memorystick events */
+static struct sonypi_event sonypi_memorystickev[] = {
+ { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
+ { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
+ { 0, 0 }
+};
+
+/* The set of possible battery events */
+static struct sonypi_event sonypi_batteryev[] = {
+ { 0x20, SONYPI_EVENT_BATTERY_INSERT },
+ { 0x30, SONYPI_EVENT_BATTERY_REMOVE },
+ { 0, 0 }
+};
+
+static struct sonypi_eventtypes {
+ int model;
+ u8 data;
+ unsigned long mask;
+ struct sonypi_event * events;
+} sony_pic_eventtypes[] = {
+ { SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev },
+ { SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
+ { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
+ { SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
+ { SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
+ { SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+ { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
+
+ { SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev },
+ { SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
+ { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
+ { SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
+ { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+ { SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
+ { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
+ { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
+ { SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
+ { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+
+ { SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev },
+ { SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+ { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { 0 }
+};
+
+static int sony_pic_detect_device_type(void)
+{
+ struct pci_dev *pcidev;
+ int model = 0;
+
+ if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+ model = SONYPI_DEVICE_TYPE1;
+
+ else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+ model = SONYPI_DEVICE_TYPE3;
+
+ else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
+ model = SONYPI_DEVICE_TYPE3;
+
+ else
+ model = SONYPI_DEVICE_TYPE2;
+
+ if (pcidev)
+ pci_dev_put(pcidev);
+
+ printk(KERN_INFO DRV_PFX "detected Type%d model\n",
+ model == SONYPI_DEVICE_TYPE1 ? 1 :
+ model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
+ return model;
+}
+
+#define ITERATIONS_LONG 10000
+#define ITERATIONS_SHORT 10
+#define wait_on_command(command, iterations) { \
+ unsigned int n = iterations; \
+ while (--n && (command)) \
+ udelay(1); \
+ if (!n) \
+ dprintk("command failed at %s : %s (line %d)\n", \
+ __FILE__, __FUNCTION__, __LINE__); \
+}
+
+static u8 sony_pic_call1(u8 dev)
+{
+ u8 v1, v2;
+
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ ITERATIONS_LONG);
+ outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+ v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4);
+ v2 = inb_p(spic_dev.cur_ioport->io.minimum);
+ dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
+ return v2;
+}
+
+static u8 sony_pic_call2(u8 dev, u8 fn)
+{
+ u8 v1;
+
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ ITERATIONS_LONG);
+ outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ ITERATIONS_LONG);
+ outb(fn, spic_dev.cur_ioport->io.minimum);
+ v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+ dprintk("sony_pic_call2: 0x%.4x\n", v1);
+ return v1;
+}
+
+static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
+{
+ u8 v1;
+
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(fn, spic_dev.cur_ioport->io.minimum);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(v, spic_dev.cur_ioport->io.minimum);
+ v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+ dprintk("sony_pic_call3: 0x%.4x\n", v1);
+ return v1;
+}
+
+/* camera tests and poweron/poweroff */
+#define SONYPI_CAMERA_PICTURE 5
+#define SONYPI_CAMERA_CONTROL 0x10
+
+#define SONYPI_CAMERA_BRIGHTNESS 0
+#define SONYPI_CAMERA_CONTRAST 1
+#define SONYPI_CAMERA_HUE 2
+#define SONYPI_CAMERA_COLOR 3
+#define SONYPI_CAMERA_SHARPNESS 4
+
+#define SONYPI_CAMERA_EXPOSURE_MASK 0xC
+#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3
+#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30
+#define SONYPI_CAMERA_MUTE_MASK 0x40
+
+/* the rest don't need a loop until not 0xff */
+#define SONYPI_CAMERA_AGC 6
+#define SONYPI_CAMERA_AGC_MASK 0x30
+#define SONYPI_CAMERA_SHUTTER_MASK 0x7
+
+#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7
+#define SONYPI_CAMERA_CONTROL 0x10
+
+#define SONYPI_CAMERA_STATUS 7
+#define SONYPI_CAMERA_STATUS_READY 0x2
+#define SONYPI_CAMERA_STATUS_POSITION 0x4
+
+#define SONYPI_DIRECTION_BACKWARDS 0x4
+
+#define SONYPI_CAMERA_REVISION 8
+#define SONYPI_CAMERA_ROMVERSION 9
+
+static int __sony_pic_camera_ready(void)
+{
+ u8 v;
+
+ v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
+ return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
+}
+
+static int __sony_pic_camera_off(void)
+{
+ if (!camera) {
+ printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+ return -ENODEV;
+ }
+
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
+ SONYPI_CAMERA_MUTE_MASK),
+ ITERATIONS_SHORT);
+
+ if (spic_dev.camera_power) {
+ sony_pic_call2(0x91, 0);
+ spic_dev.camera_power = 0;
+ }
+ return 0;
+}
+
+static int __sony_pic_camera_on(void)
{
- return acpi_bus_register_driver(&sony_acpi_driver);
+ int i, j, x;
+
+ if (!camera) {
+ printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+ return -ENODEV;
+ }
+
+ if (spic_dev.camera_power)
+ return 0;
+
+ for (j = 5; j > 0; j--) {
+
+ for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
+ msleep(10);
+ sony_pic_call1(0x93);
+
+ for (i = 400; i > 0; i--) {
+ if (__sony_pic_camera_ready())
+ break;
+ msleep(10);
+ }
+ if (i)
+ break;
+ }
+
+ if (j == 0) {
+ printk(KERN_WARNING DRV_PFX "failed to power on camera\n");
+ return -ENODEV;
+ }
+
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
+ 0x5a),
+ ITERATIONS_SHORT);
+
+ spic_dev.camera_power = 1;
+ return 0;
+}
+
+/* External camera command (exported to the motion eye v4l driver) */
+int sony_pic_camera_command(int command, u8 value)
+{
+ if (!camera)
+ return -EIO;
+
+ mutex_lock(&spic_dev.lock);
+
+ switch (command) {
+ case SONY_PIC_COMMAND_SETCAMERA:
+ if (value)
+ __sony_pic_camera_on();
+ else
+ __sony_pic_camera_off();
+ break;
+ case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERACONTRAST:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERAHUE:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERACOLOR:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERAPICTURE:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERAAGC:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
+ ITERATIONS_SHORT);
+ break;
+ default:
+ printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n",
+ command);
+ break;
+ }
+ mutex_unlock(&spic_dev.lock);
+ return 0;
+}
+EXPORT_SYMBOL(sony_pic_camera_command);
+
+/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */
+static void sony_pic_set_wwanpower(u8 state)
+{
+ state = !!state;
+ mutex_lock(&spic_dev.lock);
+ if (spic_dev.wwan_power == state) {
+ mutex_unlock(&spic_dev.lock);
+ return;
+ }
+ sony_pic_call2(0xB0, state);
+ spic_dev.wwan_power = state;
+ mutex_unlock(&spic_dev.lock);
+}
+
+static ssize_t sony_pic_wwanpower_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ unsigned long value;
+ if (count > 31)
+ return -EINVAL;
+
+ value = simple_strtoul(buffer, NULL, 10);
+ sony_pic_set_wwanpower(value);
+
+ return count;
+}
+
+static ssize_t sony_pic_wwanpower_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ ssize_t count;
+ mutex_lock(&spic_dev.lock);
+ count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
+ mutex_unlock(&spic_dev.lock);
+ return count;
+}
+
+/* bluetooth subsystem power state */
+static void __sony_pic_set_bluetoothpower(u8 state)
+{
+ state = !!state;
+ if (spic_dev.bluetooth_power == state)
+ return;
+ sony_pic_call2(0x96, state);
+ sony_pic_call1(0x82);
+ spic_dev.bluetooth_power = state;
+}
+
+static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ unsigned long value;
+ if (count > 31)
+ return -EINVAL;
+
+ value = simple_strtoul(buffer, NULL, 10);
+ mutex_lock(&spic_dev.lock);
+ __sony_pic_set_bluetoothpower(value);
+ mutex_unlock(&spic_dev.lock);
+
+ return count;
+}
+
+static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ ssize_t count = 0;
+ mutex_lock(&spic_dev.lock);
+ count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
+ mutex_unlock(&spic_dev.lock);
+ return count;
+}
+
+/* fan speed */
+/* FAN0 information (reverse engineered from ACPI tables) */
+#define SONY_PIC_FAN0_STATUS 0x93
+static int sony_pic_set_fanspeed(unsigned long value)
+{
+ return ec_write(SONY_PIC_FAN0_STATUS, value);
+}
+
+static int sony_pic_get_fanspeed(u8 *value)
+{
+ return ec_read(SONY_PIC_FAN0_STATUS, value);
+}
+
+static ssize_t sony_pic_fanspeed_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ unsigned long value;
+ if (count > 31)
+ return -EINVAL;
+
+ value = simple_strtoul(buffer, NULL, 10);
+ if (sony_pic_set_fanspeed(value))
+ return -EIO;
+
+ return count;
+}
+
+static ssize_t sony_pic_fanspeed_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ u8 value = 0;
+ if (sony_pic_get_fanspeed(&value))
+ return -EIO;
+
+ return snprintf(buffer, PAGE_SIZE, "%d\n", value);
+}
+
+#define SPIC_ATTR(_name, _mode) \
+struct device_attribute spic_attr_##_name = __ATTR(_name, \
+ _mode, sony_pic_## _name ##_show, \
+ sony_pic_## _name ##_store)
+
+static SPIC_ATTR(bluetoothpower, 0644);
+static SPIC_ATTR(wwanpower, 0644);
+static SPIC_ATTR(fanspeed, 0644);
+
+static struct attribute *spic_attributes[] = {
+ &spic_attr_bluetoothpower.attr,
+ &spic_attr_wwanpower.attr,
+ &spic_attr_fanspeed.attr,
+ NULL
+};
+
+static struct attribute_group spic_attribute_group = {
+ .attrs = spic_attributes
+};
+
+/******** SONYPI compatibility **********/
+#ifdef CONFIG_SONY_LAPTOP_OLD
+
+/* battery / brightness / temperature addresses */
+#define SONYPI_BAT_FLAGS 0x81
+#define SONYPI_LCD_LIGHT 0x96
+#define SONYPI_BAT1_PCTRM 0xa0
+#define SONYPI_BAT1_LEFT 0xa2
+#define SONYPI_BAT1_MAXRT 0xa4
+#define SONYPI_BAT2_PCTRM 0xa8
+#define SONYPI_BAT2_LEFT 0xaa
+#define SONYPI_BAT2_MAXRT 0xac
+#define SONYPI_BAT1_MAXTK 0xb0
+#define SONYPI_BAT1_FULL 0xb2
+#define SONYPI_BAT2_MAXTK 0xb8
+#define SONYPI_BAT2_FULL 0xba
+#define SONYPI_TEMP_STATUS 0xC1
+
+struct sonypi_compat_s {
+ struct fasync_struct *fifo_async;
+ struct kfifo *fifo;
+ spinlock_t fifo_lock;
+ wait_queue_head_t fifo_proc_list;
+ atomic_t open_count;
+};
+static struct sonypi_compat_s sonypi_compat = {
+ .open_count = ATOMIC_INIT(0),
+};
+
+static int sonypi_misc_fasync(int fd, struct file *filp, int on)
+{
+ int retval;
+
+ retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+static int sonypi_misc_release(struct inode *inode, struct file *file)
+{
+ sonypi_misc_fasync(-1, file, 0);
+ atomic_dec(&sonypi_compat.open_count);
+ return 0;
+}
+
+static int sonypi_misc_open(struct inode *inode, struct file *file)
+{
+ /* Flush input queue on first open */
+ if (atomic_inc_return(&sonypi_compat.open_count) == 1)
+ kfifo_reset(sonypi_compat.fifo);
+ return 0;
+}
+
+static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ ssize_t ret;
+ unsigned char c;
+
+ if ((kfifo_len(sonypi_compat.fifo) == 0) &&
+ (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
+ kfifo_len(sonypi_compat.fifo) != 0);
+ if (ret)
+ return ret;
+
+ while (ret < count &&
+ (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) {
+ if (put_user(c, buf++))
+ return -EFAULT;
+ ret++;
+ }
+
+ if (ret > 0) {
+ struct inode *inode = file->f_path.dentry->d_inode;
+ inode->i_atime = current_fs_time(inode->i_sb);
+ }
+
+ return ret;
+}
+
+static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
+ if (kfifo_len(sonypi_compat.fifo))
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static int ec_read16(u8 addr, u16 *value)
+{
+ u8 val_lb, val_hb;
+ if (ec_read(addr, &val_lb))
+ return -1;
+ if (ec_read(addr + 1, &val_hb))
+ return -1;
+ *value = val_lb | (val_hb << 8);
+ return 0;
+}
+
+static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ void __user *argp = (void __user *)arg;
+ u8 val8;
+ u16 val16;
+ int value;
+
+ mutex_lock(&spic_dev.lock);
+ switch (cmd) {
+ case SONYPI_IOCGBRT:
+ if (sony_backlight_device == NULL) {
+ ret = -EIO;
+ break;
+ }
+ if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) {
+ ret = -EIO;
+ break;
+ }
+ val8 = ((value & 0xff) - 1) << 5;
+ if (copy_to_user(argp, &val8, sizeof(val8)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCSBRT:
+ if (sony_backlight_device == NULL) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_from_user(&val8, argp, sizeof(val8))) {
+ ret = -EFAULT;
+ break;
+ }
+ if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
+ (val8 >> 5) + 1, NULL)) {
+ ret = -EIO;
+ break;
+ }
+ /* sync the backlight device status */
+ sony_backlight_device->props.brightness =
+ sony_backlight_get_brightness(sony_backlight_device);
+ break;
+ case SONYPI_IOCGBAT1CAP:
+ if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val16, sizeof(val16)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCGBAT1REM:
+ if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val16, sizeof(val16)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCGBAT2CAP:
+ if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val16, sizeof(val16)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCGBAT2REM:
+ if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val16, sizeof(val16)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCGBATFLAGS:
+ if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
+ ret = -EIO;
+ break;
+ }
+ val8 &= 0x07;
+ if (copy_to_user(argp, &val8, sizeof(val8)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCGBLUE:
+ val8 = spic_dev.bluetooth_power;
+ if (copy_to_user(argp, &val8, sizeof(val8)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCSBLUE:
+ if (copy_from_user(&val8, argp, sizeof(val8))) {
+ ret = -EFAULT;
+ break;
+ }
+ __sony_pic_set_bluetoothpower(val8);
+ break;
+ /* FAN Controls */
+ case SONYPI_IOCGFAN:
+ if (sony_pic_get_fanspeed(&val8)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val8, sizeof(val8)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCSFAN:
+ if (copy_from_user(&val8, argp, sizeof(val8))) {
+ ret = -EFAULT;
+ break;
+ }
+ if (sony_pic_set_fanspeed(val8))
+ ret = -EIO;
+ break;
+ /* GET Temperature (useful under APM) */
+ case SONYPI_IOCGTEMP:
+ if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val8, sizeof(val8)))
+ ret = -EFAULT;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&spic_dev.lock);
+ return ret;
+}
+
+static const struct file_operations sonypi_misc_fops = {
+ .owner = THIS_MODULE,
+ .read = sonypi_misc_read,
+ .poll = sonypi_misc_poll,
+ .open = sonypi_misc_open,
+ .release = sonypi_misc_release,
+ .fasync = sonypi_misc_fasync,
+ .ioctl = sonypi_misc_ioctl,
+};
+
+static struct miscdevice sonypi_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sonypi",
+ .fops = &sonypi_misc_fops,
+};
+
+static void sonypi_compat_report_event(u8 event)
+{
+ kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));
+ kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
+ wake_up_interruptible(&sonypi_compat.fifo_proc_list);
+}
+
+static int sonypi_compat_init(void)
+{
+ int error;
+
+ spin_lock_init(&sonypi_compat.fifo_lock);
+ sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
+ &sonypi_compat.fifo_lock);
+ if (IS_ERR(sonypi_compat.fifo)) {
+ printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+ return PTR_ERR(sonypi_compat.fifo);
+ }
+
+ init_waitqueue_head(&sonypi_compat.fifo_proc_list);
+
+ if (minor != -1)
+ sonypi_misc_device.minor = minor;
+ error = misc_register(&sonypi_misc_device);
+ if (error) {
+ printk(KERN_ERR DRV_PFX "misc_register failed\n");
+ goto err_free_kfifo;
+ }
+ if (minor == -1)
+ printk(KERN_INFO DRV_PFX "device allocated minor is %d\n",
+ sonypi_misc_device.minor);
+
+ return 0;
+
+err_free_kfifo:
+ kfifo_free(sonypi_compat.fifo);
+ return error;
+}
+
+static void sonypi_compat_exit(void)
+{
+ misc_deregister(&sonypi_misc_device);
+ kfifo_free(sonypi_compat.fifo);
+}
+#else
+static int sonypi_compat_init(void) { return 0; }
+static void sonypi_compat_exit(void) { }
+static void sonypi_compat_report_event(u8 event) { }
+#endif /* CONFIG_SONY_LAPTOP_OLD */
+
+/*
+ * ACPI callbacks
+ */
+static acpi_status
+sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
+{
+ u32 i;
+ struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
+
+ switch (resource->type) {
+ case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+ case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+ return AE_OK;
+
+ case ACPI_RESOURCE_TYPE_IRQ:
+ {
+ struct acpi_resource_irq *p = &resource->data.irq;
+ struct sony_pic_irq *interrupt = NULL;
+ if (!p || !p->interrupt_count) {
+ /*
+ * IRQ descriptors may have no IRQ# bits set,
+ * particularly those those w/ _STA disabled
+ */
+ dprintk("Blank IRQ resource\n");
+ return AE_OK;
+ }
+ for (i = 0; i < p->interrupt_count; i++) {
+ if (!p->interrupts[i]) {
+ printk(KERN_WARNING DRV_PFX
+ "Invalid IRQ %d\n",
+ p->interrupts[i]);
+ continue;
+ }
+ interrupt = kzalloc(sizeof(*interrupt),
+ GFP_KERNEL);
+ if (!interrupt)
+ return AE_ERROR;
+
+ list_add_tail(&interrupt->list, &dev->interrupts);
+ interrupt->irq.triggering = p->triggering;
+ interrupt->irq.polarity = p->polarity;
+ interrupt->irq.sharable = p->sharable;
+ interrupt->irq.interrupt_count = 1;
+ interrupt->irq.interrupts[0] = p->interrupts[i];
+ }
+ return AE_OK;
+ }
+ case ACPI_RESOURCE_TYPE_IO:
+ {
+ struct acpi_resource_io *io = &resource->data.io;
+ struct sony_pic_ioport *ioport = NULL;
+ if (!io) {
+ dprintk("Blank IO resource\n");
+ return AE_OK;
+ }
+
+ ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
+ if (!ioport)
+ return AE_ERROR;
+
+ list_add_tail(&ioport->list, &dev->ioports);
+ memcpy(&ioport->io, io, sizeof(*io));
+ return AE_OK;
+ }
+ default:
+ dprintk("Resource %d isn't an IRQ nor an IO port\n",
+ resource->type);
+
+ case ACPI_RESOURCE_TYPE_END_TAG:
+ return AE_OK;
+ }
+ return AE_CTRL_TERMINATE;
+}
+
+static int sony_pic_possible_resources(struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+
+ if (!device)
+ return -EINVAL;
+
+ /* get device status */
+ /* see acpi_pci_link_get_current acpi_pci_link_get_possible */
+ dprintk("Evaluating _STA\n");
+ result = acpi_bus_get_status(device);
+ if (result) {
+ printk(KERN_WARNING DRV_PFX "Unable to read status\n");
+ goto end;
+ }
+
+ if (!device->status.enabled)
+ dprintk("Device disabled\n");
+ else
+ dprintk("Device enabled\n");
+
+ /*
+ * Query and parse 'method'
+ */
+ dprintk("Evaluating %s\n", METHOD_NAME__PRS);
+ status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
+ sony_pic_read_possible_resource, &spic_dev);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_WARNING DRV_PFX
+ "Failure evaluating %s\n",
+ METHOD_NAME__PRS);
+ result = -ENODEV;
+ }
+end:
+ return result;
+}
+
+/*
+ * Disable the spic device by calling its _DIS method
+ */
+static int sony_pic_disable(struct acpi_device *device)
+{
+ if (ACPI_FAILURE(acpi_evaluate_object(device->handle, "_DIS", 0, NULL)))
+ return -ENXIO;
+
+ dprintk("Device disabled\n");
+ return 0;
+}
+
+
+/*
+ * Based on drivers/acpi/pci_link.c:acpi_pci_link_set
+ *
+ * Call _SRS to set current resources
+ */
+static int sony_pic_enable(struct acpi_device *device,
+ struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
+{
+ acpi_status status;
+ int result = 0;
+ struct {
+ struct acpi_resource io_res;
+ struct acpi_resource irq_res;
+ struct acpi_resource end;
+ } *resource;
+ struct acpi_buffer buffer = { 0, NULL };
+
+ if (!ioport || !irq)
+ return -EINVAL;
+
+ /* init acpi_buffer */
+ resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
+ if (!resource)
+ return -ENOMEM;
+
+ buffer.length = sizeof(*resource) + 1;
+ buffer.pointer = resource;
+
+ /* setup io resource */
+ resource->io_res.type = ACPI_RESOURCE_TYPE_IO;
+ resource->io_res.length = sizeof(struct acpi_resource);
+ memcpy(&resource->io_res.data.io, &ioport->io,
+ sizeof(struct acpi_resource_io));
+
+ /* setup irq resource */
+ resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ;
+ resource->irq_res.length = sizeof(struct acpi_resource);
+ memcpy(&resource->irq_res.data.irq, &irq->irq,
+ sizeof(struct acpi_resource_irq));
+ /* we requested a shared irq */
+ resource->irq_res.data.irq.sharable = ACPI_SHARED;
+
+ resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
+
+ /* Attempt to set the resource */
+ dprintk("Evaluating _SRS\n");
+ status = acpi_set_current_resources(device->handle, &buffer);
+
+ /* check for total failure */
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR DRV_PFX "Error evaluating _SRS");
+ result = -ENODEV;
+ goto end;
+ }
+
+ /* Necessary device initializations calls (from sonypi) */
+ sony_pic_call1(0x82);
+ sony_pic_call2(0x81, 0xff);
+ sony_pic_call1(compat ? 0x92 : 0x82);
+
+end:
+ kfree(resource);
+ return result;
+}
+
+/*****************
+ *
+ * ISR: some event is available
+ *
+ *****************/
+static irqreturn_t sony_pic_irq(int irq, void *dev_id)
+{
+ int i, j;
+ u32 port_val = 0;
+ u8 ev = 0;
+ u8 data_mask = 0;
+ u8 device_event = 0;
+
+ struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
+
+ acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
+ dev->cur_ioport->io.address_length);
+ ev = port_val & SONY_PIC_EV_MASK;
+ data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
+
+ dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
+ port_val, ev, data_mask, dev->cur_ioport->io.minimum);
+
+ if (ev == 0x00 || ev == 0xff)
+ return IRQ_HANDLED;
+
+ for (i = 0; sony_pic_eventtypes[i].model; i++) {
+
+ if (spic_dev.model != sony_pic_eventtypes[i].model)
+ continue;
+
+ if ((data_mask & sony_pic_eventtypes[i].data) !=
+ sony_pic_eventtypes[i].data)
+ continue;
+
+ if (!(mask & sony_pic_eventtypes[i].mask))
+ continue;
+
+ for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) {
+ if (ev == sony_pic_eventtypes[i].events[j].data) {
+ device_event =
+ sony_pic_eventtypes[i].events[j].event;
+ goto found;
+ }
+ }
+ }
+ return IRQ_HANDLED;
+
+found:
+ sony_laptop_report_input_event(device_event);
+ acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event);
+ sonypi_compat_report_event(device_event);
+
+ return IRQ_HANDLED;
+}
+
+/*****************
+ *
+ * ACPI driver
+ *
+ *****************/
+static int sony_pic_remove(struct acpi_device *device, int type)
+{
+ struct sony_pic_ioport *io, *tmp_io;
+ struct sony_pic_irq *irq, *tmp_irq;
+
+ sonypi_compat_exit();
+
+ if (sony_pic_disable(device)) {
+ printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");
+ return -ENXIO;
+ }
+
+ free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
+ release_region(spic_dev.cur_ioport->io.minimum,
+ spic_dev.cur_ioport->io.address_length);
+
+ sony_laptop_remove_input();
+
+ /* pf attrs */
+ sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
+ sony_pf_remove();
+
+ list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
+ list_del(&io->list);
+ kfree(io);
+ }
+ list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
+ list_del(&irq->list);
+ kfree(irq);
+ }
+ spic_dev.cur_ioport = NULL;
+ spic_dev.cur_irq = NULL;
+
+ dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
+ return 0;
+}
+
+static int sony_pic_add(struct acpi_device *device)
+{
+ int result;
+ struct sony_pic_ioport *io, *tmp_io;
+ struct sony_pic_irq *irq, *tmp_irq;
+
+ printk(KERN_INFO DRV_PFX "%s v%s.\n",
+ SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
+
+ spic_dev.acpi_dev = device;
+ strcpy(acpi_device_class(device), "sony/hotkey");
+ spic_dev.model = sony_pic_detect_device_type();
+ mutex_init(&spic_dev.lock);
+
+ /* read _PRS resources */
+ result = sony_pic_possible_resources(device);
+ if (result) {
+ printk(KERN_ERR DRV_PFX
+ "Unabe to read possible resources.\n");
+ goto err_free_resources;
+ }
+
+ /* setup input devices and helper fifo */
+ result = sony_laptop_setup_input();
+ if (result) {
+ printk(KERN_ERR DRV_PFX
+ "Unabe to create input devices.\n");
+ goto err_free_resources;
+ }
+
+ /* request io port */
+ list_for_each_entry(io, &spic_dev.ioports, list) {
+ if (request_region(io->io.minimum, io->io.address_length,
+ "Sony Programable I/O Device")) {
+ dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n",
+ io->io.minimum, io->io.maximum,
+ io->io.address_length);
+ spic_dev.cur_ioport = io;
+ break;
+ }
+ }
+ if (!spic_dev.cur_ioport) {
+ printk(KERN_ERR DRV_PFX "Failed to request_region.\n");
+ result = -ENODEV;
+ goto err_remove_input;
+ }
+
+ /* request IRQ */
+ list_for_each_entry(irq, &spic_dev.interrupts, list) {
+ if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
+ IRQF_SHARED, "sony-laptop", &spic_dev)) {
+ dprintk("IRQ: %d - triggering: %d - "
+ "polarity: %d - shr: %d\n",
+ irq->irq.interrupts[0],
+ irq->irq.triggering,
+ irq->irq.polarity,
+ irq->irq.sharable);
+ spic_dev.cur_irq = irq;
+ break;
+ }
+ }
+ if (!spic_dev.cur_irq) {
+ printk(KERN_ERR DRV_PFX "Failed to request_irq.\n");
+ result = -ENODEV;
+ goto err_release_region;
+ }
+
+ /* set resource status _SRS */
+ result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
+ if (result) {
+ printk(KERN_ERR DRV_PFX "Couldn't enable device.\n");
+ goto err_free_irq;
+ }
+
+ spic_dev.bluetooth_power = -1;
+ /* create device attributes */
+ result = sony_pf_add();
+ if (result)
+ goto err_disable_device;
+
+ result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
+ if (result)
+ goto err_remove_pf;
+
+ if (sonypi_compat_init())
+ goto err_remove_pf;
+
+ return 0;
+
+err_remove_pf:
+ sony_pf_remove();
+
+err_disable_device:
+ sony_pic_disable(device);
+
+err_free_irq:
+ free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
+
+err_release_region:
+ release_region(spic_dev.cur_ioport->io.minimum,
+ spic_dev.cur_ioport->io.address_length);
+
+err_remove_input:
+ sony_laptop_remove_input();
+
+err_free_resources:
+ list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
+ list_del(&io->list);
+ kfree(io);
+ }
+ list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
+ list_del(&irq->list);
+ kfree(irq);
+ }
+ spic_dev.cur_ioport = NULL;
+ spic_dev.cur_irq = NULL;
+
+ return result;
+}
+
+static int sony_pic_suspend(struct acpi_device *device, pm_message_t state)
+{
+ if (sony_pic_disable(device))
+ return -ENXIO;
+ return 0;
+}
+
+static int sony_pic_resume(struct acpi_device *device)
+{
+ sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
+ return 0;
+}
+
+static struct acpi_driver sony_pic_driver = {
+ .name = SONY_PIC_DRIVER_NAME,
+ .class = SONY_PIC_CLASS,
+ .ids = SONY_PIC_HID,
+ .owner = THIS_MODULE,
+ .ops = {
+ .add = sony_pic_add,
+ .remove = sony_pic_remove,
+ .suspend = sony_pic_suspend,
+ .resume = sony_pic_resume,
+ },
+};
+
+static struct dmi_system_id __initdata sonypi_dmi_table[] = {
+ {
+ .ident = "Sony Vaio",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
+ },
+ },
+ {
+ .ident = "Sony Vaio",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
+ },
+ },
+ { }
+};
+
+static int __init sony_laptop_init(void)
+{
+ int result;
+
+ if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
+ result = acpi_bus_register_driver(&sony_pic_driver);
+ if (result) {
+ printk(KERN_ERR DRV_PFX
+ "Unable to register SPIC driver.");
+ goto out;
+ }
+ }
+
+ result = acpi_bus_register_driver(&sony_nc_driver);
+ if (result) {
+ printk(KERN_ERR DRV_PFX "Unable to register SNC driver.");
+ goto out_unregister_pic;
+ }
+
+ return 0;
+
+out_unregister_pic:
+ if (!no_spic)
+ acpi_bus_unregister_driver(&sony_pic_driver);
+out:
+ return result;
}
-static void __exit sony_acpi_exit(void)
+static void __exit sony_laptop_exit(void)
{
- acpi_bus_unregister_driver(&sony_acpi_driver);
+ acpi_bus_unregister_driver(&sony_nc_driver);
+ if (!no_spic)
+ acpi_bus_unregister_driver(&sony_pic_driver);
}
-module_init(sony_acpi_init);
-module_exit(sony_acpi_exit);
+module_init(sony_laptop_init);
+module_exit(sony_laptop_exit);
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
new file mode 100644
index 000000000000..6c36a55cb3d1
--- /dev/null
+++ b/drivers/misc/thinkpad_acpi.c
@@ -0,0 +1,4312 @@
+/*
+ * thinkpad_acpi.c - ThinkPad ACPI Extras
+ *
+ *
+ * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define IBM_VERSION "0.14"
+#define TPACPI_SYSFS_VERSION 0x000100
+
+/*
+ * Changelog:
+ * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to
+ * drivers/misc.
+ *
+ * 2006-11-22 0.13 new maintainer
+ * changelog now lives in git commit history, and will
+ * not be updated further in-file.
+ *
+ * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
+ * 2005-03-17 0.11 support for 600e, 770x
+ * thanks to Jamie Lentin <lentinj@dial.pipex.com>
+ * support for 770e, G41
+ * G40 and G41 don't have a thinklight
+ * temperatures no longer experimental
+ * experimental brightness control
+ * experimental volume control
+ * experimental fan enable/disable
+ * 2005-01-16 0.10 fix module loading on R30, R31
+ * 2005-01-16 0.9 support for 570, R30, R31
+ * ultrabay support on A22p, A3x
+ * limit arg for cmos, led, beep, drop experimental status
+ * more capable led control on A21e, A22p, T20-22, X20
+ * experimental temperatures and fan speed
+ * experimental embedded controller register dump
+ * mark more functions as __init, drop incorrect __exit
+ * use MODULE_VERSION
+ * thanks to Henrik Brix Andersen <brix@gentoo.org>
+ * fix parameter passing on module loading
+ * thanks to Rusty Russell <rusty@rustcorp.com.au>
+ * thanks to Jim Radford <radford@blackbean.org>
+ * 2004-11-08 0.8 fix init error case, don't return from a macro
+ * thanks to Chris Wright <chrisw@osdl.org>
+ * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20
+ * fix led control on A21e
+ * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device
+ * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20
+ * proc file format changed
+ * video_switch command
+ * experimental cmos control
+ * experimental led control
+ * experimental acpi sounds
+ * 2004-09-16 0.4 support for module parameters
+ * hotkey mask can be prefixed by 0x
+ * video output switching
+ * video expansion control
+ * ultrabay eject support
+ * removed lcd brightness/on/off control, didn't work
+ * 2004-08-17 0.3 support for R40
+ * lcd off, brightness control
+ * thinklight on/off
+ * 2004-08-14 0.2 support for T series, X20
+ * bluetooth enable/disable
+ * hotkey events disabled by default
+ * removed fan control, currently useless
+ * 2004-08-09 0.1 initial release, support for X series
+ */
+
+#include "thinkpad_acpi.h"
+
+MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
+MODULE_DESCRIPTION(IBM_DESC);
+MODULE_VERSION(IBM_VERSION);
+MODULE_LICENSE("GPL");
+
+/* Please remove this in year 2009 */
+MODULE_ALIAS("ibm_acpi");
+
+#define __unused __attribute__ ((unused))
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * ACPI Helpers and device model
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/*************************************************************************
+ * ACPI basic handles
+ */
+
+static acpi_handle root_handle = NULL;
+
+#define IBM_HANDLE(object, parent, paths...) \
+ static acpi_handle object##_handle; \
+ static acpi_handle *object##_parent = &parent##_handle; \
+ static char *object##_path; \
+ static char *object##_paths[] = { paths }
+
+IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
+ "\\_SB.PCI.ISA.EC", /* 570 */
+ "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
+ "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
+ "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */
+ "\\_SB.PCI0.ICH3.EC0", /* R31 */
+ "\\_SB.PCI0.LPC.EC", /* all others */
+ );
+
+IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
+IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
+
+
+/*************************************************************************
+ * Misc ACPI handles
+ */
+
+IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */
+ "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
+ "\\CMS", /* R40, R40e */
+ ); /* all others */
+
+IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
+ "^HKEY", /* R30, R31 */
+ "HKEY", /* all others */
+ ); /* 570 */
+
+
+/*************************************************************************
+ * ACPI helpers
+ */
+
+static int acpi_evalf(acpi_handle handle,
+ void *res, char *method, char *fmt, ...)
+{
+ char *fmt0 = fmt;
+ struct acpi_object_list params;
+ union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
+ struct acpi_buffer result, *resultp;
+ union acpi_object out_obj;
+ acpi_status status;
+ va_list ap;
+ char res_type;
+ int success;
+ int quiet;
+
+ if (!*fmt) {
+ printk(IBM_ERR "acpi_evalf() called with empty format\n");
+ return 0;
+ }
+
+ if (*fmt == 'q') {
+ quiet = 1;
+ fmt++;
+ } else
+ quiet = 0;
+
+ res_type = *(fmt++);
+
+ params.count = 0;
+ params.pointer = &in_objs[0];
+
+ va_start(ap, fmt);
+ while (*fmt) {
+ char c = *(fmt++);
+ switch (c) {
+ case 'd': /* int */
+ in_objs[params.count].integer.value = va_arg(ap, int);
+ in_objs[params.count++].type = ACPI_TYPE_INTEGER;
+ break;
+ /* add more types as needed */
+ default:
+ printk(IBM_ERR "acpi_evalf() called "
+ "with invalid format character '%c'\n", c);
+ return 0;
+ }
+ }
+ va_end(ap);
+
+ if (res_type != 'v') {
+ result.length = sizeof(out_obj);
+ result.pointer = &out_obj;
+ resultp = &result;
+ } else
+ resultp = NULL;
+
+ status = acpi_evaluate_object(handle, method, &params, resultp);
+
+ switch (res_type) {
+ case 'd': /* int */
+ if (res)
+ *(int *)res = out_obj.integer.value;
+ success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
+ break;
+ case 'v': /* void */
+ success = status == AE_OK;
+ break;
+ /* add more types as needed */
+ default:
+ printk(IBM_ERR "acpi_evalf() called "
+ "with invalid format character '%c'\n", res_type);
+ return 0;
+ }
+
+ if (!success && !quiet)
+ printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
+ method, fmt0, status);
+
+ return success;
+}
+
+static void __unused acpi_print_int(acpi_handle handle, char *method)
+{
+ int i;
+
+ if (acpi_evalf(handle, &i, method, "d"))
+ printk(IBM_INFO "%s = 0x%x\n", method, i);
+ else
+ printk(IBM_ERR "error calling %s\n", method);
+}
+
+static int acpi_ec_read(int i, u8 * p)
+{
+ int v;
+
+ if (ecrd_handle) {
+ if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
+ return 0;
+ *p = v;
+ } else {
+ if (ec_read(i, p) < 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int acpi_ec_write(int i, u8 v)
+{
+ if (ecwr_handle) {
+ if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
+ return 0;
+ } else {
+ if (ec_write(i, v) < 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _sta(acpi_handle handle)
+{
+ int status;
+
+ if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
+ status = 0;
+
+ return status;
+}
+
+static int issue_thinkpad_cmos_command(int cmos_cmd)
+{
+ if (!cmos_handle)
+ return -ENXIO;
+
+ if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd))
+ return -EIO;
+
+ return 0;
+}
+
+/*************************************************************************
+ * ACPI device model
+ */
+
+static void drv_acpi_handle_init(char *name,
+ acpi_handle *handle, acpi_handle parent,
+ char **paths, int num_paths, char **path)
+{
+ int i;
+ acpi_status status;
+
+ vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n",
+ name);
+
+ for (i = 0; i < num_paths; i++) {
+ status = acpi_get_handle(parent, paths[i], handle);
+ if (ACPI_SUCCESS(status)) {
+ *path = paths[i];
+ dbg_printk(TPACPI_DBG_INIT,
+ "Found ACPI handle %s for %s\n",
+ *path, name);
+ return;
+ }
+ }
+
+ vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n",
+ name);
+ *handle = NULL;
+}
+
+static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct ibm_struct *ibm = data;
+
+ if (!ibm || !ibm->acpi || !ibm->acpi->notify)
+ return;
+
+ ibm->acpi->notify(ibm, event);
+}
+
+static int __init setup_acpi_notify(struct ibm_struct *ibm)
+{
+ acpi_status status;
+ int rc;
+
+ BUG_ON(!ibm->acpi);
+
+ if (!*ibm->acpi->handle)
+ return 0;
+
+ vdbg_printk(TPACPI_DBG_INIT,
+ "setting up ACPI notify for %s\n", ibm->name);
+
+ rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
+ if (rc < 0) {
+ printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n",
+ ibm->name, rc);
+ return -ENODEV;
+ }
+
+ acpi_driver_data(ibm->acpi->device) = ibm;
+ sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
+ IBM_ACPI_EVENT_PREFIX,
+ ibm->name);
+
+ status = acpi_install_notify_handler(*ibm->acpi->handle,
+ ibm->acpi->type, dispatch_acpi_notify, ibm);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_ALREADY_EXISTS) {
+ printk(IBM_NOTICE "another device driver is already handling %s events\n",
+ ibm->name);
+ } else {
+ printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
+ ibm->name, status);
+ }
+ return -ENODEV;
+ }
+ ibm->flags.acpi_notify_installed = 1;
+ return 0;
+}
+
+static int __init tpacpi_device_add(struct acpi_device *device)
+{
+ return 0;
+}
+
+static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
+{
+ int rc;
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "registering %s as an ACPI driver\n", ibm->name);
+
+ BUG_ON(!ibm->acpi);
+
+ ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
+ if (!ibm->acpi->driver) {
+ printk(IBM_ERR "kzalloc(ibm->driver) failed\n");
+ return -ENOMEM;
+ }
+
+ sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
+ ibm->acpi->driver->ids = ibm->acpi->hid;
+ ibm->acpi->driver->ops.add = &tpacpi_device_add;
+
+ rc = acpi_bus_register_driver(ibm->acpi->driver);
+ if (rc < 0) {
+ printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
+ ibm->acpi->hid, rc);
+ kfree(ibm->acpi->driver);
+ ibm->acpi->driver = NULL;
+ } else if (!rc)
+ ibm->flags.acpi_driver_registered = 1;
+
+ return rc;
+}
+
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Procfs Helpers
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+static int dispatch_procfs_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct ibm_struct *ibm = data;
+ int len;
+
+ if (!ibm || !ibm->read)
+ return -EINVAL;
+
+ len = ibm->read(page);
+ if (len < 0)
+ return len;
+
+ if (len <= off + count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+
+static int dispatch_procfs_write(struct file *file,
+ const char __user * userbuf,
+ unsigned long count, void *data)
+{
+ struct ibm_struct *ibm = data;
+ char *kernbuf;
+ int ret;
+
+ if (!ibm || !ibm->write)
+ return -EINVAL;
+
+ kernbuf = kmalloc(count + 2, GFP_KERNEL);
+ if (!kernbuf)
+ return -ENOMEM;
+
+ if (copy_from_user(kernbuf, userbuf, count)) {
+ kfree(kernbuf);
+ return -EFAULT;
+ }
+
+ kernbuf[count] = 0;
+ strcat(kernbuf, ",");
+ ret = ibm->write(kernbuf);
+ if (ret == 0)
+ ret = count;
+
+ kfree(kernbuf);
+
+ return ret;
+}
+
+static char *next_cmd(char **cmds)
+{
+ char *start = *cmds;
+ char *end;
+
+ while ((end = strchr(start, ',')) && end == start)
+ start = end + 1;
+
+ if (!end)
+ return NULL;
+
+ *end = 0;
+ *cmds = end + 1;
+ return start;
+}
+
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Device model: hwmon and platform
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+static struct platform_device *tpacpi_pdev = NULL;
+static struct class_device *tpacpi_hwmon = NULL;
+
+static struct platform_driver tpacpi_pdriver = {
+ .driver = {
+ .name = IBM_DRVR_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+
+/*************************************************************************
+ * thinkpad-acpi driver attributes
+ */
+
+/* interface_version --------------------------------------------------- */
+static ssize_t tpacpi_driver_interface_version_show(
+ struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
+}
+
+static DRIVER_ATTR(interface_version, S_IRUGO,
+ tpacpi_driver_interface_version_show, NULL);
+
+/* debug_level --------------------------------------------------------- */
+static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
+}
+
+static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+
+ if (parse_strtoul(buf, 0xffff, &t))
+ return -EINVAL;
+
+ dbg_level = t;
+
+ return count;
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ tpacpi_driver_debug_show, tpacpi_driver_debug_store);
+
+/* version ------------------------------------------------------------- */
+static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);
+}
+
+static DRIVER_ATTR(version, S_IRUGO,
+ tpacpi_driver_version_show, NULL);
+
+/* --------------------------------------------------------------------- */
+
+static struct driver_attribute* tpacpi_driver_attributes[] = {
+ &driver_attr_debug_level, &driver_attr_version,
+ &driver_attr_interface_version,
+};
+
+static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
+{
+ int i, res;
+
+ i = 0;
+ res = 0;
+ while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
+ res = driver_create_file(drv, tpacpi_driver_attributes[i]);
+ i++;
+ }
+
+ return res;
+}
+
+static void tpacpi_remove_driver_attributes(struct device_driver *drv)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
+ driver_remove_file(drv, tpacpi_driver_attributes[i]);
+}
+
+/*************************************************************************
+ * sysfs support helpers
+ */
+
+struct attribute_set_obj {
+ struct attribute_set s;
+ struct attribute *a;
+} __attribute__((packed));
+
+static struct attribute_set *create_attr_set(unsigned int max_members,
+ const char* name)
+{
+ struct attribute_set_obj *sobj;
+
+ if (max_members == 0)
+ return NULL;
+
+ /* Allocates space for implicit NULL at the end too */
+ sobj = kzalloc(sizeof(struct attribute_set_obj) +
+ max_members * sizeof(struct attribute *),
+ GFP_KERNEL);
+ if (!sobj)
+ return NULL;
+ sobj->s.max_members = max_members;
+ sobj->s.group.attrs = &sobj->a;
+ sobj->s.group.name = name;
+
+ return &sobj->s;
+}
+
+/* not multi-threaded safe, use it in a single thread per set */
+static int add_to_attr_set(struct attribute_set* s, struct attribute *attr)
+{
+ if (!s || !attr)
+ return -EINVAL;
+
+ if (s->members >= s->max_members)
+ return -ENOMEM;
+
+ s->group.attrs[s->members] = attr;
+ s->members++;
+
+ return 0;
+}
+
+static int add_many_to_attr_set(struct attribute_set* s,
+ struct attribute **attr,
+ unsigned int count)
+{
+ int i, res;
+
+ for (i = 0; i < count; i++) {
+ res = add_to_attr_set(s, attr[i]);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static void delete_attr_set(struct attribute_set* s, struct kobject *kobj)
+{
+ sysfs_remove_group(kobj, &s->group);
+ destroy_attr_set(s);
+}
+
+static int parse_strtoul(const char *buf,
+ unsigned long max, unsigned long *value)
+{
+ char *endp;
+
+ *value = simple_strtoul(buf, &endp, 0);
+ while (*endp && isspace(*endp))
+ endp++;
+ if (*endp || *value > max)
+ return -EINVAL;
+
+ return 0;
+}
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Subdrivers
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/*************************************************************************
+ * thinkpad-acpi init subdriver
+ */
+
+static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
+{
+ printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
+ printk(IBM_INFO "%s\n", IBM_URL);
+
+ if (ibm_thinkpad_ec_found)
+ printk(IBM_INFO "ThinkPad EC firmware %s\n",
+ ibm_thinkpad_ec_found);
+
+ return 0;
+}
+
+static int thinkpad_acpi_driver_read(char *p)
+{
+ int len = 0;
+
+ len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
+ len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
+
+ return len;
+}
+
+static struct ibm_struct thinkpad_acpi_driver_data = {
+ .name = "driver",
+ .read = thinkpad_acpi_driver_read,
+};
+
+/*************************************************************************
+ * Hotkey subdriver
+ */
+
+static int hotkey_orig_status;
+static int hotkey_orig_mask;
+
+static struct attribute_set *hotkey_dev_attributes = NULL;
+
+/* sysfs hotkey enable ------------------------------------------------- */
+static ssize_t hotkey_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res, status, mask;
+
+ res = hotkey_get(&status, &mask);
+ if (res)
+ return res;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", status);
+}
+
+static ssize_t hotkey_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+ int res, status, mask;
+
+ if (parse_strtoul(buf, 1, &t))
+ return -EINVAL;
+
+ res = hotkey_get(&status, &mask);
+ if (!res)
+ res = hotkey_set(t, mask);
+
+ return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_hotkey_enable =
+ __ATTR(enable, S_IWUSR | S_IRUGO,
+ hotkey_enable_show, hotkey_enable_store);
+
+/* sysfs hotkey mask --------------------------------------------------- */
+static ssize_t hotkey_mask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res, status, mask;
+
+ res = hotkey_get(&status, &mask);
+ if (res)
+ return res;
+
+ return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
+}
+
+static ssize_t hotkey_mask_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+ int res, status, mask;
+
+ if (parse_strtoul(buf, 0xffff, &t))
+ return -EINVAL;
+
+ res = hotkey_get(&status, &mask);
+ if (!res)
+ hotkey_set(status, t);
+
+ return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_hotkey_mask =
+ __ATTR(mask, S_IWUSR | S_IRUGO,
+ hotkey_mask_show, hotkey_mask_store);
+
+/* sysfs hotkey bios_enabled ------------------------------------------- */
+static ssize_t hotkey_bios_enabled_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status);
+}
+
+static struct device_attribute dev_attr_hotkey_bios_enabled =
+ __ATTR(bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL);
+
+/* sysfs hotkey bios_mask ---------------------------------------------- */
+static ssize_t hotkey_bios_mask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_bios_mask =
+ __ATTR(bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *hotkey_mask_attributes[] = {
+ &dev_attr_hotkey_mask.attr,
+ &dev_attr_hotkey_bios_enabled.attr,
+ &dev_attr_hotkey_bios_mask.attr,
+};
+
+static int __init hotkey_init(struct ibm_init_struct *iibm)
+{
+ int res;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(hkey);
+ mutex_init(&hotkey_mutex);
+
+ /* hotkey not supported on 570 */
+ tp_features.hotkey = hkey_handle != NULL;
+
+ vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
+ str_supported(tp_features.hotkey));
+
+ if (tp_features.hotkey) {
+ hotkey_dev_attributes = create_attr_set(4,
+ TPACPI_HOTKEY_SYSFS_GROUP);
+ if (!hotkey_dev_attributes)
+ return -ENOMEM;
+ res = add_to_attr_set(hotkey_dev_attributes,
+ &dev_attr_hotkey_enable.attr);
+ if (res)
+ return res;
+
+ /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+ A30, R30, R31, T20-22, X20-21, X22-24 */
+ tp_features.hotkey_mask =
+ acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
+
+ vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
+ str_supported(tp_features.hotkey_mask));
+
+ res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
+ if (!res && tp_features.hotkey_mask) {
+ res = add_many_to_attr_set(hotkey_dev_attributes,
+ hotkey_mask_attributes,
+ ARRAY_SIZE(hotkey_mask_attributes));
+ }
+ if (!res)
+ res = register_attr_set_with_sysfs(
+ hotkey_dev_attributes,
+ &tpacpi_pdev->dev.kobj);
+
+ if (res)
+ return res;
+ }
+
+ return (tp_features.hotkey)? 0 : 1;
+}
+
+static void hotkey_exit(void)
+{
+ int res;
+
+ if (tp_features.hotkey) {
+ dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n");
+ res = hotkey_set(hotkey_orig_status, hotkey_orig_mask);
+ if (res)
+ printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n");
+ }
+
+ if (hotkey_dev_attributes) {
+ delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
+ hotkey_dev_attributes = NULL;
+ }
+}
+
+static void hotkey_notify(struct ibm_struct *ibm, u32 event)
+{
+ int hkey;
+
+ if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
+ acpi_bus_generate_event(ibm->acpi->device, event, hkey);
+ else {
+ printk(IBM_ERR "unknown hotkey event %d\n", event);
+ acpi_bus_generate_event(ibm->acpi->device, event, 0);
+ }
+}
+
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_get(int *status, int *mask)
+{
+ if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
+ return -EIO;
+
+ if (tp_features.hotkey_mask)
+ if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_set(int status, int mask)
+{
+ int i;
+
+ if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
+ return -EIO;
+
+ if (tp_features.hotkey_mask)
+ for (i = 0; i < 32; i++) {
+ int bit = ((1 << i) & mask) != 0;
+ if (!acpi_evalf(hkey_handle,
+ NULL, "MHKM", "vdd", i + 1, bit))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int hotkey_read(char *p)
+{
+ int res, status, mask;
+ int len = 0;
+
+ if (!tp_features.hotkey) {
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ return len;
+ }
+
+ res = mutex_lock_interruptible(&hotkey_mutex);
+ if (res < 0)
+ return res;
+ res = hotkey_get(&status, &mask);
+ mutex_unlock(&hotkey_mutex);
+ if (res)
+ return res;
+
+ len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
+ if (tp_features.hotkey_mask) {
+ len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+ len += sprintf(p + len,
+ "commands:\tenable, disable, reset, <mask>\n");
+ } else {
+ len += sprintf(p + len, "mask:\t\tnot supported\n");
+ len += sprintf(p + len, "commands:\tenable, disable, reset\n");
+ }
+
+ return len;
+}
+
+static int hotkey_write(char *buf)
+{
+ int res, status, mask;
+ char *cmd;
+ int do_cmd = 0;
+
+ if (!tp_features.hotkey)
+ return -ENODEV;
+
+ res = mutex_lock_interruptible(&hotkey_mutex);
+ if (res < 0)
+ return res;
+
+ res = hotkey_get(&status, &mask);
+ if (res)
+ goto errexit;
+
+ res = 0;
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "enable") == 0) {
+ status = 1;
+ } else if (strlencmp(cmd, "disable") == 0) {
+ status = 0;
+ } else if (strlencmp(cmd, "reset") == 0) {
+ status = hotkey_orig_status;
+ mask = hotkey_orig_mask;
+ } else if (sscanf(cmd, "0x%x", &mask) == 1) {
+ /* mask set */
+ } else if (sscanf(cmd, "%x", &mask) == 1) {
+ /* mask set */
+ } else {
+ res = -EINVAL;
+ goto errexit;
+ }
+ do_cmd = 1;
+ }
+
+ if (do_cmd)
+ res = hotkey_set(status, mask);
+
+errexit:
+ mutex_unlock(&hotkey_mutex);
+ return res;
+}
+
+static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = {
+ .hid = IBM_HKEY_HID,
+ .notify = hotkey_notify,
+ .handle = &hkey_handle,
+ .type = ACPI_DEVICE_NOTIFY,
+};
+
+static struct ibm_struct hotkey_driver_data = {
+ .name = "hotkey",
+ .read = hotkey_read,
+ .write = hotkey_write,
+ .exit = hotkey_exit,
+ .acpi = &ibm_hotkey_acpidriver,
+};
+
+/*************************************************************************
+ * Bluetooth subdriver
+ */
+
+/* sysfs bluetooth enable ---------------------------------------------- */
+static ssize_t bluetooth_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int status;
+
+ status = bluetooth_get_radiosw();
+ if (status < 0)
+ return status;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
+}
+
+static ssize_t bluetooth_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+ int res;
+
+ if (parse_strtoul(buf, 1, &t))
+ return -EINVAL;
+
+ res = bluetooth_set_radiosw(t);
+
+ return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_bluetooth_enable =
+ __ATTR(enable, S_IWUSR | S_IRUGO,
+ bluetooth_enable_show, bluetooth_enable_store);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *bluetooth_attributes[] = {
+ &dev_attr_bluetooth_enable.attr,
+ NULL
+};
+
+static const struct attribute_group bluetooth_attr_group = {
+ .name = TPACPI_BLUETH_SYSFS_GROUP,
+ .attrs = bluetooth_attributes,
+};
+
+static int __init bluetooth_init(struct ibm_init_struct *iibm)
+{
+ int res;
+ int status = 0;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(hkey);
+
+ /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+ G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
+ tp_features.bluetooth = hkey_handle &&
+ acpi_evalf(hkey_handle, &status, "GBDC", "qd");
+
+ vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n",
+ str_supported(tp_features.bluetooth),
+ status);
+
+ if (tp_features.bluetooth) {
+ if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
+ /* no bluetooth hardware present in system */
+ tp_features.bluetooth = 0;
+ dbg_printk(TPACPI_DBG_INIT,
+ "bluetooth hardware not installed\n");
+ } else {
+ res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ &bluetooth_attr_group);
+ if (res)
+ return res;
+ }
+ }
+
+ return (tp_features.bluetooth)? 0 : 1;
+}
+
+static void bluetooth_exit(void)
+{
+ sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ &bluetooth_attr_group);
+}
+
+static int bluetooth_get_radiosw(void)
+{
+ int status;
+
+ if (!tp_features.bluetooth)
+ return -ENODEV;
+
+ if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+ return -EIO;
+
+ return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);
+}
+
+static int bluetooth_set_radiosw(int radio_on)
+{
+ int status;
+
+ if (!tp_features.bluetooth)
+ return -ENODEV;
+
+ if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+ return -EIO;
+ if (radio_on)
+ status |= TP_ACPI_BLUETOOTH_RADIOSSW;
+ else
+ status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
+ if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
+ return -EIO;
+
+ return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int bluetooth_read(char *p)
+{
+ int len = 0;
+ int status = bluetooth_get_radiosw();
+
+ if (!tp_features.bluetooth)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else {
+ len += sprintf(p + len, "status:\t\t%s\n",
+ (status)? "enabled" : "disabled");
+ len += sprintf(p + len, "commands:\tenable, disable\n");
+ }
+
+ return len;
+}
+
+static int bluetooth_write(char *buf)
+{
+ char *cmd;
+
+ if (!tp_features.bluetooth)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "enable") == 0) {
+ bluetooth_set_radiosw(1);
+ } else if (strlencmp(cmd, "disable") == 0) {
+ bluetooth_set_radiosw(0);
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct bluetooth_driver_data = {
+ .name = "bluetooth",
+ .read = bluetooth_read,
+ .write = bluetooth_write,
+ .exit = bluetooth_exit,
+};
+
+/*************************************************************************
+ * Wan subdriver
+ */
+
+/* sysfs wan enable ---------------------------------------------------- */
+static ssize_t wan_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int status;
+
+ status = wan_get_radiosw();
+ if (status < 0)
+ return status;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
+}
+
+static ssize_t wan_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+ int res;
+
+ if (parse_strtoul(buf, 1, &t))
+ return -EINVAL;
+
+ res = wan_set_radiosw(t);
+
+ return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_wan_enable =
+ __ATTR(enable, S_IWUSR | S_IRUGO,
+ wan_enable_show, wan_enable_store);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *wan_attributes[] = {
+ &dev_attr_wan_enable.attr,
+ NULL
+};
+
+static const struct attribute_group wan_attr_group = {
+ .name = TPACPI_WAN_SYSFS_GROUP,
+ .attrs = wan_attributes,
+};
+
+static int __init wan_init(struct ibm_init_struct *iibm)
+{
+ int res;
+ int status = 0;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(hkey);
+
+ tp_features.wan = hkey_handle &&
+ acpi_evalf(hkey_handle, &status, "GWAN", "qd");
+
+ vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n",
+ str_supported(tp_features.wan),
+ status);
+
+ if (tp_features.wan) {
+ if (!(status & TP_ACPI_WANCARD_HWPRESENT)) {
+ /* no wan hardware present in system */
+ tp_features.wan = 0;
+ dbg_printk(TPACPI_DBG_INIT,
+ "wan hardware not installed\n");
+ } else {
+ res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ &wan_attr_group);
+ if (res)
+ return res;
+ }
+ }
+
+ return (tp_features.wan)? 0 : 1;
+}
+
+static void wan_exit(void)
+{
+ sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ &wan_attr_group);
+}
+
+static int wan_get_radiosw(void)
+{
+ int status;
+
+ if (!tp_features.wan)
+ return -ENODEV;
+
+ if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+ return -EIO;
+
+ return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0);
+}
+
+static int wan_set_radiosw(int radio_on)
+{
+ int status;
+
+ if (!tp_features.wan)
+ return -ENODEV;
+
+ if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+ return -EIO;
+ if (radio_on)
+ status |= TP_ACPI_WANCARD_RADIOSSW;
+ else
+ status &= ~TP_ACPI_WANCARD_RADIOSSW;
+ if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
+ return -EIO;
+
+ return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int wan_read(char *p)
+{
+ int len = 0;
+ int status = wan_get_radiosw();
+
+ if (!tp_features.wan)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else {
+ len += sprintf(p + len, "status:\t\t%s\n",
+ (status)? "enabled" : "disabled");
+ len += sprintf(p + len, "commands:\tenable, disable\n");
+ }
+
+ return len;
+}
+
+static int wan_write(char *buf)
+{
+ char *cmd;
+
+ if (!tp_features.wan)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "enable") == 0) {
+ wan_set_radiosw(1);
+ } else if (strlencmp(cmd, "disable") == 0) {
+ wan_set_radiosw(0);
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct wan_driver_data = {
+ .name = "wan",
+ .read = wan_read,
+ .write = wan_write,
+ .exit = wan_exit,
+ .flags.experimental = 1,
+};
+
+/*************************************************************************
+ * Video subdriver
+ */
+
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
+
+IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
+ "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
+ "\\_SB.PCI0.VID0", /* 770e */
+ "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
+ "\\_SB.PCI0.AGP.VID", /* all others */
+ ); /* R30, R31 */
+
+IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
+
+static int __init video_init(struct ibm_init_struct *iibm)
+{
+ int ivga;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(vid);
+ IBM_ACPIHANDLE_INIT(vid2);
+
+ if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
+ /* G41, assume IVGA doesn't change */
+ vid_handle = vid2_handle;
+
+ if (!vid_handle)
+ /* video switching not supported on R30, R31 */
+ video_supported = TPACPI_VIDEO_NONE;
+ else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
+ /* 570 */
+ video_supported = TPACPI_VIDEO_570;
+ else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
+ /* 600e/x, 770e, 770x */
+ video_supported = TPACPI_VIDEO_770;
+ else
+ /* all others */
+ video_supported = TPACPI_VIDEO_NEW;
+
+ vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n",
+ str_supported(video_supported != TPACPI_VIDEO_NONE),
+ video_supported);
+
+ return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1;
+}
+
+static void video_exit(void)
+{
+ dbg_printk(TPACPI_DBG_EXIT,
+ "restoring original video autoswitch mode\n");
+ if (video_autosw_set(video_orig_autosw))
+ printk(IBM_ERR "error while trying to restore original "
+ "video autoswitch mode\n");
+}
+
+static int video_outputsw_get(void)
+{
+ int status = 0;
+ int i;
+
+ switch (video_supported) {
+ case TPACPI_VIDEO_570:
+ if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd",
+ TP_ACPI_VIDEO_570_PHSCMD))
+ return -EIO;
+ status = i & TP_ACPI_VIDEO_570_PHSMASK;
+ break;
+ case TPACPI_VIDEO_770:
+ if (!acpi_evalf(NULL, &i, "\\VCDL", "d"))
+ return -EIO;
+ if (i)
+ status |= TP_ACPI_VIDEO_S_LCD;
+ if (!acpi_evalf(NULL, &i, "\\VCDC", "d"))
+ return -EIO;
+ if (i)
+ status |= TP_ACPI_VIDEO_S_CRT;
+ break;
+ case TPACPI_VIDEO_NEW:
+ if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) ||
+ !acpi_evalf(NULL, &i, "\\VCDC", "d"))
+ return -EIO;
+ if (i)
+ status |= TP_ACPI_VIDEO_S_CRT;
+
+ if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) ||
+ !acpi_evalf(NULL, &i, "\\VCDL", "d"))
+ return -EIO;
+ if (i)
+ status |= TP_ACPI_VIDEO_S_LCD;
+ if (!acpi_evalf(NULL, &i, "\\VCDD", "d"))
+ return -EIO;
+ if (i)
+ status |= TP_ACPI_VIDEO_S_DVI;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return status;
+}
+
+static int video_outputsw_set(int status)
+{
+ int autosw;
+ int res = 0;
+
+ switch (video_supported) {
+ case TPACPI_VIDEO_570:
+ res = acpi_evalf(NULL, NULL,
+ "\\_SB.PHS2", "vdd",
+ TP_ACPI_VIDEO_570_PHS2CMD,
+ status | TP_ACPI_VIDEO_570_PHS2SET);
+ break;
+ case TPACPI_VIDEO_770:
+ autosw = video_autosw_get();
+ if (autosw < 0)
+ return autosw;
+
+ res = video_autosw_set(1);
+ if (res)
+ return res;
+ res = acpi_evalf(vid_handle, NULL,
+ "ASWT", "vdd", status * 0x100, 0);
+ if (!autosw && video_autosw_set(autosw)) {
+ printk(IBM_ERR "video auto-switch left enabled due to error\n");
+ return -EIO;
+ }
+ break;
+ case TPACPI_VIDEO_NEW:
+ res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
+ acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return (res)? 0 : -EIO;
+}
+
+static int video_autosw_get(void)
+{
+ int autosw = 0;
+
+ switch (video_supported) {
+ case TPACPI_VIDEO_570:
+ if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d"))
+ return -EIO;
+ break;
+ case TPACPI_VIDEO_770:
+ case TPACPI_VIDEO_NEW:
+ if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d"))
+ return -EIO;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return autosw & 1;
+}
+
+static int video_autosw_set(int enable)
+{
+ if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0))
+ return -EIO;
+ return 0;
+}
+
+static int video_outputsw_cycle(void)
+{
+ int autosw = video_autosw_get();
+ int res;
+
+ if (autosw < 0)
+ return autosw;
+
+ switch (video_supported) {
+ case TPACPI_VIDEO_570:
+ res = video_autosw_set(1);
+ if (res)
+ return res;
+ res = acpi_evalf(ec_handle, NULL, "_Q16", "v");
+ break;
+ case TPACPI_VIDEO_770:
+ case TPACPI_VIDEO_NEW:
+ res = video_autosw_set(1);
+ if (res)
+ return res;
+ res = acpi_evalf(vid_handle, NULL, "VSWT", "v");
+ break;
+ default:
+ return -ENOSYS;
+ }
+ if (!autosw && video_autosw_set(autosw)) {
+ printk(IBM_ERR "video auto-switch left enabled due to error\n");
+ return -EIO;
+ }
+
+ return (res)? 0 : -EIO;
+}
+
+static int video_expand_toggle(void)
+{
+ switch (video_supported) {
+ case TPACPI_VIDEO_570:
+ return acpi_evalf(ec_handle, NULL, "_Q17", "v")?
+ 0 : -EIO;
+ case TPACPI_VIDEO_770:
+ return acpi_evalf(vid_handle, NULL, "VEXP", "v")?
+ 0 : -EIO;
+ case TPACPI_VIDEO_NEW:
+ return acpi_evalf(NULL, NULL, "\\VEXP", "v")?
+ 0 : -EIO;
+ default:
+ return -ENOSYS;
+ }
+ /* not reached */
+}
+
+static int video_read(char *p)
+{
+ int status, autosw;
+ int len = 0;
+
+ if (video_supported == TPACPI_VIDEO_NONE) {
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ return len;
+ }
+
+ status = video_outputsw_get();
+ if (status < 0)
+ return status;
+
+ autosw = video_autosw_get();
+ if (autosw < 0)
+ return autosw;
+
+ len += sprintf(p + len, "status:\t\tsupported\n");
+ len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
+ len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
+ if (video_supported == TPACPI_VIDEO_NEW)
+ len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
+ len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
+ len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
+ len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
+ if (video_supported == TPACPI_VIDEO_NEW)
+ len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
+ len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
+ len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
+
+ return len;
+}
+
+static int video_write(char *buf)
+{
+ char *cmd;
+ int enable, disable, status;
+ int res;
+
+ if (video_supported == TPACPI_VIDEO_NONE)
+ return -ENODEV;
+
+ enable = 0;
+ disable = 0;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "lcd_enable") == 0) {
+ enable |= TP_ACPI_VIDEO_S_LCD;
+ } else if (strlencmp(cmd, "lcd_disable") == 0) {
+ disable |= TP_ACPI_VIDEO_S_LCD;
+ } else if (strlencmp(cmd, "crt_enable") == 0) {
+ enable |= TP_ACPI_VIDEO_S_CRT;
+ } else if (strlencmp(cmd, "crt_disable") == 0) {
+ disable |= TP_ACPI_VIDEO_S_CRT;
+ } else if (video_supported == TPACPI_VIDEO_NEW &&
+ strlencmp(cmd, "dvi_enable") == 0) {
+ enable |= TP_ACPI_VIDEO_S_DVI;
+ } else if (video_supported == TPACPI_VIDEO_NEW &&
+ strlencmp(cmd, "dvi_disable") == 0) {
+ disable |= TP_ACPI_VIDEO_S_DVI;
+ } else if (strlencmp(cmd, "auto_enable") == 0) {
+ res = video_autosw_set(1);
+ if (res)
+ return res;
+ } else if (strlencmp(cmd, "auto_disable") == 0) {
+ res = video_autosw_set(0);
+ if (res)
+ return res;
+ } else if (strlencmp(cmd, "video_switch") == 0) {
+ res = video_outputsw_cycle();
+ if (res)
+ return res;
+ } else if (strlencmp(cmd, "expand_toggle") == 0) {
+ res = video_expand_toggle();
+ if (res)
+ return res;
+ } else
+ return -EINVAL;
+ }
+
+ if (enable || disable) {
+ status = video_outputsw_get();
+ if (status < 0)
+ return status;
+ res = video_outputsw_set((status & ~disable) | enable);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct video_driver_data = {
+ .name = "video",
+ .read = video_read,
+ .write = video_write,
+ .exit = video_exit,
+};
+
+/*************************************************************************
+ * Light (thinklight) subdriver
+ */
+
+IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
+IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
+
+static int __init light_init(struct ibm_init_struct *iibm)
+{
+ vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(ledb);
+ IBM_ACPIHANDLE_INIT(lght);
+ IBM_ACPIHANDLE_INIT(cmos);
+
+ /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
+ tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
+
+ if (tp_features.light)
+ /* light status not supported on
+ 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
+ tp_features.light_status =
+ acpi_evalf(ec_handle, NULL, "KBLT", "qv");
+
+ vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
+ str_supported(tp_features.light));
+
+ return (tp_features.light)? 0 : 1;
+}
+
+static int light_read(char *p)
+{
+ int len = 0;
+ int status = 0;
+
+ if (!tp_features.light) {
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ } else if (!tp_features.light_status) {
+ len += sprintf(p + len, "status:\t\tunknown\n");
+ len += sprintf(p + len, "commands:\ton, off\n");
+ } else {
+ if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
+ return -EIO;
+ len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
+ len += sprintf(p + len, "commands:\ton, off\n");
+ }
+
+ return len;
+}
+
+static int light_write(char *buf)
+{
+ int cmos_cmd, lght_cmd;
+ char *cmd;
+ int success;
+
+ if (!tp_features.light)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "on") == 0) {
+ cmos_cmd = 0x0c;
+ lght_cmd = 1;
+ } else if (strlencmp(cmd, "off") == 0) {
+ cmos_cmd = 0x0d;
+ lght_cmd = 0;
+ } else
+ return -EINVAL;
+
+ success = cmos_handle ?
+ acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
+ acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
+ if (!success)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct light_driver_data = {
+ .name = "light",
+ .read = light_read,
+ .write = light_write,
+};
+
+/*************************************************************************
+ * Dock subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+
+IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
+ "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
+ "\\_SB.PCI0.PCI1.DOCK", /* all others */
+ "\\_SB.PCI.ISA.SLCE", /* 570 */
+ ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
+
+/* don't list other alternatives as we install a notify handler on the 570 */
+IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
+
+static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
+ {
+ .notify = dock_notify,
+ .handle = &dock_handle,
+ .type = ACPI_SYSTEM_NOTIFY,
+ },
+ {
+ .hid = IBM_PCI_HID,
+ .notify = dock_notify,
+ .handle = &pci_handle,
+ .type = ACPI_SYSTEM_NOTIFY,
+ },
+};
+
+static struct ibm_struct dock_driver_data[2] = {
+ {
+ .name = "dock",
+ .read = dock_read,
+ .write = dock_write,
+ .acpi = &ibm_dock_acpidriver[0],
+ },
+ {
+ .name = "dock",
+ .acpi = &ibm_dock_acpidriver[1],
+ },
+};
+
+#define dock_docked() (_sta(dock_handle) & 1)
+
+static int __init dock_init(struct ibm_init_struct *iibm)
+{
+ vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(dock);
+
+ vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
+ str_supported(dock_handle != NULL));
+
+ return (dock_handle)? 0 : 1;
+}
+
+static int __init dock_init2(struct ibm_init_struct *iibm)
+{
+ int dock2_needed;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n");
+
+ if (dock_driver_data[0].flags.acpi_driver_registered &&
+ dock_driver_data[0].flags.acpi_notify_installed) {
+ IBM_ACPIHANDLE_INIT(pci);
+ dock2_needed = (pci_handle != NULL);
+ vdbg_printk(TPACPI_DBG_INIT,
+ "dock PCI handler for the TP 570 is %s\n",
+ str_supported(dock2_needed));
+ } else {
+ vdbg_printk(TPACPI_DBG_INIT,
+ "dock subdriver part 2 not required\n");
+ dock2_needed = 0;
+ }
+
+ return (dock2_needed)? 0 : 1;
+}
+
+static void dock_notify(struct ibm_struct *ibm, u32 event)
+{
+ int docked = dock_docked();
+ int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
+
+ if (event == 1 && !pci) /* 570 */
+ acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
+ else if (event == 1 && pci) /* 570 */
+ acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */
+ else if (event == 3 && docked)
+ acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
+ else if (event == 3 && !docked)
+ acpi_bus_generate_event(ibm->acpi->device, event, 2); /* undock */
+ else if (event == 0 && docked)
+ acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */
+ else {
+ printk(IBM_ERR "unknown dock event %d, status %d\n",
+ event, _sta(dock_handle));
+ acpi_bus_generate_event(ibm->acpi->device, event, 0); /* unknown */
+ }
+}
+
+static int dock_read(char *p)
+{
+ int len = 0;
+ int docked = dock_docked();
+
+ if (!dock_handle)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else if (!docked)
+ len += sprintf(p + len, "status:\t\tundocked\n");
+ else {
+ len += sprintf(p + len, "status:\t\tdocked\n");
+ len += sprintf(p + len, "commands:\tdock, undock\n");
+ }
+
+ return len;
+}
+
+static int dock_write(char *buf)
+{
+ char *cmd;
+
+ if (!dock_docked())
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "undock") == 0) {
+ if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
+ !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
+ return -EIO;
+ } else if (strlencmp(cmd, "dock") == 0) {
+ if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
+ return -EIO;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_THINKPAD_ACPI_DOCK */
+
+/*************************************************************************
+ * Bay subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
+ "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
+ "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
+ "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
+ ); /* A21e, R30, R31 */
+IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
+ "_EJ0", /* all others */
+ ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
+IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
+ "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
+ ); /* all others */
+IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
+ "_EJ0", /* 770x */
+ ); /* all others */
+
+static int __init bay_init(struct ibm_init_struct *iibm)
+{
+ vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(bay);
+ if (bay_handle)
+ IBM_ACPIHANDLE_INIT(bay_ej);
+ IBM_ACPIHANDLE_INIT(bay2);
+ if (bay2_handle)
+ IBM_ACPIHANDLE_INIT(bay2_ej);
+
+ tp_features.bay_status = bay_handle &&
+ acpi_evalf(bay_handle, NULL, "_STA", "qv");
+ tp_features.bay_status2 = bay2_handle &&
+ acpi_evalf(bay2_handle, NULL, "_STA", "qv");
+
+ tp_features.bay_eject = bay_handle && bay_ej_handle &&
+ (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
+ tp_features.bay_eject2 = bay2_handle && bay2_ej_handle &&
+ (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
+
+ vdbg_printk(TPACPI_DBG_INIT,
+ "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n",
+ str_supported(tp_features.bay_status),
+ str_supported(tp_features.bay_eject),
+ str_supported(tp_features.bay_status2),
+ str_supported(tp_features.bay_eject2));
+
+ return (tp_features.bay_status || tp_features.bay_eject ||
+ tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1;
+}
+
+static void bay_notify(struct ibm_struct *ibm, u32 event)
+{
+ acpi_bus_generate_event(ibm->acpi->device, event, 0);
+}
+
+#define bay_occupied(b) (_sta(b##_handle) & 1)
+
+static int bay_read(char *p)
+{
+ int len = 0;
+ int occupied = bay_occupied(bay);
+ int occupied2 = bay_occupied(bay2);
+ int eject, eject2;
+
+ len += sprintf(p + len, "status:\t\t%s\n",
+ tp_features.bay_status ?
+ (occupied ? "occupied" : "unoccupied") :
+ "not supported");
+ if (tp_features.bay_status2)
+ len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
+ "occupied" : "unoccupied");
+
+ eject = tp_features.bay_eject && occupied;
+ eject2 = tp_features.bay_eject2 && occupied2;
+
+ if (eject && eject2)
+ len += sprintf(p + len, "commands:\teject, eject2\n");
+ else if (eject)
+ len += sprintf(p + len, "commands:\teject\n");
+ else if (eject2)
+ len += sprintf(p + len, "commands:\teject2\n");
+
+ return len;
+}
+
+static int bay_write(char *buf)
+{
+ char *cmd;
+
+ if (!tp_features.bay_eject && !tp_features.bay_eject2)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) {
+ if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
+ return -EIO;
+ } else if (tp_features.bay_eject2 &&
+ strlencmp(cmd, "eject2") == 0) {
+ if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
+ return -EIO;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct tp_acpi_drv_struct ibm_bay_acpidriver = {
+ .notify = bay_notify,
+ .handle = &bay_handle,
+ .type = ACPI_SYSTEM_NOTIFY,
+};
+
+static struct ibm_struct bay_driver_data = {
+ .name = "bay",
+ .read = bay_read,
+ .write = bay_write,
+ .acpi = &ibm_bay_acpidriver,
+};
+
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+
+/*************************************************************************
+ * CMOS subdriver
+ */
+
+/* sysfs cmos_command -------------------------------------------------- */
+static ssize_t cmos_command_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long cmos_cmd;
+ int res;
+
+ if (parse_strtoul(buf, 21, &cmos_cmd))
+ return -EINVAL;
+
+ res = issue_thinkpad_cmos_command(cmos_cmd);
+ return (res)? res : count;
+}
+
+static struct device_attribute dev_attr_cmos_command =
+ __ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store);
+
+/* --------------------------------------------------------------------- */
+
+static int __init cmos_init(struct ibm_init_struct *iibm)
+{
+ int res;
+
+ vdbg_printk(TPACPI_DBG_INIT,
+ "initializing cmos commands subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(cmos);
+
+ vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
+ str_supported(cmos_handle != NULL));
+
+ res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
+ if (res)
+ return res;
+
+ return (cmos_handle)? 0 : 1;
+}
+
+static void cmos_exit(void)
+{
+ device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
+}
+
+static int cmos_read(char *p)
+{
+ int len = 0;
+
+ /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+ R30, R31, T20-22, X20-21 */
+ if (!cmos_handle)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else {
+ len += sprintf(p + len, "status:\t\tsupported\n");
+ len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
+ }
+
+ return len;
+}
+
+static int cmos_write(char *buf)
+{
+ char *cmd;
+ int cmos_cmd, res;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
+ cmos_cmd >= 0 && cmos_cmd <= 21) {
+ /* cmos_cmd set */
+ } else
+ return -EINVAL;
+
+ res = issue_thinkpad_cmos_command(cmos_cmd);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct cmos_driver_data = {
+ .name = "cmos",
+ .read = cmos_read,
+ .write = cmos_write,
+ .exit = cmos_exit,
+};
+
+/*************************************************************************
+ * LED subdriver
+ */
+
+static enum led_access_mode led_supported;
+
+IBM_HANDLE(led, ec, "SLED", /* 570 */
+ "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+ "LED", /* all others */
+ ); /* R30, R31 */
+
+static int __init led_init(struct ibm_init_struct *iibm)
+{
+ vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(led);
+
+ if (!led_handle)
+ /* led not supported on R30, R31 */
+ led_supported = TPACPI_LED_NONE;
+ else if (strlencmp(led_path, "SLED") == 0)
+ /* 570 */
+ led_supported = TPACPI_LED_570;
+ else if (strlencmp(led_path, "SYSL") == 0)
+ /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+ led_supported = TPACPI_LED_OLD;
+ else
+ /* all others */
+ led_supported = TPACPI_LED_NEW;
+
+ vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
+ str_supported(led_supported), led_supported);
+
+ return (led_supported != TPACPI_LED_NONE)? 0 : 1;
+}
+
+#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
+
+static int led_read(char *p)
+{
+ int len = 0;
+
+ if (!led_supported) {
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ return len;
+ }
+ len += sprintf(p + len, "status:\t\tsupported\n");
+
+ if (led_supported == TPACPI_LED_570) {
+ /* 570 */
+ int i, status;
+ for (i = 0; i < 8; i++) {
+ if (!acpi_evalf(ec_handle,
+ &status, "GLED", "dd", 1 << i))
+ return -EIO;
+ len += sprintf(p + len, "%d:\t\t%s\n",
+ i, led_status(status));
+ }
+ }
+
+ len += sprintf(p + len, "commands:\t"
+ "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
+
+ return len;
+}
+
+/* off, on, blink */
+static const int led_sled_arg1[] = { 0, 1, 3 };
+static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
+static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
+static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
+
+static int led_write(char *buf)
+{
+ char *cmd;
+ int led, ind, ret;
+
+ if (!led_supported)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
+ return -EINVAL;
+
+ if (strstr(cmd, "off")) {
+ ind = 0;
+ } else if (strstr(cmd, "on")) {
+ ind = 1;
+ } else if (strstr(cmd, "blink")) {
+ ind = 2;
+ } else
+ return -EINVAL;
+
+ if (led_supported == TPACPI_LED_570) {
+ /* 570 */
+ led = 1 << led;
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_sled_arg1[ind]))
+ return -EIO;
+ } else if (led_supported == TPACPI_LED_OLD) {
+ /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
+ led = 1 << led;
+ ret = ec_write(TPACPI_LED_EC_HLMS, led);
+ if (ret >= 0)
+ ret =
+ ec_write(TPACPI_LED_EC_HLBL,
+ led * led_exp_hlbl[ind]);
+ if (ret >= 0)
+ ret =
+ ec_write(TPACPI_LED_EC_HLCL,
+ led * led_exp_hlcl[ind]);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* all others */
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_led_arg1[ind]))
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static struct ibm_struct led_driver_data = {
+ .name = "led",
+ .read = led_read,
+ .write = led_write,
+};
+
+/*************************************************************************
+ * Beep subdriver
+ */
+
+IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
+
+static int __init beep_init(struct ibm_init_struct *iibm)
+{
+ vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(beep);
+
+ vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
+ str_supported(beep_handle != NULL));
+
+ return (beep_handle)? 0 : 1;
+}
+
+static int beep_read(char *p)
+{
+ int len = 0;
+
+ if (!beep_handle)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else {
+ len += sprintf(p + len, "status:\t\tsupported\n");
+ len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
+ }
+
+ return len;
+}
+
+static int beep_write(char *buf)
+{
+ char *cmd;
+ int beep_cmd;
+
+ if (!beep_handle)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
+ beep_cmd >= 0 && beep_cmd <= 17) {
+ /* beep_cmd set */
+ } else
+ return -EINVAL;
+ if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct beep_driver_data = {
+ .name = "beep",
+ .read = beep_read,
+ .write = beep_write,
+};
+
+/*************************************************************************
+ * Thermal subdriver
+ */
+
+static enum thermal_access_mode thermal_read_mode;
+
+/* sysfs temp##_input -------------------------------------------------- */
+
+static ssize_t thermal_temp_input_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr =
+ to_sensor_dev_attr(attr);
+ int idx = sensor_attr->index;
+ s32 value;
+ int res;
+
+ res = thermal_get_sensor(idx, &value);
+ if (res)
+ return res;
+ if (value == TP_EC_THERMAL_TMP_NA * 1000)
+ return -ENXIO;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
+ SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB)
+
+static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
+ THERMAL_SENSOR_ATTR_TEMP(1, 0),
+ THERMAL_SENSOR_ATTR_TEMP(2, 1),
+ THERMAL_SENSOR_ATTR_TEMP(3, 2),
+ THERMAL_SENSOR_ATTR_TEMP(4, 3),
+ THERMAL_SENSOR_ATTR_TEMP(5, 4),
+ THERMAL_SENSOR_ATTR_TEMP(6, 5),
+ THERMAL_SENSOR_ATTR_TEMP(7, 6),
+ THERMAL_SENSOR_ATTR_TEMP(8, 7),
+ THERMAL_SENSOR_ATTR_TEMP(9, 8),
+ THERMAL_SENSOR_ATTR_TEMP(10, 9),
+ THERMAL_SENSOR_ATTR_TEMP(11, 10),
+ THERMAL_SENSOR_ATTR_TEMP(12, 11),
+ THERMAL_SENSOR_ATTR_TEMP(13, 12),
+ THERMAL_SENSOR_ATTR_TEMP(14, 13),
+ THERMAL_SENSOR_ATTR_TEMP(15, 14),
+ THERMAL_SENSOR_ATTR_TEMP(16, 15),
+};
+
+#define THERMAL_ATTRS(X) \
+ &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr
+
+static struct attribute *thermal_temp_input_attr[] = {
+ THERMAL_ATTRS(8),
+ THERMAL_ATTRS(9),
+ THERMAL_ATTRS(10),
+ THERMAL_ATTRS(11),
+ THERMAL_ATTRS(12),
+ THERMAL_ATTRS(13),
+ THERMAL_ATTRS(14),
+ THERMAL_ATTRS(15),
+ THERMAL_ATTRS(0),
+ THERMAL_ATTRS(1),
+ THERMAL_ATTRS(2),
+ THERMAL_ATTRS(3),
+ THERMAL_ATTRS(4),
+ THERMAL_ATTRS(5),
+ THERMAL_ATTRS(6),
+ THERMAL_ATTRS(7),
+ NULL
+};
+
+static const struct attribute_group thermal_temp_input16_group = {
+ .attrs = thermal_temp_input_attr
+};
+
+static const struct attribute_group thermal_temp_input8_group = {
+ .attrs = &thermal_temp_input_attr[8]
+};
+
+#undef THERMAL_SENSOR_ATTR_TEMP
+#undef THERMAL_ATTRS
+
+/* --------------------------------------------------------------------- */
+
+static int __init thermal_init(struct ibm_init_struct *iibm)
+{
+ u8 t, ta1, ta2;
+ int i;
+ int acpi_tmp7;
+ int res;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n");
+
+ acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
+
+ if (ibm_thinkpad_ec_found && experimental) {
+ /*
+ * Direct EC access mode: sensors at registers
+ * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
+ * non-implemented, thermal sensors return 0x80 when
+ * not available
+ */
+
+ ta1 = ta2 = 0;
+ for (i = 0; i < 8; i++) {
+ if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) {
+ ta1 |= t;
+ } else {
+ ta1 = 0;
+ break;
+ }
+ if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) {
+ ta2 |= t;
+ } else {
+ ta1 = 0;
+ break;
+ }
+ }
+ if (ta1 == 0) {
+ /* This is sheer paranoia, but we handle it anyway */
+ if (acpi_tmp7) {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "falling back to ACPI TMPx access mode\n");
+ thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
+ } else {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "disabling thermal sensors access\n");
+ thermal_read_mode = TPACPI_THERMAL_NONE;
+ }
+ } else {
+ thermal_read_mode =
+ (ta2 != 0) ?
+ TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8;
+ }
+ } else if (acpi_tmp7) {
+ if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
+ /* 600e/x, 770e, 770x */
+ thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT;
+ } else {
+ /* Standard ACPI TMPx access, max 8 sensors */
+ thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
+ }
+ } else {
+ /* temperatures not supported on 570, G4x, R30, R31, R32 */
+ thermal_read_mode = TPACPI_THERMAL_NONE;
+ }
+
+ vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n",
+ str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
+ thermal_read_mode);
+
+ switch(thermal_read_mode) {
+ case TPACPI_THERMAL_TPEC_16:
+ res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ &thermal_temp_input16_group);
+ if (res)
+ return res;
+ break;
+ case TPACPI_THERMAL_TPEC_8:
+ case TPACPI_THERMAL_ACPI_TMP07:
+ case TPACPI_THERMAL_ACPI_UPDT:
+ res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ &thermal_temp_input8_group);
+ if (res)
+ return res;
+ break;
+ case TPACPI_THERMAL_NONE:
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+static void thermal_exit(void)
+{
+ switch(thermal_read_mode) {
+ case TPACPI_THERMAL_TPEC_16:
+ sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ &thermal_temp_input16_group);
+ break;
+ case TPACPI_THERMAL_TPEC_8:
+ case TPACPI_THERMAL_ACPI_TMP07:
+ case TPACPI_THERMAL_ACPI_UPDT:
+ sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ &thermal_temp_input16_group);
+ break;
+ case TPACPI_THERMAL_NONE:
+ default:
+ break;
+ }
+}
+
+/* idx is zero-based */
+static int thermal_get_sensor(int idx, s32 *value)
+{
+ int t;
+ s8 tmp;
+ char tmpi[5];
+
+ t = TP_EC_THERMAL_TMP0;
+
+ switch (thermal_read_mode) {
+#if TPACPI_MAX_THERMAL_SENSORS >= 16
+ case TPACPI_THERMAL_TPEC_16:
+ if (idx >= 8 && idx <= 15) {
+ t = TP_EC_THERMAL_TMP8;
+ idx -= 8;
+ }
+ /* fallthrough */
+#endif
+ case TPACPI_THERMAL_TPEC_8:
+ if (idx <= 7) {
+ if (!acpi_ec_read(t + idx, &tmp))
+ return -EIO;
+ *value = tmp * 1000;
+ return 0;
+ }
+ break;
+
+ case TPACPI_THERMAL_ACPI_UPDT:
+ if (idx <= 7) {
+ snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+ if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+ return -EIO;
+ if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+ return -EIO;
+ *value = (t - 2732) * 100;
+ return 0;
+ }
+ break;
+
+ case TPACPI_THERMAL_ACPI_TMP07:
+ if (idx <= 7) {
+ snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+ if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+ return -EIO;
+ *value = t * 1000;
+ return 0;
+ }
+ break;
+
+ case TPACPI_THERMAL_NONE:
+ default:
+ return -ENOSYS;
+ }
+
+ return -EINVAL;
+}
+
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
+{
+ int res, i;
+ int n;
+
+ n = 8;
+ i = 0;
+
+ if (!s)
+ return -EINVAL;
+
+ if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
+ n = 16;
+
+ for(i = 0 ; i < n; i++) {
+ res = thermal_get_sensor(i, &s->temp[i]);
+ if (res)
+ return res;
+ }
+
+ return n;
+}
+
+static int thermal_read(char *p)
+{
+ int len = 0;
+ int n, i;
+ struct ibm_thermal_sensors_struct t;
+
+ n = thermal_get_sensors(&t);
+ if (unlikely(n < 0))
+ return n;
+
+ len += sprintf(p + len, "temperatures:\t");
+
+ if (n > 0) {
+ for (i = 0; i < (n - 1); i++)
+ len += sprintf(p + len, "%d ", t.temp[i] / 1000);
+ len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
+ } else
+ len += sprintf(p + len, "not supported\n");
+
+ return len;
+}
+
+static struct ibm_struct thermal_driver_data = {
+ .name = "thermal",
+ .read = thermal_read,
+ .exit = thermal_exit,
+};
+
+/*************************************************************************
+ * EC Dump subdriver
+ */
+
+static u8 ecdump_regs[256];
+
+static int ecdump_read(char *p)
+{
+ int len = 0;
+ int i, j;
+ u8 v;
+
+ len += sprintf(p + len, "EC "
+ " +00 +01 +02 +03 +04 +05 +06 +07"
+ " +08 +09 +0a +0b +0c +0d +0e +0f\n");
+ for (i = 0; i < 256; i += 16) {
+ len += sprintf(p + len, "EC 0x%02x:", i);
+ for (j = 0; j < 16; j++) {
+ if (!acpi_ec_read(i + j, &v))
+ break;
+ if (v != ecdump_regs[i + j])
+ len += sprintf(p + len, " *%02x", v);
+ else
+ len += sprintf(p + len, " %02x", v);
+ ecdump_regs[i + j] = v;
+ }
+ len += sprintf(p + len, "\n");
+ if (j != 16)
+ break;
+ }
+
+ /* These are way too dangerous to advertise openly... */
+#if 0
+ len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
+ " (<offset> is 00-ff, <value> is 00-ff)\n");
+ len += sprintf(p + len, "commands:\t0x<offset> <value> "
+ " (<offset> is 00-ff, <value> is 0-255)\n");
+#endif
+ return len;
+}
+
+static int ecdump_write(char *buf)
+{
+ char *cmd;
+ int i, v;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
+ /* i and v set */
+ } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
+ /* i and v set */
+ } else
+ return -EINVAL;
+ if (i >= 0 && i < 256 && v >= 0 && v < 256) {
+ if (!acpi_ec_write(i, v))
+ return -EIO;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct ecdump_driver_data = {
+ .name = "ecdump",
+ .read = ecdump_read,
+ .write = ecdump_write,
+ .flags.experimental = 1,
+};
+
+/*************************************************************************
+ * Backlight/brightness subdriver
+ */
+
+static struct backlight_device *ibm_backlight_device = NULL;
+
+static struct backlight_ops ibm_backlight_data = {
+ .get_brightness = brightness_get,
+ .update_status = brightness_update_status,
+};
+
+static int __init brightness_init(struct ibm_init_struct *iibm)
+{
+ int b;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
+
+ b = brightness_get(NULL);
+ if (b < 0)
+ return b;
+
+ ibm_backlight_device = backlight_device_register(
+ TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
+ &ibm_backlight_data);
+ if (IS_ERR(ibm_backlight_device)) {
+ printk(IBM_ERR "Could not register backlight device\n");
+ return PTR_ERR(ibm_backlight_device);
+ }
+ vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
+
+ ibm_backlight_device->props.max_brightness = 7;
+ ibm_backlight_device->props.brightness = b;
+ backlight_update_status(ibm_backlight_device);
+
+ return 0;
+}
+
+static void brightness_exit(void)
+{
+ if (ibm_backlight_device) {
+ vdbg_printk(TPACPI_DBG_EXIT,
+ "calling backlight_device_unregister()\n");
+ backlight_device_unregister(ibm_backlight_device);
+ ibm_backlight_device = NULL;
+ }
+}
+
+static int brightness_update_status(struct backlight_device *bd)
+{
+ return brightness_set(
+ (bd->props.fb_blank == FB_BLANK_UNBLANK &&
+ bd->props.power == FB_BLANK_UNBLANK) ?
+ bd->props.brightness : 0);
+}
+
+static int brightness_get(struct backlight_device *bd)
+{
+ u8 level;
+ if (!acpi_ec_read(brightness_offset, &level))
+ return -EIO;
+
+ level &= 0x7;
+
+ return level;
+}
+
+static int brightness_set(int value)
+{
+ int cmos_cmd, inc, i;
+ int current_value = brightness_get(NULL);
+
+ value &= 7;
+
+ cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
+ inc = value > current_value ? 1 : -1;
+ for (i = current_value; i != value; i += inc) {
+ if (issue_thinkpad_cmos_command(cmos_cmd))
+ return -EIO;
+ if (!acpi_ec_write(brightness_offset, i + inc))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int brightness_read(char *p)
+{
+ int len = 0;
+ int level;
+
+ if ((level = brightness_get(NULL)) < 0) {
+ len += sprintf(p + len, "level:\t\tunreadable\n");
+ } else {
+ len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
+ len += sprintf(p + len, "commands:\tup, down\n");
+ len += sprintf(p + len, "commands:\tlevel <level>"
+ " (<level> is 0-7)\n");
+ }
+
+ return len;
+}
+
+static int brightness_write(char *buf)
+{
+ int level;
+ int new_level;
+ char *cmd;
+
+ while ((cmd = next_cmd(&buf))) {
+ if ((level = brightness_get(NULL)) < 0)
+ return level;
+ level &= 7;
+
+ if (strlencmp(cmd, "up") == 0) {
+ new_level = level == 7 ? 7 : level + 1;
+ } else if (strlencmp(cmd, "down") == 0) {
+ new_level = level == 0 ? 0 : level - 1;
+ } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
+ new_level >= 0 && new_level <= 7) {
+ /* new_level set */
+ } else
+ return -EINVAL;
+
+ brightness_set(new_level);
+ }
+
+ return 0;
+}
+
+static struct ibm_struct brightness_driver_data = {
+ .name = "brightness",
+ .read = brightness_read,
+ .write = brightness_write,
+ .exit = brightness_exit,
+};
+
+/*************************************************************************
+ * Volume subdriver
+ */
+
+static int volume_read(char *p)
+{
+ int len = 0;
+ u8 level;
+
+ if (!acpi_ec_read(volume_offset, &level)) {
+ len += sprintf(p + len, "level:\t\tunreadable\n");
+ } else {
+ len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
+ len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
+ len += sprintf(p + len, "commands:\tup, down, mute\n");
+ len += sprintf(p + len, "commands:\tlevel <level>"
+ " (<level> is 0-15)\n");
+ }
+
+ return len;
+}
+
+static int volume_write(char *buf)
+{
+ int cmos_cmd, inc, i;
+ u8 level, mute;
+ int new_level, new_mute;
+ char *cmd;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (!acpi_ec_read(volume_offset, &level))
+ return -EIO;
+ new_mute = mute = level & 0x40;
+ new_level = level = level & 0xf;
+
+ if (strlencmp(cmd, "up") == 0) {
+ if (mute)
+ new_mute = 0;
+ else
+ new_level = level == 15 ? 15 : level + 1;
+ } else if (strlencmp(cmd, "down") == 0) {
+ if (mute)
+ new_mute = 0;
+ else
+ new_level = level == 0 ? 0 : level - 1;
+ } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
+ new_level >= 0 && new_level <= 15) {
+ /* new_level set */
+ } else if (strlencmp(cmd, "mute") == 0) {
+ new_mute = 0x40;
+ } else
+ return -EINVAL;
+
+ if (new_level != level) { /* mute doesn't change */
+ cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
+ inc = new_level > level ? 1 : -1;
+
+ if (mute && (issue_thinkpad_cmos_command(cmos_cmd) ||
+ !acpi_ec_write(volume_offset, level)))
+ return -EIO;
+
+ for (i = level; i != new_level; i += inc)
+ if (issue_thinkpad_cmos_command(cmos_cmd) ||
+ !acpi_ec_write(volume_offset, i + inc))
+ return -EIO;
+
+ if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
+ !acpi_ec_write(volume_offset,
+ new_level + mute)))
+ return -EIO;
+ }
+
+ if (new_mute != mute) { /* level doesn't change */
+ cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
+
+ if (issue_thinkpad_cmos_command(cmos_cmd) ||
+ !acpi_ec_write(volume_offset, level + new_mute))
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static struct ibm_struct volume_driver_data = {
+ .name = "volume",
+ .read = volume_read,
+ .write = volume_write,
+};
+
+/*************************************************************************
+ * Fan subdriver
+ */
+
+/*
+ * FAN ACCESS MODES
+ *
+ * TPACPI_FAN_RD_ACPI_GFAN:
+ * ACPI GFAN method: returns fan level
+ *
+ * see TPACPI_FAN_WR_ACPI_SFAN
+ * EC 0x2f (HFSP) not available if GFAN exists
+ *
+ * TPACPI_FAN_WR_ACPI_SFAN:
+ * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
+ *
+ * EC 0x2f (HFSP) might be available *for reading*, but do not use
+ * it for writing.
+ *
+ * TPACPI_FAN_WR_TPEC:
+ * ThinkPad EC register 0x2f (HFSP): fan control loop mode
+ * Supported on almost all ThinkPads
+ *
+ * Fan speed changes of any sort (including those caused by the
+ * disengaged mode) are usually done slowly by the firmware as the
+ * maximum ammount of fan duty cycle change per second seems to be
+ * limited.
+ *
+ * Reading is not available if GFAN exists.
+ * Writing is not available if SFAN exists.
+ *
+ * Bits
+ * 7 automatic mode engaged;
+ * (default operation mode of the ThinkPad)
+ * fan level is ignored in this mode.
+ * 6 full speed mode (takes precedence over bit 7);
+ * not available on all thinkpads. May disable
+ * the tachometer while the fan controller ramps up
+ * the speed (which can take up to a few *minutes*).
+ * Speeds up fan to 100% duty-cycle, which is far above
+ * the standard RPM levels. It is not impossible that
+ * it could cause hardware damage.
+ * 5-3 unused in some models. Extra bits for fan level
+ * in others, but still useless as all values above
+ * 7 map to the same speed as level 7 in these models.
+ * 2-0 fan level (0..7 usually)
+ * 0x00 = stop
+ * 0x07 = max (set when temperatures critical)
+ * Some ThinkPads may have other levels, see
+ * TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
+ *
+ * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
+ * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
+ * does so, its initial value is meaningless (0x07).
+ *
+ * For firmware bugs, refer to:
+ * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * ----
+ *
+ * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
+ * Main fan tachometer reading (in RPM)
+ *
+ * This register is present on all ThinkPads with a new-style EC, and
+ * it is known not to be present on the A21m/e, and T22, as there is
+ * something else in offset 0x84 according to the ACPI DSDT. Other
+ * ThinkPads from this same time period (and earlier) probably lack the
+ * tachometer as well.
+ *
+ * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
+ * was never fixed by IBM to report the EC firmware version string
+ * probably support the tachometer (like the early X models), so
+ * detecting it is quite hard. We need more data to know for sure.
+ *
+ * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
+ * might result.
+ *
+ * FIRMWARE BUG: may go stale while the EC is switching to full speed
+ * mode.
+ *
+ * For firmware bugs, refer to:
+ * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * TPACPI_FAN_WR_ACPI_FANS:
+ * ThinkPad X31, X40, X41. Not available in the X60.
+ *
+ * FANS ACPI handle: takes three arguments: low speed, medium speed,
+ * high speed. ACPI DSDT seems to map these three speeds to levels
+ * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
+ * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
+ *
+ * The speeds are stored on handles
+ * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
+ *
+ * There are three default speed sets, acessible as handles:
+ * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
+ *
+ * ACPI DSDT switches which set is in use depending on various
+ * factors.
+ *
+ * TPACPI_FAN_WR_TPEC is also available and should be used to
+ * command the fan. The X31/X40/X41 seems to have 8 fan levels,
+ * but the ACPI tables just mention level 7.
+ */
+
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
+
+static u8 fan_control_initial_status;
+static u8 fan_control_desired_level;
+
+static void fan_watchdog_fire(struct work_struct *ignored);
+static int fan_watchdog_maxinterval;
+static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
+
+IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
+IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
+ "\\FSPD", /* 600e/x, 770e, 770x */
+ ); /* all others */
+IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
+ "JFNS", /* 770x-JL */
+ ); /* all others */
+
+/*
+ * SYSFS fan layout: hwmon compatible (device)
+ *
+ * pwm*_enable:
+ * 0: "disengaged" mode
+ * 1: manual mode
+ * 2: native EC "auto" mode (recommended, hardware default)
+ *
+ * pwm*: set speed in manual mode, ignored otherwise.
+ * 0 is level 0; 255 is level 7. Intermediate points done with linear
+ * interpolation.
+ *
+ * fan*_input: tachometer reading, RPM
+ *
+ *
+ * SYSFS fan layout: extensions
+ *
+ * fan_watchdog (driver):
+ * fan watchdog interval in seconds, 0 disables (default), max 120
+ */
+
+/* sysfs fan pwm1_enable ----------------------------------------------- */
+static ssize_t fan_pwm1_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res, mode;
+ u8 status;
+
+ res = fan_get_status_safe(&status);
+ if (res)
+ return res;
+
+ if (unlikely(tp_features.fan_ctrl_status_undef)) {
+ if (status != fan_control_initial_status) {
+ tp_features.fan_ctrl_status_undef = 0;
+ } else {
+ /* Return most likely status. In fact, it
+ * might be the only possible status */
+ status = TP_EC_FAN_AUTO;
+ }
+ }
+
+ if (status & TP_EC_FAN_FULLSPEED) {
+ mode = 0;
+ } else if (status & TP_EC_FAN_AUTO) {
+ mode = 2;
+ } else
+ mode = 1;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", mode);
+}
+
+static ssize_t fan_pwm1_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+ int res, level;
+
+ if (parse_strtoul(buf, 2, &t))
+ return -EINVAL;
+
+ switch (t) {
+ case 0:
+ level = TP_EC_FAN_FULLSPEED;
+ break;
+ case 1:
+ level = TPACPI_FAN_LAST_LEVEL;
+ break;
+ case 2:
+ level = TP_EC_FAN_AUTO;
+ break;
+ case 3:
+ /* reserved for software-controlled auto mode */
+ return -ENOSYS;
+ default:
+ return -EINVAL;
+ }
+
+ res = fan_set_level_safe(level);
+ if (res == -ENXIO)
+ return -EINVAL;
+ else if (res < 0)
+ return res;
+
+ fan_watchdog_reset();
+
+ return count;
+}
+
+static struct device_attribute dev_attr_fan_pwm1_enable =
+ __ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+ fan_pwm1_enable_show, fan_pwm1_enable_store);
+
+/* sysfs fan pwm1 ------------------------------------------------------ */
+static ssize_t fan_pwm1_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res;
+ u8 status;
+
+ res = fan_get_status_safe(&status);
+ if (res)
+ return res;
+
+ if (unlikely(tp_features.fan_ctrl_status_undef)) {
+ if (status != fan_control_initial_status) {
+ tp_features.fan_ctrl_status_undef = 0;
+ } else {
+ status = TP_EC_FAN_AUTO;
+ }
+ }
+
+ if ((status &
+ (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
+ status = fan_control_desired_level;
+
+ if (status > 7)
+ status = 7;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7);
+}
+
+static ssize_t fan_pwm1_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long s;
+ int rc;
+ u8 status, newlevel;
+
+ if (parse_strtoul(buf, 255, &s))
+ return -EINVAL;
+
+ /* scale down from 0-255 to 0-7 */
+ newlevel = (s >> 5) & 0x07;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ rc = fan_get_status(&status);
+ if (!rc && (status &
+ (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+ rc = fan_set_level(newlevel);
+ if (rc == -ENXIO)
+ rc = -EINVAL;
+ else if (!rc) {
+ fan_update_desired_level(newlevel);
+ fan_watchdog_reset();
+ }
+ }
+
+ mutex_unlock(&fan_mutex);
+ return (rc)? rc : count;
+}
+
+static struct device_attribute dev_attr_fan_pwm1 =
+ __ATTR(pwm1, S_IWUSR | S_IRUGO,
+ fan_pwm1_show, fan_pwm1_store);
+
+/* sysfs fan fan1_input ------------------------------------------------ */
+static ssize_t fan_fan1_input_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res;
+ unsigned int speed;
+
+ res = fan_get_speed(&speed);
+ if (res < 0)
+ return res;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", speed);
+}
+
+static struct device_attribute dev_attr_fan_fan1_input =
+ __ATTR(fan1_input, S_IRUGO,
+ fan_fan1_input_show, NULL);
+
+/* sysfs fan fan_watchdog (driver) ------------------------------------- */
+static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval);
+}
+
+static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+
+ if (parse_strtoul(buf, 120, &t))
+ return -EINVAL;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ fan_watchdog_maxinterval = t;
+ fan_watchdog_reset();
+
+ return count;
+}
+
+static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
+ fan_fan_watchdog_show, fan_fan_watchdog_store);
+
+/* --------------------------------------------------------------------- */
+static struct attribute *fan_attributes[] = {
+ &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
+ &dev_attr_fan_fan1_input.attr,
+ NULL
+};
+
+static const struct attribute_group fan_attr_group = {
+ .attrs = fan_attributes,
+};
+
+static int __init fan_init(struct ibm_init_struct *iibm)
+{
+ int rc;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
+
+ mutex_init(&fan_mutex);
+ fan_status_access_mode = TPACPI_FAN_NONE;
+ fan_control_access_mode = TPACPI_FAN_WR_NONE;
+ fan_control_commands = 0;
+ fan_watchdog_maxinterval = 0;
+ tp_features.fan_ctrl_status_undef = 0;
+ fan_control_desired_level = 7;
+
+ IBM_ACPIHANDLE_INIT(fans);
+ IBM_ACPIHANDLE_INIT(gfan);
+ IBM_ACPIHANDLE_INIT(sfan);
+
+ if (gfan_handle) {
+ /* 570, 600e/x, 770e, 770x */
+ fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
+ } else {
+ /* all other ThinkPads: note that even old-style
+ * ThinkPad ECs supports the fan control register */
+ if (likely(acpi_ec_read(fan_status_offset,
+ &fan_control_initial_status))) {
+ fan_status_access_mode = TPACPI_FAN_RD_TPEC;
+
+ /* In some ThinkPads, neither the EC nor the ACPI
+ * DSDT initialize the fan status, and it ends up
+ * being set to 0x07 when it *could* be either
+ * 0x07 or 0x80.
+ *
+ * Enable for TP-1Y (T43), TP-78 (R51e),
+ * TP-76 (R52), TP-70 (T43, R52), which are known
+ * to be buggy. */
+ if (fan_control_initial_status == 0x07 &&
+ ibm_thinkpad_ec_found &&
+ ((ibm_thinkpad_ec_found[0] == '1' &&
+ ibm_thinkpad_ec_found[1] == 'Y') ||
+ (ibm_thinkpad_ec_found[0] == '7' &&
+ (ibm_thinkpad_ec_found[1] == '6' ||
+ ibm_thinkpad_ec_found[1] == '8' ||
+ ibm_thinkpad_ec_found[1] == '0'))
+ )) {
+ printk(IBM_NOTICE
+ "fan_init: initial fan status is "
+ "unknown, assuming it is in auto "
+ "mode\n");
+ tp_features.fan_ctrl_status_undef = 1;
+ }
+ } else {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "fan status and control unavailable\n");
+ return 1;
+ }
+ }
+
+ if (sfan_handle) {
+ /* 570, 770x-JL */
+ fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN;
+ fan_control_commands |=
+ TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE;
+ } else {
+ if (!gfan_handle) {
+ /* gfan without sfan means no fan control */
+ /* all other models implement TP EC 0x2f control */
+
+ if (fans_handle) {
+ /* X31, X40, X41 */
+ fan_control_access_mode =
+ TPACPI_FAN_WR_ACPI_FANS;
+ fan_control_commands |=
+ TPACPI_FAN_CMD_SPEED |
+ TPACPI_FAN_CMD_LEVEL |
+ TPACPI_FAN_CMD_ENABLE;
+ } else {
+ fan_control_access_mode = TPACPI_FAN_WR_TPEC;
+ fan_control_commands |=
+ TPACPI_FAN_CMD_LEVEL |
+ TPACPI_FAN_CMD_ENABLE;
+ }
+ }
+ }
+
+ vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n",
+ str_supported(fan_status_access_mode != TPACPI_FAN_NONE ||
+ fan_control_access_mode != TPACPI_FAN_WR_NONE),
+ fan_status_access_mode, fan_control_access_mode);
+
+ /* fan control master switch */
+ if (!fan_control_allowed) {
+ fan_control_access_mode = TPACPI_FAN_WR_NONE;
+ fan_control_commands = 0;
+ dbg_printk(TPACPI_DBG_INIT,
+ "fan control features disabled by parameter\n");
+ }
+
+ /* update fan_control_desired_level */
+ if (fan_status_access_mode != TPACPI_FAN_NONE)
+ fan_get_status_safe(NULL);
+
+ if (fan_status_access_mode != TPACPI_FAN_NONE ||
+ fan_control_access_mode != TPACPI_FAN_WR_NONE) {
+ rc = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ &fan_attr_group);
+ if (!(rc < 0))
+ rc = driver_create_file(&tpacpi_pdriver.driver,
+ &driver_attr_fan_watchdog);
+ if (rc < 0)
+ return rc;
+ return 0;
+ } else
+ return 1;
+}
+
+/*
+ * Call with fan_mutex held
+ */
+static void fan_update_desired_level(u8 status)
+{
+ if ((status &
+ (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+ if (status > 7)
+ fan_control_desired_level = 7;
+ else
+ fan_control_desired_level = status;
+ }
+}
+
+static int fan_get_status(u8 *status)
+{
+ u8 s;
+
+ /* TODO:
+ * Add TPACPI_FAN_RD_ACPI_FANS ? */
+
+ switch (fan_status_access_mode) {
+ case TPACPI_FAN_RD_ACPI_GFAN:
+ /* 570, 600e/x, 770e, 770x */
+
+ if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
+ return -EIO;
+
+ if (likely(status))
+ *status = s & 0x07;
+
+ break;
+
+ case TPACPI_FAN_RD_TPEC:
+ /* all except 570, 600e/x, 770e, 770x */
+ if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
+ return -EIO;
+
+ if (likely(status))
+ *status = s;
+
+ break;
+
+ default:
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int fan_get_status_safe(u8 *status)
+{
+ int rc;
+ u8 s;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+ rc = fan_get_status(&s);
+ if (!rc)
+ fan_update_desired_level(s);
+ mutex_unlock(&fan_mutex);
+
+ if (status)
+ *status = s;
+
+ return rc;
+}
+
+static void fan_exit(void)
+{
+ vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
+
+ /* FIXME: can we really do this unconditionally? */
+ sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group);
+ driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog);
+
+ cancel_delayed_work(&fan_watchdog_task);
+ flush_scheduled_work();
+}
+
+static int fan_get_speed(unsigned int *speed)
+{
+ u8 hi, lo;
+
+ switch (fan_status_access_mode) {
+ case TPACPI_FAN_RD_TPEC:
+ /* all except 570, 600e/x, 770e, 770x */
+ if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
+ !acpi_ec_read(fan_rpm_offset + 1, &hi)))
+ return -EIO;
+
+ if (likely(speed))
+ *speed = (hi << 8) | lo;
+
+ break;
+
+ default:
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void fan_watchdog_fire(struct work_struct *ignored)
+{
+ int rc;
+
+ printk(IBM_NOTICE "fan watchdog: enabling fan\n");
+ rc = fan_set_enable();
+ if (rc < 0) {
+ printk(IBM_ERR "fan watchdog: error %d while enabling fan, "
+ "will try again later...\n", -rc);
+ /* reschedule for later */
+ fan_watchdog_reset();
+ }
+}
+
+static void fan_watchdog_reset(void)
+{
+ static int fan_watchdog_active = 0;
+
+ if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
+ return;
+
+ if (fan_watchdog_active)
+ cancel_delayed_work(&fan_watchdog_task);
+
+ if (fan_watchdog_maxinterval > 0) {
+ fan_watchdog_active = 1;
+ if (!schedule_delayed_work(&fan_watchdog_task,
+ msecs_to_jiffies(fan_watchdog_maxinterval
+ * 1000))) {
+ printk(IBM_ERR "failed to schedule the fan watchdog, "
+ "watchdog will not trigger\n");
+ }
+ } else
+ fan_watchdog_active = 0;
+}
+
+static int fan_set_level(int level)
+{
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ if (level >= 0 && level <= 7) {
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
+ return -EIO;
+ } else
+ return -EINVAL;
+ break;
+
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ if ((level != TP_EC_FAN_AUTO) &&
+ (level != TP_EC_FAN_FULLSPEED) &&
+ ((level < 0) || (level > 7)))
+ return -EINVAL;
+
+ /* safety net should the EC not support AUTO
+ * or FULLSPEED mode bits and just ignore them */
+ if (level & TP_EC_FAN_FULLSPEED)
+ level |= 7; /* safety min speed 7 */
+ else if (level & TP_EC_FAN_FULLSPEED)
+ level |= 4; /* safety min speed 4 */
+
+ if (!acpi_ec_write(fan_status_offset, level))
+ return -EIO;
+ else
+ tp_features.fan_ctrl_status_undef = 0;
+ break;
+
+ default:
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int fan_set_level_safe(int level)
+{
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ if (level == TPACPI_FAN_LAST_LEVEL)
+ level = fan_control_desired_level;
+
+ rc = fan_set_level(level);
+ if (!rc)
+ fan_update_desired_level(level);
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_set_enable(void)
+{
+ u8 s;
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ rc = fan_get_status(&s);
+ if (rc < 0)
+ break;
+
+ /* Don't go out of emergency fan mode */
+ if (s != 7) {
+ s &= 0x07;
+ s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
+ }
+
+ if (!acpi_ec_write(fan_status_offset, s))
+ rc = -EIO;
+ else {
+ tp_features.fan_ctrl_status_undef = 0;
+ rc = 0;
+ }
+ break;
+
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ rc = fan_get_status(&s);
+ if (rc < 0)
+ break;
+
+ s &= 0x07;
+
+ /* Set fan to at least level 4 */
+ s |= 4;
+
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
+ rc= -EIO;
+ else
+ rc = 0;
+ break;
+
+ default:
+ rc = -ENXIO;
+ }
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_set_disable(void)
+{
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ rc = 0;
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ if (!acpi_ec_write(fan_status_offset, 0x00))
+ rc = -EIO;
+ else {
+ fan_control_desired_level = 0;
+ tp_features.fan_ctrl_status_undef = 0;
+ }
+ break;
+
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
+ rc = -EIO;
+ else
+ fan_control_desired_level = 0;
+ break;
+
+ default:
+ rc = -ENXIO;
+ }
+
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_set_speed(int speed)
+{
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ rc = 0;
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_FANS:
+ if (speed >= 0 && speed <= 65535) {
+ if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
+ speed, speed, speed))
+ rc = -EIO;
+ } else
+ rc = -EINVAL;
+ break;
+
+ default:
+ rc = -ENXIO;
+ }
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_read(char *p)
+{
+ int len = 0;
+ int rc;
+ u8 status;
+ unsigned int speed = 0;
+
+ switch (fan_status_access_mode) {
+ case TPACPI_FAN_RD_ACPI_GFAN:
+ /* 570, 600e/x, 770e, 770x */
+ if ((rc = fan_get_status_safe(&status)) < 0)
+ return rc;
+
+ len += sprintf(p + len, "status:\t\t%s\n"
+ "level:\t\t%d\n",
+ (status != 0) ? "enabled" : "disabled", status);
+ break;
+
+ case TPACPI_FAN_RD_TPEC:
+ /* all except 570, 600e/x, 770e, 770x */
+ if ((rc = fan_get_status_safe(&status)) < 0)
+ return rc;
+
+ if (unlikely(tp_features.fan_ctrl_status_undef)) {
+ if (status != fan_control_initial_status)
+ tp_features.fan_ctrl_status_undef = 0;
+ else
+ /* Return most likely status. In fact, it
+ * might be the only possible status */
+ status = TP_EC_FAN_AUTO;
+ }
+
+ len += sprintf(p + len, "status:\t\t%s\n",
+ (status != 0) ? "enabled" : "disabled");
+
+ if ((rc = fan_get_speed(&speed)) < 0)
+ return rc;
+
+ len += sprintf(p + len, "speed:\t\t%d\n", speed);
+
+ if (status & TP_EC_FAN_FULLSPEED)
+ /* Disengaged mode takes precedence */
+ len += sprintf(p + len, "level:\t\tdisengaged\n");
+ else if (status & TP_EC_FAN_AUTO)
+ len += sprintf(p + len, "level:\t\tauto\n");
+ else
+ len += sprintf(p + len, "level:\t\t%d\n", status);
+ break;
+
+ case TPACPI_FAN_NONE:
+ default:
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ }
+
+ if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) {
+ len += sprintf(p + len, "commands:\tlevel <level>");
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ len += sprintf(p + len, " (<level> is 0-7)\n");
+ break;
+
+ default:
+ len += sprintf(p + len, " (<level> is 0-7, "
+ "auto, disengaged, full-speed)\n");
+ break;
+ }
+ }
+
+ if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
+ len += sprintf(p + len, "commands:\tenable, disable\n"
+ "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
+ "1-120 (seconds))\n");
+
+ if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
+ len += sprintf(p + len, "commands:\tspeed <speed>"
+ " (<speed> is 0-65535)\n");
+
+ return len;
+}
+
+static int fan_write_cmd_level(const char *cmd, int *rc)
+{
+ int level;
+
+ if (strlencmp(cmd, "level auto") == 0)
+ level = TP_EC_FAN_AUTO;
+ else if ((strlencmp(cmd, "level disengaged") == 0) |
+ (strlencmp(cmd, "level full-speed") == 0))
+ level = TP_EC_FAN_FULLSPEED;
+ else if (sscanf(cmd, "level %d", &level) != 1)
+ return 0;
+
+ if ((*rc = fan_set_level_safe(level)) == -ENXIO)
+ printk(IBM_ERR "level command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_enable(const char *cmd, int *rc)
+{
+ if (strlencmp(cmd, "enable") != 0)
+ return 0;
+
+ if ((*rc = fan_set_enable()) == -ENXIO)
+ printk(IBM_ERR "enable command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_disable(const char *cmd, int *rc)
+{
+ if (strlencmp(cmd, "disable") != 0)
+ return 0;
+
+ if ((*rc = fan_set_disable()) == -ENXIO)
+ printk(IBM_ERR "disable command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_speed(const char *cmd, int *rc)
+{
+ int speed;
+
+ /* TODO:
+ * Support speed <low> <medium> <high> ? */
+
+ if (sscanf(cmd, "speed %d", &speed) != 1)
+ return 0;
+
+ if ((*rc = fan_set_speed(speed)) == -ENXIO)
+ printk(IBM_ERR "speed command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_watchdog(const char *cmd, int *rc)
+{
+ int interval;
+
+ if (sscanf(cmd, "watchdog %d", &interval) != 1)
+ return 0;
+
+ if (interval < 0 || interval > 120)
+ *rc = -EINVAL;
+ else
+ fan_watchdog_maxinterval = interval;
+
+ return 1;
+}
+
+static int fan_write(char *buf)
+{
+ char *cmd;
+ int rc = 0;
+
+ while (!rc && (cmd = next_cmd(&buf))) {
+ if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) &&
+ fan_write_cmd_level(cmd, &rc)) &&
+ !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) &&
+ (fan_write_cmd_enable(cmd, &rc) ||
+ fan_write_cmd_disable(cmd, &rc) ||
+ fan_write_cmd_watchdog(cmd, &rc))) &&
+ !((fan_control_commands & TPACPI_FAN_CMD_SPEED) &&
+ fan_write_cmd_speed(cmd, &rc))
+ )
+ rc = -EINVAL;
+ else if (!rc)
+ fan_watchdog_reset();
+ }
+
+ return rc;
+}
+
+static struct ibm_struct fan_driver_data = {
+ .name = "fan",
+ .read = fan_read,
+ .write = fan_write,
+ .exit = fan_exit,
+};
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Infrastructure
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/* /proc support */
+static struct proc_dir_entry *proc_dir = NULL;
+
+/* Subdriver registry */
+static LIST_HEAD(tpacpi_all_drivers);
+
+
+/*
+ * Module and infrastructure proble, init and exit handling
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DEBUG
+static const char * __init str_supported(int is_supported)
+{
+ static char text_unsupported[] __initdata = "not supported";
+
+ return (is_supported)? &text_unsupported[4] : &text_unsupported[0];
+}
+#endif /* CONFIG_THINKPAD_ACPI_DEBUG */
+
+static int __init ibm_init(struct ibm_init_struct *iibm)
+{
+ int ret;
+ struct ibm_struct *ibm = iibm->data;
+ struct proc_dir_entry *entry;
+
+ BUG_ON(ibm == NULL);
+
+ INIT_LIST_HEAD(&ibm->all_drivers);
+
+ if (ibm->flags.experimental && !experimental)
+ return 0;
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "probing for %s\n", ibm->name);
+
+ if (iibm->init) {
+ ret = iibm->init(iibm);
+ if (ret > 0)
+ return 0; /* probe failed */
+ if (ret)
+ return ret;
+
+ ibm->flags.init_called = 1;
+ }
+
+ if (ibm->acpi) {
+ if (ibm->acpi->hid) {
+ ret = register_tpacpi_subdriver(ibm);
+ if (ret)
+ goto err_out;
+ }
+
+ if (ibm->acpi->notify) {
+ ret = setup_acpi_notify(ibm);
+ if (ret == -ENODEV) {
+ printk(IBM_NOTICE "disabling subdriver %s\n",
+ ibm->name);
+ ret = 0;
+ goto err_out;
+ }
+ if (ret < 0)
+ goto err_out;
+ }
+ }
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "%s installed\n", ibm->name);
+
+ if (ibm->read) {
+ entry = create_proc_entry(ibm->name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ proc_dir);
+ if (!entry) {
+ printk(IBM_ERR "unable to create proc entry %s\n",
+ ibm->name);
+ ret = -ENODEV;
+ goto err_out;
+ }
+ entry->owner = THIS_MODULE;
+ entry->data = ibm;
+ entry->read_proc = &dispatch_procfs_read;
+ if (ibm->write)
+ entry->write_proc = &dispatch_procfs_write;
+ ibm->flags.proc_created = 1;
+ }
+
+ list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers);
+
+ return 0;
+
+err_out:
+ dbg_printk(TPACPI_DBG_INIT,
+ "%s: at error exit path with result %d\n",
+ ibm->name, ret);
+
+ ibm_exit(ibm);
+ return (ret < 0)? ret : 0;
+}
+
+static void ibm_exit(struct ibm_struct *ibm)
+{
+ dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
+
+ list_del_init(&ibm->all_drivers);
+
+ if (ibm->flags.acpi_notify_installed) {
+ dbg_printk(TPACPI_DBG_EXIT,
+ "%s: acpi_remove_notify_handler\n", ibm->name);
+ BUG_ON(!ibm->acpi);
+ acpi_remove_notify_handler(*ibm->acpi->handle,
+ ibm->acpi->type,
+ dispatch_acpi_notify);
+ ibm->flags.acpi_notify_installed = 0;
+ ibm->flags.acpi_notify_installed = 0;
+ }
+
+ if (ibm->flags.proc_created) {
+ dbg_printk(TPACPI_DBG_EXIT,
+ "%s: remove_proc_entry\n", ibm->name);
+ remove_proc_entry(ibm->name, proc_dir);
+ ibm->flags.proc_created = 0;
+ }
+
+ if (ibm->flags.acpi_driver_registered) {
+ dbg_printk(TPACPI_DBG_EXIT,
+ "%s: acpi_bus_unregister_driver\n", ibm->name);
+ BUG_ON(!ibm->acpi);
+ acpi_bus_unregister_driver(ibm->acpi->driver);
+ kfree(ibm->acpi->driver);
+ ibm->acpi->driver = NULL;
+ ibm->flags.acpi_driver_registered = 0;
+ }
+
+ if (ibm->flags.init_called && ibm->exit) {
+ ibm->exit();
+ ibm->flags.init_called = 0;
+ }
+
+ dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
+}
+
+/* Probing */
+
+static char *ibm_thinkpad_ec_found = NULL;
+
+static char* __init check_dmi_for_ec(void)
+{
+ struct dmi_device *dev = NULL;
+ char ec_fw_string[18];
+
+ /*
+ * ThinkPad T23 or newer, A31 or newer, R50e or newer,
+ * X32 or newer, all Z series; Some models must have an
+ * up-to-date BIOS or they will not be detected.
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ */
+ while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+ if (sscanf(dev->name,
+ "IBM ThinkPad Embedded Controller -[%17c",
+ ec_fw_string) == 1) {
+ ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
+ ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
+ return kstrdup(ec_fw_string, GFP_KERNEL);
+ }
+ }
+ return NULL;
+}
+
+static int __init probe_for_thinkpad(void)
+{
+ int is_thinkpad;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ /*
+ * Non-ancient models have better DMI tagging, but very old models
+ * don't.
+ */
+ is_thinkpad = dmi_name_in_vendors("ThinkPad");
+
+ /* ec is required because many other handles are relative to it */
+ IBM_ACPIHANDLE_INIT(ec);
+ if (!ec_handle) {
+ if (is_thinkpad)
+ printk(IBM_ERR
+ "Not yet supported ThinkPad detected!\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Risks a regression on very old machines, but reduces potential
+ * false positives a damn great deal
+ */
+ if (!is_thinkpad)
+ is_thinkpad = dmi_name_in_vendors("IBM");
+
+ if (!is_thinkpad && !force_load)
+ return -ENODEV;
+
+ return 0;
+}
+
+
+/* Module init, exit, parameters */
+
+static struct ibm_init_struct ibms_init[] __initdata = {
+ {
+ .init = thinkpad_acpi_driver_init,
+ .data = &thinkpad_acpi_driver_data,
+ },
+ {
+ .init = hotkey_init,
+ .data = &hotkey_driver_data,
+ },
+ {
+ .init = bluetooth_init,
+ .data = &bluetooth_driver_data,
+ },
+ {
+ .init = wan_init,
+ .data = &wan_driver_data,
+ },
+ {
+ .init = video_init,
+ .data = &video_driver_data,
+ },
+ {
+ .init = light_init,
+ .data = &light_driver_data,
+ },
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+ {
+ .init = dock_init,
+ .data = &dock_driver_data[0],
+ },
+ {
+ .init = dock_init2,
+ .data = &dock_driver_data[1],
+ },
+#endif
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+ {
+ .init = bay_init,
+ .data = &bay_driver_data,
+ },
+#endif
+ {
+ .init = cmos_init,
+ .data = &cmos_driver_data,
+ },
+ {
+ .init = led_init,
+ .data = &led_driver_data,
+ },
+ {
+ .init = beep_init,
+ .data = &beep_driver_data,
+ },
+ {
+ .init = thermal_init,
+ .data = &thermal_driver_data,
+ },
+ {
+ .data = &ecdump_driver_data,
+ },
+ {
+ .init = brightness_init,
+ .data = &brightness_driver_data,
+ },
+ {
+ .data = &volume_driver_data,
+ },
+ {
+ .init = fan_init,
+ .data = &fan_driver_data,
+ },
+};
+
+static int __init set_ibm_param(const char *val, struct kernel_param *kp)
+{
+ unsigned int i;
+ struct ibm_struct *ibm;
+
+ for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
+ ibm = ibms_init[i].data;
+ BUG_ON(ibm == NULL);
+
+ if (strcmp(ibm->name, kp->name) == 0 && ibm->write) {
+ if (strlen(val) > sizeof(ibms_init[i].param) - 2)
+ return -ENOSPC;
+ strcpy(ibms_init[i].param, val);
+ strcat(ibms_init[i].param, ",");
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int experimental;
+module_param(experimental, int, 0);
+
+static u32 dbg_level;
+module_param_named(debug, dbg_level, uint, 0);
+
+static int force_load;
+module_param(force_load, int, 0);
+
+static int fan_control_allowed;
+module_param_named(fan_control, fan_control_allowed, int, 0);
+
+#define IBM_PARAM(feature) \
+ module_param_call(feature, set_ibm_param, NULL, NULL, 0)
+
+IBM_PARAM(hotkey);
+IBM_PARAM(bluetooth);
+IBM_PARAM(video);
+IBM_PARAM(light);
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+IBM_PARAM(dock);
+#endif
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+IBM_PARAM(bay);
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+IBM_PARAM(cmos);
+IBM_PARAM(led);
+IBM_PARAM(beep);
+IBM_PARAM(ecdump);
+IBM_PARAM(brightness);
+IBM_PARAM(volume);
+IBM_PARAM(fan);
+
+static int __init thinkpad_acpi_module_init(void)
+{
+ int ret, i;
+
+ /* Driver-level probe */
+ ret = probe_for_thinkpad();
+ if (ret)
+ return ret;
+
+ /* Driver initialization */
+ ibm_thinkpad_ec_found = check_dmi_for_ec();
+ IBM_ACPIHANDLE_INIT(ecrd);
+ IBM_ACPIHANDLE_INIT(ecwr);
+
+ proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir);
+ if (!proc_dir) {
+ printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR);
+ thinkpad_acpi_module_exit();
+ return -ENODEV;
+ }
+ proc_dir->owner = THIS_MODULE;
+
+ ret = platform_driver_register(&tpacpi_pdriver);
+ if (ret) {
+ printk(IBM_ERR "unable to register platform driver\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
+ if (ret) {
+ printk(IBM_ERR "unable to create sysfs driver attributes\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+
+
+ /* Device initialization */
+ tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1,
+ NULL, 0);
+ if (IS_ERR(tpacpi_pdev)) {
+ ret = PTR_ERR(tpacpi_pdev);
+ tpacpi_pdev = NULL;
+ printk(IBM_ERR "unable to register platform device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev);
+ if (IS_ERR(tpacpi_hwmon)) {
+ ret = PTR_ERR(tpacpi_hwmon);
+ tpacpi_hwmon = NULL;
+ printk(IBM_ERR "unable to register hwmon device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
+ ret = ibm_init(&ibms_init[i]);
+ if (ret >= 0 && *ibms_init[i].param)
+ ret = ibms_init[i].data->write(ibms_init[i].param);
+ if (ret < 0) {
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void thinkpad_acpi_module_exit(void)
+{
+ struct ibm_struct *ibm, *itmp;
+
+ list_for_each_entry_safe_reverse(ibm, itmp,
+ &tpacpi_all_drivers,
+ all_drivers) {
+ ibm_exit(ibm);
+ }
+
+ dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
+
+ if (tpacpi_hwmon)
+ hwmon_device_unregister(tpacpi_hwmon);
+
+ if (tpacpi_pdev)
+ platform_device_unregister(tpacpi_pdev);
+
+ tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+ platform_driver_unregister(&tpacpi_pdriver);
+
+ if (proc_dir)
+ remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
+
+ kfree(ibm_thinkpad_ec_found);
+}
+
+module_init(thinkpad_acpi_module_init);
+module_exit(thinkpad_acpi_module_exit);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
new file mode 100644
index 000000000000..440145a02617
--- /dev/null
+++ b/drivers/misc/thinkpad_acpi.h
@@ -0,0 +1,572 @@
+/*
+ * thinkpad_acpi.h - ThinkPad ACPI Extras
+ *
+ *
+ * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __THINKPAD_ACPI_H__
+#define __THINKPAD_ACPI_H__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+#include <linux/proc_fs.h>
+#include <linux/sysfs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/uaccess.h>
+
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+
+#include <acpi/acpi_drivers.h>
+#include <acpi/acnamesp.h>
+
+
+/****************************************************************************
+ * Main driver
+ */
+
+#define IBM_NAME "thinkpad"
+#define IBM_DESC "ThinkPad ACPI Extras"
+#define IBM_FILE "thinkpad_acpi"
+#define IBM_URL "http://ibm-acpi.sf.net/"
+#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
+
+#define IBM_PROC_DIR "ibm"
+#define IBM_ACPI_EVENT_PREFIX "ibm"
+#define IBM_DRVR_NAME IBM_FILE
+
+#define IBM_LOG IBM_FILE ": "
+#define IBM_ERR KERN_ERR IBM_LOG
+#define IBM_NOTICE KERN_NOTICE IBM_LOG
+#define IBM_INFO KERN_INFO IBM_LOG
+#define IBM_DEBUG KERN_DEBUG IBM_LOG
+
+#define IBM_MAX_ACPI_ARGS 3
+
+/* ThinkPad CMOS commands */
+#define TP_CMOS_VOLUME_DOWN 0
+#define TP_CMOS_VOLUME_UP 1
+#define TP_CMOS_VOLUME_MUTE 2
+#define TP_CMOS_BRIGHTNESS_UP 4
+#define TP_CMOS_BRIGHTNESS_DOWN 5
+
+#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
+#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
+#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
+
+/* Debugging */
+#define TPACPI_DBG_ALL 0xffff
+#define TPACPI_DBG_ALL 0xffff
+#define TPACPI_DBG_INIT 0x0001
+#define TPACPI_DBG_EXIT 0x0002
+#define dbg_printk(a_dbg_level, format, arg...) \
+ do { if (dbg_level & a_dbg_level) \
+ printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0)
+#ifdef CONFIG_THINKPAD_ACPI_DEBUG
+#define vdbg_printk(a_dbg_level, format, arg...) \
+ dbg_printk(a_dbg_level, format, ## arg)
+static const char *str_supported(int is_supported);
+#else
+#define vdbg_printk(a_dbg_level, format, arg...)
+#endif
+
+/* ACPI HIDs */
+#define IBM_HKEY_HID "IBM0068"
+#define IBM_PCI_HID "PNP0A03"
+
+/* ACPI helpers */
+static int __must_check acpi_evalf(acpi_handle handle,
+ void *res, char *method, char *fmt, ...);
+static int __must_check acpi_ec_read(int i, u8 * p);
+static int __must_check acpi_ec_write(int i, u8 v);
+static int __must_check _sta(acpi_handle handle);
+
+/* ACPI handles */
+static acpi_handle root_handle; /* root namespace */
+static acpi_handle ec_handle; /* EC */
+static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */
+static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */
+
+static void drv_acpi_handle_init(char *name,
+ acpi_handle *handle, acpi_handle parent,
+ char **paths, int num_paths, char **path);
+#define IBM_ACPIHANDLE_INIT(object) \
+ drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
+ object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
+
+/* ThinkPad ACPI helpers */
+static int issue_thinkpad_cmos_command(int cmos_cmd);
+
+/* procfs support */
+static struct proc_dir_entry *proc_dir;
+
+/* procfs helpers */
+static int dispatch_procfs_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+static int dispatch_procfs_write(struct file *file,
+ const char __user * userbuf,
+ unsigned long count, void *data);
+static char *next_cmd(char **cmds);
+
+/* sysfs support */
+struct attribute_set {
+ unsigned int members, max_members;
+ struct attribute_group group;
+};
+
+static struct attribute_set *create_attr_set(unsigned int max_members,
+ const char* name);
+#define destroy_attr_set(_set) \
+ kfree(_set);
+static int add_to_attr_set(struct attribute_set* s, struct attribute *attr);
+static int add_many_to_attr_set(struct attribute_set* s,
+ struct attribute **attr,
+ unsigned int count);
+#define register_attr_set_with_sysfs(_attr_set, _kobj) \
+ sysfs_create_group(_kobj, &_attr_set->group)
+static void delete_attr_set(struct attribute_set* s, struct kobject *kobj);
+
+static int parse_strtoul(const char *buf, unsigned long max,
+ unsigned long *value);
+
+/* Device model */
+static struct platform_device *tpacpi_pdev;
+static struct class_device *tpacpi_hwmon;
+static struct platform_driver tpacpi_pdriver;
+static int tpacpi_create_driver_attributes(struct device_driver *drv);
+static void tpacpi_remove_driver_attributes(struct device_driver *drv);
+
+/* Module */
+static int experimental;
+static u32 dbg_level;
+static int force_load;
+static char *ibm_thinkpad_ec_found;
+
+static char* check_dmi_for_ec(void);
+static int thinkpad_acpi_module_init(void);
+static void thinkpad_acpi_module_exit(void);
+
+
+/****************************************************************************
+ * Subdrivers
+ */
+
+struct ibm_struct;
+
+struct tp_acpi_drv_struct {
+ char *hid;
+ struct acpi_driver *driver;
+
+ void (*notify) (struct ibm_struct *, u32);
+ acpi_handle *handle;
+ u32 type;
+ struct acpi_device *device;
+};
+
+struct ibm_struct {
+ char *name;
+
+ int (*read) (char *);
+ int (*write) (char *);
+ void (*exit) (void);
+
+ struct list_head all_drivers;
+
+ struct tp_acpi_drv_struct *acpi;
+
+ struct {
+ u8 acpi_driver_registered:1;
+ u8 acpi_notify_installed:1;
+ u8 proc_created:1;
+ u8 init_called:1;
+ u8 experimental:1;
+ } flags;
+};
+
+struct ibm_init_struct {
+ char param[32];
+
+ int (*init) (struct ibm_init_struct *);
+ struct ibm_struct *data;
+};
+
+static struct {
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+ u16 bay_status:1;
+ u16 bay_eject:1;
+ u16 bay_status2:1;
+ u16 bay_eject2:1;
+#endif
+ u16 bluetooth:1;
+ u16 hotkey:1;
+ u16 hotkey_mask:1;
+ u16 light:1;
+ u16 light_status:1;
+ u16 wan:1;
+ u16 fan_ctrl_status_undef:1;
+} tp_features;
+
+static struct list_head tpacpi_all_drivers;
+
+static struct ibm_init_struct ibms_init[];
+static int set_ibm_param(const char *val, struct kernel_param *kp);
+static int ibm_init(struct ibm_init_struct *iibm);
+static void ibm_exit(struct ibm_struct *ibm);
+
+
+/*
+ * procfs master subdriver
+ */
+static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm);
+static int thinkpad_acpi_driver_read(char *p);
+
+
+/*
+ * Bay subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+static acpi_handle bay_handle, bay_ej_handle;
+static acpi_handle bay2_handle, bay2_ej_handle;
+
+static int bay_init(struct ibm_init_struct *iibm);
+static void bay_notify(struct ibm_struct *ibm, u32 event);
+static int bay_read(char *p);
+static int bay_write(char *buf);
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+
+
+/*
+ * Beep subdriver
+ */
+
+static acpi_handle beep_handle;
+
+static int beep_read(char *p);
+static int beep_write(char *buf);
+
+
+/*
+ * Bluetooth subdriver
+ */
+
+#define TPACPI_BLUETH_SYSFS_GROUP "bluetooth"
+
+enum {
+ /* ACPI GBDC/SBDC bits */
+ TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
+ TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
+ TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
+};
+
+static int bluetooth_init(struct ibm_init_struct *iibm);
+static int bluetooth_get_radiosw(void);
+static int bluetooth_set_radiosw(int radio_on);
+static int bluetooth_read(char *p);
+static int bluetooth_write(char *buf);
+
+
+/*
+ * Brightness (backlight) subdriver
+ */
+
+#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
+
+static struct backlight_device *ibm_backlight_device;
+static int brightness_offset = 0x31;
+
+static int brightness_init(struct ibm_init_struct *iibm);
+static void brightness_exit(void);
+static int brightness_get(struct backlight_device *bd);
+static int brightness_set(int value);
+static int brightness_update_status(struct backlight_device *bd);
+static int brightness_read(char *p);
+static int brightness_write(char *buf);
+
+
+/*
+ * CMOS subdriver
+ */
+
+static int cmos_read(char *p);
+static int cmos_write(char *buf);
+
+
+/*
+ * Dock subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+static acpi_handle pci_handle;
+static acpi_handle dock_handle;
+
+static void dock_notify(struct ibm_struct *ibm, u32 event);
+static int dock_read(char *p);
+static int dock_write(char *buf);
+#endif /* CONFIG_THINKPAD_ACPI_DOCK */
+
+
+/*
+ * EC dump subdriver
+ */
+
+static int ecdump_read(char *p) ;
+static int ecdump_write(char *buf);
+
+
+/*
+ * Fan subdriver
+ */
+
+enum { /* Fan control constants */
+ fan_status_offset = 0x2f, /* EC register 0x2f */
+ fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
+ * 0x84 must be read before 0x85 */
+
+ TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
+ TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
+
+ TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
+};
+
+enum fan_status_access_mode {
+ TPACPI_FAN_NONE = 0, /* No fan status or control */
+ TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
+ TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
+};
+
+enum fan_control_access_mode {
+ TPACPI_FAN_WR_NONE = 0, /* No fan control */
+ TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
+ TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
+ TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
+};
+
+enum fan_control_commands {
+ TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
+ TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
+ TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
+ * and also watchdog cmd */
+};
+
+static int fan_control_allowed;
+
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
+static u8 fan_control_initial_status;
+static u8 fan_control_desired_level;
+static int fan_watchdog_maxinterval;
+
+static struct mutex fan_mutex;
+
+static acpi_handle fans_handle, gfan_handle, sfan_handle;
+
+static int fan_init(struct ibm_init_struct *iibm);
+static void fan_exit(void);
+static int fan_get_status(u8 *status);
+static int fan_get_status_safe(u8 *status);
+static int fan_get_speed(unsigned int *speed);
+static void fan_update_desired_level(u8 status);
+static void fan_watchdog_fire(struct work_struct *ignored);
+static void fan_watchdog_reset(void);
+static int fan_set_level(int level);
+static int fan_set_level_safe(int level);
+static int fan_set_enable(void);
+static int fan_set_disable(void);
+static int fan_set_speed(int speed);
+static int fan_read(char *p);
+static int fan_write(char *buf);
+static int fan_write_cmd_level(const char *cmd, int *rc);
+static int fan_write_cmd_enable(const char *cmd, int *rc);
+static int fan_write_cmd_disable(const char *cmd, int *rc);
+static int fan_write_cmd_speed(const char *cmd, int *rc);
+static int fan_write_cmd_watchdog(const char *cmd, int *rc);
+
+
+/*
+ * Hotkey subdriver
+ */
+
+#define TPACPI_HOTKEY_SYSFS_GROUP "hotkey"
+
+static int hotkey_orig_status;
+static int hotkey_orig_mask;
+
+static struct mutex hotkey_mutex;
+
+static int hotkey_init(struct ibm_init_struct *iibm);
+static void hotkey_exit(void);
+static int hotkey_get(int *status, int *mask);
+static int hotkey_set(int status, int mask);
+static void hotkey_notify(struct ibm_struct *ibm, u32 event);
+static int hotkey_read(char *p);
+static int hotkey_write(char *buf);
+
+
+/*
+ * LED subdriver
+ */
+
+enum led_access_mode {
+ TPACPI_LED_NONE = 0,
+ TPACPI_LED_570, /* 570 */
+ TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+ TPACPI_LED_NEW, /* all others */
+};
+
+enum { /* For TPACPI_LED_OLD */
+ TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */
+ TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */
+ TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
+};
+
+static enum led_access_mode led_supported;
+static acpi_handle led_handle;
+
+static int led_init(struct ibm_init_struct *iibm);
+static int led_read(char *p);
+static int led_write(char *buf);
+
+/*
+ * Light (thinklight) subdriver
+ */
+
+static acpi_handle lght_handle, ledb_handle;
+
+static int light_init(struct ibm_init_struct *iibm);
+static int light_read(char *p);
+static int light_write(char *buf);
+
+
+/*
+ * Thermal subdriver
+ */
+
+enum thermal_access_mode {
+ TPACPI_THERMAL_NONE = 0, /* No thermal support */
+ TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
+ TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
+ TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
+ TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
+};
+
+enum { /* TPACPI_THERMAL_TPEC_* */
+ TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
+ TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
+ TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
+};
+
+#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
+struct ibm_thermal_sensors_struct {
+ s32 temp[TPACPI_MAX_THERMAL_SENSORS];
+};
+
+static enum thermal_access_mode thermal_read_mode;
+
+static int thermal_init(struct ibm_init_struct *iibm);
+static int thermal_get_sensor(int idx, s32 *value);
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s);
+static int thermal_read(char *p);
+
+
+/*
+ * Video subdriver
+ */
+
+enum video_access_mode {
+ TPACPI_VIDEO_NONE = 0,
+ TPACPI_VIDEO_570, /* 570 */
+ TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */
+ TPACPI_VIDEO_NEW, /* all others */
+};
+
+enum { /* video status flags, based on VIDEO_570 */
+ TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */
+ TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */
+ TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */
+};
+
+enum { /* TPACPI_VIDEO_570 constants */
+ TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */
+ TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to
+ * video_status_flags */
+ TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */
+ TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */
+};
+
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
+static acpi_handle vid_handle, vid2_handle;
+
+static int video_init(struct ibm_init_struct *iibm);
+static void video_exit(void);
+static int video_outputsw_get(void);
+static int video_outputsw_set(int status);
+static int video_autosw_get(void);
+static int video_autosw_set(int enable);
+static int video_outputsw_cycle(void);
+static int video_expand_toggle(void);
+static int video_read(char *p);
+static int video_write(char *buf);
+
+
+/*
+ * Volume subdriver
+ */
+
+static int volume_offset = 0x30;
+
+static int volume_read(char *p);
+static int volume_write(char *buf);
+
+
+/*
+ * Wan subdriver
+ */
+
+#define TPACPI_WAN_SYSFS_GROUP "wwan"
+
+enum {
+ /* ACPI GWAN/SWAN bits */
+ TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
+ TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
+ TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
+};
+
+static int wan_init(struct ibm_init_struct *iibm);
+static int wan_get_radiosw(void);
+static int wan_set_radiosw(int radio_on);
+static int wan_read(char *p);
+static int wan_write(char *buf);
+
+
+#endif /* __THINKPAD_ACPI_H */
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index c7511c4d3b68..9588da3a30e7 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -83,7 +83,6 @@ static int max_interrupt_work = 10;
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/pm.h>
-#include <linux/pm_legacy.h>
#include <linux/skbuff.h>
#include <linux/delay.h> /* for udelay() */
#include <linux/spinlock.h>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 32a3003893d8..dcdad217df51 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -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)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 58527322a39d..59c0459a037c 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -18,7 +18,7 @@ gianfar_driver-objs := gianfar.o \
gianfar_sysfs.o
obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
-ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o
+ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o
#
# link order important here
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile
index 382d23f810ab..743ad8b41b5e 100644
--- a/drivers/net/chelsio/Makefile
+++ b/drivers/net/chelsio/Makefile
@@ -4,8 +4,6 @@
obj-$(CONFIG_CHELSIO_T1) += cxgb.o
-cxgb-$(CONFIG_CHELSIO_T1_1G) += ixf1010.o mac.o mv88e1xxx.o vsc7326.o vsc8244.o
+cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o
cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \
mv88x201x.o my3126.o $(cxgb-y)
-
-
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 787f2f2820fe..8ba702c8b560 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -322,9 +322,9 @@ struct board_info {
unsigned char mdio_mdiinv;
unsigned char mdio_mdc;
unsigned char mdio_phybaseaddr;
- struct gmac *gmac;
- struct gphy *gphy;
- struct mdio_ops *mdio_ops;
+ const struct gmac *gmac;
+ const struct gphy *gphy;
+ const struct mdio_ops *mdio_ops;
const char *desc;
};
diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h
index cf9143499882..79d855e267e0 100644
--- a/drivers/net/chelsio/cphy.h
+++ b/drivers/net/chelsio/cphy.h
@@ -100,7 +100,7 @@ struct cphy {
u32 elmer_gpo;
- struct cphy_ops *ops; /* PHY operations */
+ const struct cphy_ops *ops; /* PHY operations */
int (*mdio_read)(adapter_t *adapter, int phy_addr, int mmd_addr,
int reg_addr, unsigned int *val);
int (*mdio_write)(adapter_t *adapter, int phy_addr, int mmd_addr,
@@ -136,7 +136,7 @@ static inline int simple_mdio_write(struct cphy *cphy, int reg,
/* Convenience initializer */
static inline void cphy_init(struct cphy *phy, adapter_t *adapter,
int phy_addr, struct cphy_ops *phy_ops,
- struct mdio_ops *mdio_ops)
+ const struct mdio_ops *mdio_ops)
{
phy->adapter = adapter;
phy->addr = phy_addr;
@@ -151,7 +151,7 @@ static inline void cphy_init(struct cphy *phy, adapter_t *adapter,
struct gphy {
/* Construct a PHY instance with the given PHY address */
struct cphy *(*create)(adapter_t *adapter, int phy_addr,
- struct mdio_ops *mdio_ops);
+ const struct mdio_ops *mdio_ops);
/*
* Reset the PHY chip. This resets the whole PHY chip, not individual
@@ -160,11 +160,9 @@ struct gphy {
int (*reset)(adapter_t *adapter);
};
-extern struct gphy t1_my3126_ops;
-extern struct gphy t1_mv88e1xxx_ops;
-extern struct gphy t1_vsc8244_ops;
-extern struct gphy t1_xpak_ops;
-extern struct gphy t1_mv88x201x_ops;
-extern struct gphy t1_dummy_phy_ops;
+extern const struct gphy t1_my3126_ops;
+extern const struct gphy t1_mv88e1xxx_ops;
+extern const struct gphy t1_vsc8244_ops;
+extern const struct gphy t1_mv88x201x_ops;
#endif /* _CXGB_CPHY_H_ */
diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h
index 006a2eb2d362..d42337457cf7 100644
--- a/drivers/net/chelsio/gmac.h
+++ b/drivers/net/chelsio/gmac.h
@@ -126,7 +126,7 @@ typedef struct _cmac_instance cmac_instance;
struct cmac {
struct cmac_statistics stats;
adapter_t *adapter;
- struct cmac_ops *ops;
+ const struct cmac_ops *ops;
cmac_instance *instance;
};
@@ -136,11 +136,7 @@ struct gmac {
int (*reset)(adapter_t *);
};
-extern struct gmac t1_pm3393_ops;
-extern struct gmac t1_chelsio_mac_ops;
-extern struct gmac t1_vsc7321_ops;
-extern struct gmac t1_vsc7326_ops;
-extern struct gmac t1_ixf1010_ops;
-extern struct gmac t1_dummy_mac_ops;
+extern const struct gmac t1_pm3393_ops;
+extern const struct gmac t1_vsc7326_ops;
#endif /* _CXGB_GMAC_H_ */
diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c
deleted file mode 100644
index 10b2a9a19006..000000000000
--- a/drivers/net/chelsio/ixf1010.c
+++ /dev/null
@@ -1,505 +0,0 @@
-/* $Date: 2005/11/12 02:13:49 $ $RCSfile: ixf1010.c,v $ $Revision: 1.36 $ */
-#include "gmac.h"
-#include "elmer0.h"
-
-/* Update fast changing statistics every 15 seconds */
-#define STATS_TICK_SECS 15
-/* 30 minutes for full statistics update */
-#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS)
-
-/*
- * The IXF1010 can handle frames up to 16383 bytes but it's optimized for
- * frames up to 9831 (0x2667) bytes, so we limit jumbo frame size to this.
- * This length includes ethernet header and FCS.
- */
-#define MAX_FRAME_SIZE 0x2667
-
-/* MAC registers */
-enum {
- /* Per-port registers */
- REG_MACADDR_LOW = 0,
- REG_MACADDR_HIGH = 0x4,
- REG_FDFC_TYPE = 0xC,
- REG_FC_TX_TIMER_VALUE = 0x1c,
- REG_IPG_RX_TIME1 = 0x28,
- REG_IPG_RX_TIME2 = 0x2c,
- REG_IPG_TX_TIME = 0x30,
- REG_PAUSE_THRES = 0x38,
- REG_MAX_FRAME_SIZE = 0x3c,
- REG_RGMII_SPEED = 0x40,
- REG_FC_ENABLE = 0x48,
- REG_DISCARD_CTRL_FRAMES = 0x54,
- REG_DIVERSE_CONFIG = 0x60,
- REG_RX_FILTER = 0x64,
- REG_MC_ADDR_LOW = 0x68,
- REG_MC_ADDR_HIGH = 0x6c,
-
- REG_RX_OCTETS_OK = 0x80,
- REG_RX_OCTETS_BAD = 0x84,
- REG_RX_UC_PKTS = 0x88,
- REG_RX_MC_PKTS = 0x8c,
- REG_RX_BC_PKTS = 0x90,
- REG_RX_FCS_ERR = 0xb0,
- REG_RX_TAGGED = 0xb4,
- REG_RX_DATA_ERR = 0xb8,
- REG_RX_ALIGN_ERR = 0xbc,
- REG_RX_LONG_ERR = 0xc0,
- REG_RX_JABBER_ERR = 0xc4,
- REG_RX_PAUSE_FRAMES = 0xc8,
- REG_RX_UNKNOWN_CTRL_FRAMES = 0xcc,
- REG_RX_VERY_LONG_ERR = 0xd0,
- REG_RX_RUNT_ERR = 0xd4,
- REG_RX_SHORT_ERR = 0xd8,
- REG_RX_SYMBOL_ERR = 0xe4,
-
- REG_TX_OCTETS_OK = 0x100,
- REG_TX_OCTETS_BAD = 0x104,
- REG_TX_UC_PKTS = 0x108,
- REG_TX_MC_PKTS = 0x10c,
- REG_TX_BC_PKTS = 0x110,
- REG_TX_EXCESSIVE_LEN_DROP = 0x14c,
- REG_TX_UNDERRUN = 0x150,
- REG_TX_TAGGED = 0x154,
- REG_TX_PAUSE_FRAMES = 0x15C,
-
- /* Global registers */
- REG_PORT_ENABLE = 0x1400,
-
- REG_JTAG_ID = 0x1430,
-
- RX_FIFO_HIGH_WATERMARK_BASE = 0x1600,
- RX_FIFO_LOW_WATERMARK_BASE = 0x1628,
- RX_FIFO_FRAMES_REMOVED_BASE = 0x1650,
-
- REG_RX_ERR_DROP = 0x167c,
- REG_RX_FIFO_OVERFLOW_EVENT = 0x1680,
-
- TX_FIFO_HIGH_WATERMARK_BASE = 0x1800,
- TX_FIFO_LOW_WATERMARK_BASE = 0x1828,
- TX_FIFO_XFER_THRES_BASE = 0x1850,
-
- REG_TX_FIFO_OVERFLOW_EVENT = 0x1878,
- REG_TX_FIFO_OOS_EVENT = 0x1884,
-
- TX_FIFO_FRAMES_REMOVED_BASE = 0x1888,
-
- REG_SPI_RX_BURST = 0x1c00,
- REG_SPI_RX_TRAINING = 0x1c04,
- REG_SPI_RX_CALENDAR = 0x1c08,
- REG_SPI_TX_SYNC = 0x1c0c
-};
-
-enum { /* RMON registers */
- REG_RxOctetsTotalOK = 0x80,
- REG_RxOctetsBad = 0x84,
- REG_RxUCPkts = 0x88,
- REG_RxMCPkts = 0x8c,
- REG_RxBCPkts = 0x90,
- REG_RxJumboPkts = 0xac,
- REG_RxFCSErrors = 0xb0,
- REG_RxDataErrors = 0xb8,
- REG_RxAlignErrors = 0xbc,
- REG_RxLongErrors = 0xc0,
- REG_RxJabberErrors = 0xc4,
- REG_RxPauseMacControlCounter = 0xc8,
- REG_RxVeryLongErrors = 0xd0,
- REG_RxRuntErrors = 0xd4,
- REG_RxShortErrors = 0xd8,
- REG_RxSequenceErrors = 0xe0,
- REG_RxSymbolErrors = 0xe4,
-
- REG_TxOctetsTotalOK = 0x100,
- REG_TxOctetsBad = 0x104,
- REG_TxUCPkts = 0x108,
- REG_TxMCPkts = 0x10c,
- REG_TxBCPkts = 0x110,
- REG_TxJumboPkts = 0x12C,
- REG_TxTotalCollisions = 0x134,
- REG_TxExcessiveLengthDrop = 0x14c,
- REG_TxUnderrun = 0x150,
- REG_TxCRCErrors = 0x158,
- REG_TxPauseFrames = 0x15c
-};
-
-enum {
- DIVERSE_CONFIG_PAD_ENABLE = 0x80,
- DIVERSE_CONFIG_CRC_ADD = 0x40
-};
-
-#define MACREG_BASE 0
-#define MACREG(mac, mac_reg) ((mac)->instance->mac_base + (mac_reg))
-
-struct _cmac_instance {
- u32 mac_base;
- u32 index;
- u32 version;
- u32 ticks;
-};
-
-static void disable_port(struct cmac *mac)
-{
- u32 val;
-
- t1_tpi_read(mac->adapter, REG_PORT_ENABLE, &val);
- val &= ~(1 << mac->instance->index);
- t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val);
-}
-
-/*
- * Read the current values of the RMON counters and add them to the cumulative
- * port statistics. The HW RMON counters are cleared by this operation.
- */
-static void port_stats_update(struct cmac *mac)
-{
- static struct {
- unsigned int reg;
- unsigned int offset;
- } hw_stats[] = {
-
-#define HW_STAT(name, stat_name) \
- { REG_##name, \
- (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
-
- /* Rx stats */
- HW_STAT(RxOctetsTotalOK, RxOctetsOK),
- HW_STAT(RxOctetsBad, RxOctetsBad),
- HW_STAT(RxUCPkts, RxUnicastFramesOK),
- HW_STAT(RxMCPkts, RxMulticastFramesOK),
- HW_STAT(RxBCPkts, RxBroadcastFramesOK),
- HW_STAT(RxJumboPkts, RxJumboFramesOK),
- HW_STAT(RxFCSErrors, RxFCSErrors),
- HW_STAT(RxAlignErrors, RxAlignErrors),
- HW_STAT(RxLongErrors, RxFrameTooLongErrors),
- HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors),
- HW_STAT(RxPauseMacControlCounter, RxPauseFrames),
- HW_STAT(RxDataErrors, RxDataErrors),
- HW_STAT(RxJabberErrors, RxJabberErrors),
- HW_STAT(RxRuntErrors, RxRuntErrors),
- HW_STAT(RxShortErrors, RxRuntErrors),
- HW_STAT(RxSequenceErrors, RxSequenceErrors),
- HW_STAT(RxSymbolErrors, RxSymbolErrors),
-
- /* Tx stats (skip collision stats as we are full-duplex only) */
- HW_STAT(TxOctetsTotalOK, TxOctetsOK),
- HW_STAT(TxOctetsBad, TxOctetsBad),
- HW_STAT(TxUCPkts, TxUnicastFramesOK),
- HW_STAT(TxMCPkts, TxMulticastFramesOK),
- HW_STAT(TxBCPkts, TxBroadcastFramesOK),
- HW_STAT(TxJumboPkts, TxJumboFramesOK),
- HW_STAT(TxPauseFrames, TxPauseFrames),
- HW_STAT(TxExcessiveLengthDrop, TxLengthErrors),
- HW_STAT(TxUnderrun, TxUnderrun),
- HW_STAT(TxCRCErrors, TxFCSErrors)
- }, *p = hw_stats;
- u64 *stats = (u64 *) &mac->stats;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
- u32 val;
-
- t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val);
- stats[p->offset] += val;
- }
-}
-
-/* No-op interrupt operation as this MAC does not support interrupts */
-static int mac_intr_op(struct cmac *mac)
-{
- return 0;
-}
-
-/* Expect MAC address to be in network byte order. */
-static int mac_set_address(struct cmac *mac, u8 addr[6])
-{
- u32 addr_lo, addr_hi;
-
- addr_lo = addr[2];
- addr_lo = (addr_lo << 8) | addr[3];
- addr_lo = (addr_lo << 8) | addr[4];
- addr_lo = (addr_lo << 8) | addr[5];
-
- addr_hi = addr[0];
- addr_hi = (addr_hi << 8) | addr[1];
-
- t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_LOW), addr_lo);
- t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), addr_hi);
- return 0;
-}
-
-static int mac_get_address(struct cmac *mac, u8 addr[6])
-{
- u32 addr_lo, addr_hi;
-
- t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_LOW), &addr_lo);
- t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), &addr_hi);
-
- addr[0] = (u8) (addr_hi >> 8);
- addr[1] = (u8) addr_hi;
- addr[2] = (u8) (addr_lo >> 24);
- addr[3] = (u8) (addr_lo >> 16);
- addr[4] = (u8) (addr_lo >> 8);
- addr[5] = (u8) addr_lo;
- return 0;
-}
-
-/* This is intended to reset a port, not the whole MAC */
-static int mac_reset(struct cmac *mac)
-{
- return 0;
-}
-
-static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
-{
- u32 val, new_mode;
- adapter_t *adapter = mac->adapter;
- u32 addr_lo, addr_hi;
- u8 *addr;
-
- t1_tpi_read(adapter, MACREG(mac, REG_RX_FILTER), &val);
- new_mode = val & ~7;
- if (!t1_rx_mode_promisc(rm) && mac->instance->version > 0)
- new_mode |= 1; /* only set if version > 0 due to erratum */
- if (!t1_rx_mode_promisc(rm) && !t1_rx_mode_allmulti(rm)
- && t1_rx_mode_mc_cnt(rm) <= 1)
- new_mode |= 2;
- if (new_mode != val)
- t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), new_mode);
- switch (t1_rx_mode_mc_cnt(rm)) {
- case 0:
- t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), 0);
- t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), 0);
- break;
- case 1:
- addr = t1_get_next_mcaddr(rm);
- addr_lo = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |
- addr[5];
- addr_hi = (addr[0] << 8) | addr[1];
- t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), addr_lo);
- t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), addr_hi);
- break;
- default:
- break;
- }
- return 0;
-}
-
-static int mac_set_mtu(struct cmac *mac, int mtu)
-{
- /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */
- if (mtu > (MAX_FRAME_SIZE - 14 - 4))
- return -EINVAL;
- t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE),
- mtu + 14 + 4);
- return 0;
-}
-
-static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
- int fc)
-{
- u32 val;
-
- if (speed >= 0 && speed != SPEED_100 && speed != SPEED_1000)
- return -1;
- if (duplex >= 0 && duplex != DUPLEX_FULL)
- return -1;
-
- if (speed >= 0) {
- val = speed == SPEED_100 ? 1 : 2;
- t1_tpi_write(mac->adapter, MACREG(mac, REG_RGMII_SPEED), val);
- }
-
- t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val);
- val &= ~3;
- if (fc & PAUSE_RX)
- val |= 1;
- if (fc & PAUSE_TX)
- val |= 2;
- t1_tpi_write(mac->adapter, MACREG(mac, REG_FC_ENABLE), val);
- return 0;
-}
-
-static int mac_get_speed_duplex_fc(struct cmac *mac, int *speed, int *duplex,
- int *fc)
-{
- u32 val;
-
- if (duplex)
- *duplex = DUPLEX_FULL;
- if (speed) {
- t1_tpi_read(mac->adapter, MACREG(mac, REG_RGMII_SPEED),
- &val);
- *speed = (val & 2) ? SPEED_1000 : SPEED_100;
- }
- if (fc) {
- t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val);
- *fc = 0;
- if (val & 1)
- *fc |= PAUSE_RX;
- if (val & 2)
- *fc |= PAUSE_TX;
- }
- return 0;
-}
-
-static void enable_port(struct cmac *mac)
-{
- u32 val;
- u32 index = mac->instance->index;
- adapter_t *adapter = mac->adapter;
-
- t1_tpi_read(adapter, MACREG(mac, REG_DIVERSE_CONFIG), &val);
- val |= DIVERSE_CONFIG_CRC_ADD | DIVERSE_CONFIG_PAD_ENABLE;
- t1_tpi_write(adapter, MACREG(mac, REG_DIVERSE_CONFIG), val);
- if (mac->instance->version > 0)
- t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 3);
- else /* Don't enable unicast address filtering due to IXF1010 bug */
- t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 2);
-
- t1_tpi_read(adapter, REG_RX_ERR_DROP, &val);
- val |= (1 << index);
- t1_tpi_write(adapter, REG_RX_ERR_DROP, val);
-
- /*
- * Clear the port RMON registers by adding their current values to the
- * cumulatice port stats and then clearing the stats. Really.
- */
- port_stats_update(mac);
- memset(&mac->stats, 0, sizeof(struct cmac_statistics));
- mac->instance->ticks = 0;
-
- t1_tpi_read(adapter, REG_PORT_ENABLE, &val);
- val |= (1 << index);
- t1_tpi_write(adapter, REG_PORT_ENABLE, val);
-
- index <<= 2;
- if (is_T2(adapter)) {
- /* T204: set the Fifo water level & threshold */
- t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740);
- t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730);
- t1_tpi_write(adapter, TX_FIFO_HIGH_WATERMARK_BASE + index, 0x600);
- t1_tpi_write(adapter, TX_FIFO_LOW_WATERMARK_BASE + index, 0x1d0);
- t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x1100);
- } else {
- /*
- * Set the TX Fifo Threshold to 0x400 instead of 0x100 to work around
- * Underrun problem. Intel has blessed this solution.
- */
- t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x400);
- }
-}
-
-/* IXF1010 ports do not have separate enables for TX and RX */
-static int mac_enable(struct cmac *mac, int which)
-{
- if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX))
- enable_port(mac);
- return 0;
-}
-
-static int mac_disable(struct cmac *mac, int which)
-{
- if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX))
- disable_port(mac);
- return 0;
-}
-
-#define RMON_UPDATE(mac, name, stat_name) \
- t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
- (mac)->stats.stat_name += val;
-
-/*
- * This function is called periodically to accumulate the current values of the
- * RMON counters into the port statistics. Since the counters are only 32 bits
- * some of them can overflow in less than a minute at GigE speeds, so this
- * function should be called every 30 seconds or so.
- *
- * To cut down on reading costs we update only the octet counters at each tick
- * and do a full update at major ticks, which can be every 30 minutes or more.
- */
-static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
- int flag)
-{
- if (flag == MAC_STATS_UPDATE_FULL ||
- MAJOR_UPDATE_TICKS <= mac->instance->ticks) {
- port_stats_update(mac);
- mac->instance->ticks = 0;
- } else {
- u32 val;
-
- RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
- RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
- mac->instance->ticks++;
- }
- return &mac->stats;
-}
-
-static void mac_destroy(struct cmac *mac)
-{
- kfree(mac);
-}
-
-static struct cmac_ops ixf1010_ops = {
- .destroy = mac_destroy,
- .reset = mac_reset,
- .interrupt_enable = mac_intr_op,
- .interrupt_disable = mac_intr_op,
- .interrupt_clear = mac_intr_op,
- .enable = mac_enable,
- .disable = mac_disable,
- .set_mtu = mac_set_mtu,
- .set_rx_mode = mac_set_rx_mode,
- .set_speed_duplex_fc = mac_set_speed_duplex_fc,
- .get_speed_duplex_fc = mac_get_speed_duplex_fc,
- .statistics_update = mac_update_statistics,
- .macaddress_get = mac_get_address,
- .macaddress_set = mac_set_address,
-};
-
-static int ixf1010_mac_reset(adapter_t *adapter)
-{
- u32 val;
-
- t1_tpi_read(adapter, A_ELMER0_GPO, &val);
- if ((val & 1) != 0) {
- val &= ~1;
- t1_tpi_write(adapter, A_ELMER0_GPO, val);
- udelay(2);
- }
- val |= 1;
- t1_tpi_write(adapter, A_ELMER0_GPO, val);
- udelay(2);
-
- t1_tpi_write(adapter, REG_PORT_ENABLE, 0);
- return 0;
-}
-
-static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index)
-{
- struct cmac *mac;
- u32 val;
-
- if (index > 9)
- return NULL;
-
- mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
- if (!mac)
- return NULL;
-
- mac->ops = &ixf1010_ops;
- mac->instance = (cmac_instance *)(mac + 1);
-
- mac->instance->mac_base = MACREG_BASE + (index * 0x200);
- mac->instance->index = index;
- mac->adapter = adapter;
- mac->instance->ticks = 0;
-
- t1_tpi_read(adapter, REG_JTAG_ID, &val);
- mac->instance->version = val >> 28;
- return mac;
-}
-
-struct gmac t1_ixf1010_ops = {
- STATS_TICK_SECS,
- ixf1010_mac_create,
- ixf1010_mac_reset
-};
diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c
index 6af39dc70459..1d972825eac3 100644
--- a/drivers/net/chelsio/mac.c
+++ b/drivers/net/chelsio/mac.c
@@ -363,6 +363,6 @@ static struct cmac *mac_create(adapter_t *adapter, int index)
return mac;
}
-struct gmac t1_chelsio_mac_ops = {
+const struct gmac t1_chelsio_mac_ops = {
.create = mac_create
};
diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c
index 5867e3b0a887..0632be0d6494 100644
--- a/drivers/net/chelsio/mv88e1xxx.c
+++ b/drivers/net/chelsio/mv88e1xxx.c
@@ -354,7 +354,7 @@ static struct cphy_ops mv88e1xxx_ops = {
};
static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
- struct mdio_ops *mdio_ops)
+ const struct mdio_ops *mdio_ops)
{
struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
@@ -390,7 +390,7 @@ static int mv88e1xxx_phy_reset(adapter_t* adapter)
return 0;
}
-struct gphy t1_mv88e1xxx_ops = {
- mv88e1xxx_phy_create,
- mv88e1xxx_phy_reset
+const struct gphy t1_mv88e1xxx_ops = {
+ .create = mv88e1xxx_phy_create,
+ .reset = mv88e1xxx_phy_reset
};
diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c
index c8e89480d906..cd856041af34 100644
--- a/drivers/net/chelsio/mv88x201x.c
+++ b/drivers/net/chelsio/mv88x201x.c
@@ -208,7 +208,7 @@ static struct cphy_ops mv88x201x_ops = {
};
static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr,
- struct mdio_ops *mdio_ops)
+ const struct mdio_ops *mdio_ops)
{
u32 val;
struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
@@ -252,7 +252,7 @@ static int mv88x201x_phy_reset(adapter_t *adapter)
return 0;
}
-struct gphy t1_mv88x201x_ops = {
- mv88x201x_phy_create,
- mv88x201x_phy_reset
+const struct gphy t1_mv88x201x_ops = {
+ .create = mv88x201x_phy_create,
+ .reset = mv88x201x_phy_reset
};
diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c
index 87dde3e60046..040acd29995a 100644
--- a/drivers/net/chelsio/my3126.c
+++ b/drivers/net/chelsio/my3126.c
@@ -166,7 +166,7 @@ static struct cphy_ops my3126_ops = {
};
static struct cphy *my3126_phy_create(adapter_t *adapter,
- int phy_addr, struct mdio_ops *mdio_ops)
+ int phy_addr, const struct mdio_ops *mdio_ops)
{
struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL);
@@ -201,7 +201,7 @@ static int my3126_phy_reset(adapter_t * adapter)
return 0;
}
-struct gphy t1_my3126_ops = {
- my3126_phy_create,
- my3126_phy_reset
+const struct gphy t1_my3126_ops = {
+ .create = my3126_phy_create,
+ .reset = my3126_phy_reset
};
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c
index 69129edeefd6..678778a8d133 100644
--- a/drivers/net/chelsio/pm3393.c
+++ b/drivers/net/chelsio/pm3393.c
@@ -807,8 +807,8 @@ static int pm3393_mac_reset(adapter_t * adapter)
return successful_reset ? 0 : 1;
}
-struct gmac t1_pm3393_ops = {
- STATS_TICK_SECS,
- pm3393_mac_create,
- pm3393_mac_reset
+const struct gmac t1_pm3393_ops = {
+ .stats_update_period = STATS_TICK_SECS,
+ .create = pm3393_mac_create,
+ .reset = pm3393_mac_reset,
};
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index c2522cdfab37..7de9a611e1f7 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -321,10 +321,10 @@ static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr,
}
#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
-static struct mdio_ops mi1_mdio_ops = {
- mi1_mdio_init,
- mi1_mdio_read,
- mi1_mdio_write
+static const struct mdio_ops mi1_mdio_ops = {
+ .init = mi1_mdio_init,
+ .read = mi1_mdio_read,
+ .write = mi1_mdio_write
};
#endif
@@ -377,10 +377,10 @@ static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr,
return 0;
}
-static struct mdio_ops mi1_mdio_ext_ops = {
- mi1_mdio_init,
- mi1_mdio_ext_read,
- mi1_mdio_ext_write
+static const struct mdio_ops mi1_mdio_ext_ops = {
+ .init = mi1_mdio_init,
+ .read = mi1_mdio_ext_read,
+ .write = mi1_mdio_ext_write
};
enum {
@@ -392,63 +392,136 @@ enum {
CH_BRD_N204_4CU,
};
-static struct board_info t1_board[] = {
-
-{ CHBT_BOARD_CHT110, 1/*ports#*/,
- SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T1,
- CHBT_MAC_PM3393, CHBT_PHY_MY3126,
- 125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/,
- 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
- 1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
- &t1_my3126_ops, &mi1_mdio_ext_ops,
- "Chelsio T110 1x10GBase-CX4 TOE" },
-
-{ CHBT_BOARD_N110, 1/*ports#*/,
- SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
- CHBT_MAC_PM3393, CHBT_PHY_88X2010,
- 125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
- 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
- 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
- &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
- "Chelsio N110 1x10GBaseX NIC" },
-
-{ CHBT_BOARD_N210, 1/*ports#*/,
- SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T2,
- CHBT_MAC_PM3393, CHBT_PHY_88X2010,
- 125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
- 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
- 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
- &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
- "Chelsio N210 1x10GBaseX NIC" },
-
-{ CHBT_BOARD_CHT210, 1/*ports#*/,
- SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
- CHBT_MAC_PM3393, CHBT_PHY_88X2010,
- 125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
- 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
- 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
- &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
- "Chelsio T210 1x10GBaseX TOE" },
-
-{ CHBT_BOARD_CHT210, 1/*ports#*/,
- SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
- CHBT_MAC_PM3393, CHBT_PHY_MY3126,
- 125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
- 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
- 1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
- &t1_my3126_ops, &mi1_mdio_ext_ops,
- "Chelsio T210 1x10GBase-CX4 TOE" },
+static const struct board_info t1_board[] = {
+ {
+ .board = CHBT_BOARD_CHT110,
+ .port_number = 1,
+ .caps = SUPPORTED_10000baseT_Full,
+ .chip_term = CHBT_TERM_T1,
+ .chip_mac = CHBT_MAC_PM3393,
+ .chip_phy = CHBT_PHY_MY3126,
+ .clock_core = 125000000,
+ .clock_mc3 = 150000000,
+ .clock_mc4 = 125000000,
+ .espi_nports = 1,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 1,
+ .mdio_mdiinv = 1,
+ .mdio_mdc = 1,
+ .mdio_phybaseaddr = 1,
+ .gmac = &t1_pm3393_ops,
+ .gphy = &t1_my3126_ops,
+ .mdio_ops = &mi1_mdio_ext_ops,
+ .desc = "Chelsio T110 1x10GBase-CX4 TOE",
+ },
+
+ {
+ .board = CHBT_BOARD_N110,
+ .port_number = 1,
+ .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,
+ .chip_term = CHBT_TERM_T1,
+ .chip_mac = CHBT_MAC_PM3393,
+ .chip_phy = CHBT_PHY_88X2010,
+ .clock_core = 125000000,
+ .espi_nports = 1,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 0,
+ .mdio_mdiinv = 0,
+ .mdio_mdc = 1,
+ .mdio_phybaseaddr = 0,
+ .gmac = &t1_pm3393_ops,
+ .gphy = &t1_mv88x201x_ops,
+ .mdio_ops = &mi1_mdio_ext_ops,
+ .desc = "Chelsio N110 1x10GBaseX NIC",
+ },
+
+ {
+ .board = CHBT_BOARD_N210,
+ .port_number = 1,
+ .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,
+ .chip_term = CHBT_TERM_T2,
+ .chip_mac = CHBT_MAC_PM3393,
+ .chip_phy = CHBT_PHY_88X2010,
+ .clock_core = 125000000,
+ .espi_nports = 1,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 0,
+ .mdio_mdiinv = 0,
+ .mdio_mdc = 1,
+ .mdio_phybaseaddr = 0,
+ .gmac = &t1_pm3393_ops,
+ .gphy = &t1_mv88x201x_ops,
+ .mdio_ops = &mi1_mdio_ext_ops,
+ .desc = "Chelsio N210 1x10GBaseX NIC",
+ },
+
+ {
+ .board = CHBT_BOARD_CHT210,
+ .port_number = 1,
+ .caps = SUPPORTED_10000baseT_Full,
+ .chip_term = CHBT_TERM_T2,
+ .chip_mac = CHBT_MAC_PM3393,
+ .chip_phy = CHBT_PHY_88X2010,
+ .clock_core = 125000000,
+ .clock_mc3 = 133000000,
+ .clock_mc4 = 125000000,
+ .espi_nports = 1,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 0,
+ .mdio_mdiinv = 0,
+ .mdio_mdc = 1,
+ .mdio_phybaseaddr = 0,
+ .gmac = &t1_pm3393_ops,
+ .gphy = &t1_mv88x201x_ops,
+ .mdio_ops = &mi1_mdio_ext_ops,
+ .desc = "Chelsio T210 1x10GBaseX TOE",
+ },
+
+ {
+ .board = CHBT_BOARD_CHT210,
+ .port_number = 1,
+ .caps = SUPPORTED_10000baseT_Full,
+ .chip_term = CHBT_TERM_T2,
+ .chip_mac = CHBT_MAC_PM3393,
+ .chip_phy = CHBT_PHY_MY3126,
+ .clock_core = 125000000,
+ .clock_mc3 = 133000000,
+ .clock_mc4 = 125000000,
+ .espi_nports = 1,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 1,
+ .mdio_mdiinv = 1,
+ .mdio_mdc = 1,
+ .mdio_phybaseaddr = 1,
+ .gmac = &t1_pm3393_ops,
+ .gphy = &t1_my3126_ops,
+ .mdio_ops = &mi1_mdio_ext_ops,
+ .desc = "Chelsio T210 1x10GBase-CX4 TOE",
+ },
#ifdef CONFIG_CHELSIO_T1_1G
-{ CHBT_BOARD_CHN204, 4/*ports#*/,
- SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
- SUPPORTED_PAUSE | SUPPORTED_TP /*caps*/, CHBT_TERM_T2, CHBT_MAC_VSC7321, CHBT_PHY_88E1111,
- 100000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
- 4/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
- 0/*mdiinv*/, 1/*mdc*/, 4/*phybaseaddr*/, &t1_vsc7326_ops,
- &t1_mv88e1xxx_ops, &mi1_mdio_ops,
- "Chelsio N204 4x100/1000BaseT NIC" },
+ {
+ .board = CHBT_BOARD_CHN204,
+ .port_number = 4,
+ .caps = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
+ | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+ SUPPORTED_PAUSE | SUPPORTED_TP,
+ .chip_term = CHBT_TERM_T2,
+ .chip_mac = CHBT_MAC_VSC7321,
+ .chip_phy = CHBT_PHY_88E1111,
+ .clock_core = 100000000,
+ .espi_nports = 4,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 0,
+ .mdio_mdiinv = 0,
+ .mdio_mdc = 0,
+ .mdio_phybaseaddr = 4,
+ .gmac = &t1_vsc7326_ops,
+ .gphy = &t1_mv88e1xxx_ops,
+ .mdio_ops = &mi1_mdio_ops,
+ .desc = "Chelsio N204 4x100/1000BaseT NIC",
+ },
#endif
};
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c
index 534ffa0f616e..99b51f61fe77 100644
--- a/drivers/net/chelsio/vsc7326.c
+++ b/drivers/net/chelsio/vsc7326.c
@@ -723,7 +723,7 @@ static int vsc7326_mac_reset(adapter_t *adapter)
return 0;
}
-struct gmac t1_vsc7326_ops = {
+const struct gmac t1_vsc7326_ops = {
.stats_update_period = STATS_TICK_SECS,
.create = vsc7326_mac_create,
.reset = vsc7326_mac_reset,
diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c
deleted file mode 100644
index 251d4859c91d..000000000000
--- a/drivers/net/chelsio/vsc8244.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * This file is part of the Chelsio T2 Ethernet driver.
- *
- * Copyright (C) 2005 Chelsio Communications. All rights reserved.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this
- * release for licensing terms and conditions.
- */
-
-#include "common.h"
-#include "cphy.h"
-#include "elmer0.h"
-
-#ifndef ADVERTISE_PAUSE_CAP
-# define ADVERTISE_PAUSE_CAP 0x400
-#endif
-#ifndef ADVERTISE_PAUSE_ASYM
-# define ADVERTISE_PAUSE_ASYM 0x800
-#endif
-
-/* Gigabit MII registers */
-#ifndef MII_CTRL1000
-# define MII_CTRL1000 9
-#endif
-
-#ifndef ADVERTISE_1000FULL
-# define ADVERTISE_1000FULL 0x200
-# define ADVERTISE_1000HALF 0x100
-#endif
-
-/* VSC8244 PHY specific registers. */
-enum {
- VSC8244_INTR_ENABLE = 25,
- VSC8244_INTR_STATUS = 26,
- VSC8244_AUX_CTRL_STAT = 28,
-};
-
-enum {
- VSC_INTR_RX_ERR = 1 << 0,
- VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
- VSC_INTR_CABLE = 1 << 2, /* cable impairment */
- VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
- VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
- VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
- VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
- VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
- VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
- VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
- VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
- VSC_INTR_LINK_CHG = 1 << 13, /* link change */
- VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
-};
-
-#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
- VSC_INTR_NEG_DONE)
-#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
- VSC_INTR_ENABLE)
-
-/* PHY specific auxiliary control & status register fields */
-#define S_ACSR_ACTIPHY_TMR 0
-#define M_ACSR_ACTIPHY_TMR 0x3
-#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
-
-#define S_ACSR_SPEED 3
-#define M_ACSR_SPEED 0x3
-#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
-
-#define S_ACSR_DUPLEX 5
-#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
-
-#define S_ACSR_ACTIPHY 6
-#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
-
-/*
- * Reset the PHY. This PHY completes reset immediately so we never wait.
- */
-static int vsc8244_reset(struct cphy *cphy, int wait)
-{
- int err;
- unsigned int ctl;
-
- err = simple_mdio_read(cphy, MII_BMCR, &ctl);
- if (err)
- return err;
-
- ctl &= ~BMCR_PDOWN;
- ctl |= BMCR_RESET;
- return simple_mdio_write(cphy, MII_BMCR, ctl);
-}
-
-static int vsc8244_intr_enable(struct cphy *cphy)
-{
- simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK);
-
- /* Enable interrupts through Elmer */
- if (t1_is_asic(cphy->adapter)) {
- u32 elmer;
-
- t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
- elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter))
- elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
- }
-
- return 0;
-}
-
-static int vsc8244_intr_disable(struct cphy *cphy)
-{
- simple_mdio_write(cphy, VSC8244_INTR_ENABLE, 0);
-
- if (t1_is_asic(cphy->adapter)) {
- u32 elmer;
-
- t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
- elmer &= ~ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter))
- elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
- t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
- }
-
- return 0;
-}
-
-static int vsc8244_intr_clear(struct cphy *cphy)
-{
- u32 val;
- u32 elmer;
-
- /* Clear PHY interrupts by reading the register. */
- simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val);
-
- if (t1_is_asic(cphy->adapter)) {
- t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
- elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter))
- elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
- }
-
- return 0;
-}
-
-/*
- * Force the PHY speed and duplex. This also disables auto-negotiation, except
- * for 1Gb/s, where auto-negotiation is mandatory.
- */
-static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex)
-{
- int err;
- unsigned int ctl;
-
- err = simple_mdio_read(phy, MII_BMCR, &ctl);
- if (err)
- return err;
-
- if (speed >= 0) {
- ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
- if (speed == SPEED_100)
- ctl |= BMCR_SPEED100;
- else if (speed == SPEED_1000)
- ctl |= BMCR_SPEED1000;
- }
- if (duplex >= 0) {
- ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
- if (duplex == DUPLEX_FULL)
- ctl |= BMCR_FULLDPLX;
- }
- if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */
- ctl |= BMCR_ANENABLE;
- return simple_mdio_write(phy, MII_BMCR, ctl);
-}
-
-int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits)
-{
- int ret;
- unsigned int val;
-
- ret = mdio_read(phy, mmd, reg, &val);
- if (!ret)
- ret = mdio_write(phy, mmd, reg, val | bits);
- return ret;
-}
-
-static int vsc8244_autoneg_enable(struct cphy *cphy)
-{
- return t1_mdio_set_bits(cphy, 0, MII_BMCR,
- BMCR_ANENABLE | BMCR_ANRESTART);
-}
-
-static int vsc8244_autoneg_restart(struct cphy *cphy)
-{
- return t1_mdio_set_bits(cphy, 0, MII_BMCR, BMCR_ANRESTART);
-}
-
-static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map)
-{
- int err;
- unsigned int val = 0;
-
- err = simple_mdio_read(phy, MII_CTRL1000, &val);
- if (err)
- return err;
-
- val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
- if (advertise_map & ADVERTISED_1000baseT_Half)
- val |= ADVERTISE_1000HALF;
- if (advertise_map & ADVERTISED_1000baseT_Full)
- val |= ADVERTISE_1000FULL;
-
- err = simple_mdio_write(phy, MII_CTRL1000, val);
- if (err)
- return err;
-
- val = 1;
- if (advertise_map & ADVERTISED_10baseT_Half)
- val |= ADVERTISE_10HALF;
- if (advertise_map & ADVERTISED_10baseT_Full)
- val |= ADVERTISE_10FULL;
- if (advertise_map & ADVERTISED_100baseT_Half)
- val |= ADVERTISE_100HALF;
- if (advertise_map & ADVERTISED_100baseT_Full)
- val |= ADVERTISE_100FULL;
- if (advertise_map & ADVERTISED_PAUSE)
- val |= ADVERTISE_PAUSE_CAP;
- if (advertise_map & ADVERTISED_ASYM_PAUSE)
- val |= ADVERTISE_PAUSE_ASYM;
- return simple_mdio_write(phy, MII_ADVERTISE, val);
-}
-
-static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok,
- int *speed, int *duplex, int *fc)
-{
- unsigned int bmcr, status, lpa, adv;
- int err, sp = -1, dplx = -1, pause = 0;
-
- err = simple_mdio_read(cphy, MII_BMCR, &bmcr);
- if (!err)
- err = simple_mdio_read(cphy, MII_BMSR, &status);
- if (err)
- return err;
-
- if (link_ok) {
- /*
- * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
- * once more to get the current link state.
- */
- if (!(status & BMSR_LSTATUS))
- err = simple_mdio_read(cphy, MII_BMSR, &status);
- if (err)
- return err;
- *link_ok = (status & BMSR_LSTATUS) != 0;
- }
- if (!(bmcr & BMCR_ANENABLE)) {
- dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
- if (bmcr & BMCR_SPEED1000)
- sp = SPEED_1000;
- else if (bmcr & BMCR_SPEED100)
- sp = SPEED_100;
- else
- sp = SPEED_10;
- } else if (status & BMSR_ANEGCOMPLETE) {
- err = simple_mdio_read(cphy, VSC8244_AUX_CTRL_STAT, &status);
- if (err)
- return err;
-
- dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
- sp = G_ACSR_SPEED(status);
- if (sp == 0)
- sp = SPEED_10;
- else if (sp == 1)
- sp = SPEED_100;
- else
- sp = SPEED_1000;
-
- if (fc && dplx == DUPLEX_FULL) {
- err = simple_mdio_read(cphy, MII_LPA, &lpa);
- if (!err)
- err = simple_mdio_read(cphy, MII_ADVERTISE,
- &adv);
- if (err)
- return err;
-
- if (lpa & adv & ADVERTISE_PAUSE_CAP)
- pause = PAUSE_RX | PAUSE_TX;
- else if ((lpa & ADVERTISE_PAUSE_CAP) &&
- (lpa & ADVERTISE_PAUSE_ASYM) &&
- (adv & ADVERTISE_PAUSE_ASYM))
- pause = PAUSE_TX;
- else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
- (adv & ADVERTISE_PAUSE_CAP))
- pause = PAUSE_RX;
- }
- }
- if (speed)
- *speed = sp;
- if (duplex)
- *duplex = dplx;
- if (fc)
- *fc = pause;
- return 0;
-}
-
-static int vsc8244_intr_handler(struct cphy *cphy)
-{
- unsigned int cause;
- int err, cphy_cause = 0;
-
- err = simple_mdio_read(cphy, VSC8244_INTR_STATUS, &cause);
- if (err)
- return err;
-
- cause &= INTR_MASK;
- if (cause & CFG_CHG_INTR_MASK)
- cphy_cause |= cphy_cause_link_change;
- if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
- cphy_cause |= cphy_cause_fifo_error;
- return cphy_cause;
-}
-
-static void vsc8244_destroy(struct cphy *cphy)
-{
- kfree(cphy);
-}
-
-static struct cphy_ops vsc8244_ops = {
- .destroy = vsc8244_destroy,
- .reset = vsc8244_reset,
- .interrupt_enable = vsc8244_intr_enable,
- .interrupt_disable = vsc8244_intr_disable,
- .interrupt_clear = vsc8244_intr_clear,
- .interrupt_handler = vsc8244_intr_handler,
- .autoneg_enable = vsc8244_autoneg_enable,
- .autoneg_restart = vsc8244_autoneg_restart,
- .advertise = vsc8244_advertise,
- .set_speed_duplex = vsc8244_set_speed_duplex,
- .get_link_status = vsc8244_get_link_status
-};
-
-static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr,
- struct mdio_ops *mdio_ops)
-{
- struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
-
- if (!cphy)
- return NULL;
-
- cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops);
-
- return cphy;
-}
-
-
-static int vsc8244_phy_reset(adapter_t* adapter)
-{
- return 0;
-}
-
-struct gphy t1_vsc8244_ops = {
- vsc8244_phy_create,
- vsc8244_phy_reset
-};
-
-
diff --git a/drivers/net/chelsio/vsc8244_reg.h b/drivers/net/chelsio/vsc8244_reg.h
deleted file mode 100644
index d3c1829055cb..000000000000
--- a/drivers/net/chelsio/vsc8244_reg.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* $Date: 2005/11/23 16:28:53 $ $RCSfile: vsc8244_reg.h,v $ $Revision: 1.1 $ */
-#ifndef CHELSIO_MV8E1XXX_H
-#define CHELSIO_MV8E1XXX_H
-
-#ifndef BMCR_SPEED1000
-# define BMCR_SPEED1000 0x40
-#endif
-
-#ifndef ADVERTISE_PAUSE
-# define ADVERTISE_PAUSE 0x400
-#endif
-#ifndef ADVERTISE_PAUSE_ASYM
-# define ADVERTISE_PAUSE_ASYM 0x800
-#endif
-
-/* Gigabit MII registers */
-#define MII_GBMR 1 /* 1000Base-T mode register */
-#define MII_GBCR 9 /* 1000Base-T control register */
-#define MII_GBSR 10 /* 1000Base-T status register */
-
-/* 1000Base-T control register fields */
-#define GBCR_ADV_1000HALF 0x100
-#define GBCR_ADV_1000FULL 0x200
-#define GBCR_PREFER_MASTER 0x400
-#define GBCR_MANUAL_AS_MASTER 0x800
-#define GBCR_MANUAL_CONFIG_ENABLE 0x1000
-
-/* 1000Base-T status register fields */
-#define GBSR_LP_1000HALF 0x400
-#define GBSR_LP_1000FULL 0x800
-#define GBSR_REMOTE_OK 0x1000
-#define GBSR_LOCAL_OK 0x2000
-#define GBSR_LOCAL_MASTER 0x4000
-#define GBSR_MASTER_FAULT 0x8000
-
-/* Vitesse PHY interrupt status bits. */
-#if 0
-#define VSC8244_INTR_JABBER 0x0001
-#define VSC8244_INTR_POLARITY_CHNG 0x0002
-#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010
-#define VSC8244_INTR_DOWNSHIFT 0x0020
-#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040
-#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080
-#define VSC8244_INTR_FALSE_CARRIER 0x0100
-#define VSC8244_INTR_SYMBOL_ERROR 0x0200
-#define VSC8244_INTR_LINK_CHNG 0x0400
-#define VSC8244_INTR_AUTONEG_DONE 0x0800
-#define VSC8244_INTR_PAGE_RECV 0x1000
-#define VSC8244_INTR_DUPLEX_CHNG 0x2000
-#define VSC8244_INTR_SPEED_CHNG 0x4000
-#define VSC8244_INTR_AUTONEG_ERR 0x8000
-#else
-//#define VSC8244_INTR_JABBER 0x0001
-//#define VSC8244_INTR_POLARITY_CHNG 0x0002
-//#define VSC8244_INTR_BIT2 0x0004
-//#define VSC8244_INTR_BIT3 0x0008
-#define VSC8244_INTR_RX_ERR 0x0001
-#define VSC8244_INTR_MASTER_SLAVE 0x0002
-#define VSC8244_INTR_CABLE_IMPAIRED 0x0004
-#define VSC8244_INTR_FALSE_CARRIER 0x0008
-//#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010
-//#define VSC8244_INTR_DOWNSHIFT 0x0020
-//#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040
-//#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080
-#define VSC8244_INTR_BIT4 0x0010
-#define VSC8244_INTR_FIFO_RX 0x0020
-#define VSC8244_INTR_FIFO_OVER_UNDER 0x0040
-#define VSC8244_INTR_LOCK_LOST 0x0080
-//#define VSC8244_INTR_FALSE_CARRIER 0x0100
-//#define VSC8244_INTR_SYMBOL_ERROR 0x0200
-//#define VSC8244_INTR_LINK_CHNG 0x0400
-//#define VSC8244_INTR_AUTONEG_DONE 0x0800
-#define VSC8244_INTR_SYMBOL_ERROR 0x0100
-#define VSC8244_INTR_ENG_DETECT_CHNG 0x0200
-#define VSC8244_INTR_AUTONEG_DONE 0x0400
-#define VSC8244_INTR_AUTONEG_ERR 0x0800
-//#define VSC8244_INTR_PAGE_RECV 0x1000
-//#define VSC8244_INTR_DUPLEX_CHNG 0x2000
-//#define VSC8244_INTR_SPEED_CHNG 0x4000
-//#define VSC8244_INTR_AUTONEG_ERR 0x8000
-#define VSC8244_INTR_DUPLEX_CHNG 0x1000
-#define VSC8244_INTR_LINK_CHNG 0x2000
-#define VSC8244_INTR_SPEED_CHNG 0x4000
-#define VSC8244_INTR_STATUS 0x8000
-#endif
-
-
-/* Vitesse PHY specific registers. */
-#define VSC8244_SPECIFIC_CNTRL_REGISTER 16
-#define VSC8244_SPECIFIC_STATUS_REGISTER 0x1c
-#define VSC8244_INTERRUPT_ENABLE_REGISTER 0x19
-#define VSC8244_INTERRUPT_STATUS_REGISTER 0x1a
-#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_REGISTER 20
-#define VSC8244_RECV_ERR_CNTR_REGISTER 21
-#define VSC8244_RES_REGISTER 22
-#define VSC8244_GLOBAL_STATUS_REGISTER 23
-#define VSC8244_LED_CONTROL_REGISTER 24
-#define VSC8244_MANUAL_LED_OVERRIDE_REGISTER 25
-#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_2_REGISTER 26
-#define VSC8244_EXT_PHY_SPECIFIC_STATUS_REGISTER 27
-#define VSC8244_VIRTUAL_CABLE_TESTER_REGISTER 28
-#define VSC8244_EXTENDED_ADDR_REGISTER 29
-#define VSC8244_EXTENDED_REGISTER 30
-
-/* PHY specific control register fields */
-#define S_PSCR_MDI_XOVER_MODE 5
-#define M_PSCR_MDI_XOVER_MODE 0x3
-#define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE)
-#define G_PSCR_MDI_XOVER_MODE(x) (((x) >> S_PSCR_MDI_XOVER_MODE) & M_PSCR_MDI_XOVER_MODE)
-
-/* Extended PHY specific control register fields */
-#define S_DOWNSHIFT_ENABLE 8
-#define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE)
-
-#define S_DOWNSHIFT_CNT 9
-#define M_DOWNSHIFT_CNT 0x7
-#define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT)
-#define G_DOWNSHIFT_CNT(x) (((x) >> S_DOWNSHIFT_CNT) & M_DOWNSHIFT_CNT)
-
-/* PHY specific status register fields */
-#define S_PSSR_JABBER 0
-#define V_PSSR_JABBER (1 << S_PSSR_JABBER)
-
-#define S_PSSR_POLARITY 1
-#define V_PSSR_POLARITY (1 << S_PSSR_POLARITY)
-
-#define S_PSSR_RX_PAUSE 2
-#define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE)
-
-#define S_PSSR_TX_PAUSE 3
-#define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE)
-
-#define S_PSSR_ENERGY_DETECT 4
-#define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT)
-
-#define S_PSSR_DOWNSHIFT_STATUS 5
-#define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS)
-
-#define S_PSSR_MDI 6
-#define V_PSSR_MDI (1 << S_PSSR_MDI)
-
-#define S_PSSR_CABLE_LEN 7
-#define M_PSSR_CABLE_LEN 0x7
-#define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN)
-#define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN)
-
-//#define S_PSSR_LINK 10
-//#define S_PSSR_LINK 13
-#define S_PSSR_LINK 2
-#define V_PSSR_LINK (1 << S_PSSR_LINK)
-
-//#define S_PSSR_STATUS_RESOLVED 11
-//#define S_PSSR_STATUS_RESOLVED 10
-#define S_PSSR_STATUS_RESOLVED 15
-#define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED)
-
-#define S_PSSR_PAGE_RECEIVED 12
-#define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED)
-
-//#define S_PSSR_DUPLEX 13
-//#define S_PSSR_DUPLEX 12
-#define S_PSSR_DUPLEX 5
-#define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX)
-
-//#define S_PSSR_SPEED 14
-//#define S_PSSR_SPEED 14
-#define S_PSSR_SPEED 3
-#define M_PSSR_SPEED 0x3
-#define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED)
-#define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED)
-
-#endif
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 4d0e0aea72bf..61696637a21e 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -159,7 +159,7 @@
#define DRV_NAME "e100"
#define DRV_EXT "-NAPI"
-#define DRV_VERSION "3.5.17-k2"DRV_EXT
+#define DRV_VERSION "3.5.17-k4"DRV_EXT
#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation"
#define PFX DRV_NAME ": "
@@ -174,10 +174,13 @@ MODULE_VERSION(DRV_VERSION);
static int debug = 3;
static int eeprom_bad_csum_allow = 0;
+static int use_io = 0;
module_param(debug, int, 0);
module_param(eeprom_bad_csum_allow, int, 0);
+module_param(use_io, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
+MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
#define DPRINTK(nlevel, klevel, fmt, args...) \
(void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
@@ -282,12 +285,6 @@ enum scb_status {
rus_mask = 0x3C,
};
-enum ru_state {
- RU_SUSPENDED = 0,
- RU_RUNNING = 1,
- RU_UNINITIALIZED = -1,
-};
-
enum scb_stat_ack {
stat_ack_not_ours = 0x00,
stat_ack_sw_gen = 0x04,
@@ -529,7 +526,6 @@ struct nic {
struct rx *rx_to_use;
struct rx *rx_to_clean;
struct rfd blank_rfd;
- enum ru_state ru_running;
spinlock_t cb_lock ____cacheline_aligned;
spinlock_t cmd_lock;
@@ -591,7 +587,7 @@ static inline void e100_write_flush(struct nic *nic)
{
/* Flush previous PCI writes through intermediate bridges
* by doing a benign read */
- (void)readb(&nic->csr->scb.status);
+ (void)ioread8(&nic->csr->scb.status);
}
static void e100_enable_irq(struct nic *nic)
@@ -599,7 +595,7 @@ static void e100_enable_irq(struct nic *nic)
unsigned long flags;
spin_lock_irqsave(&nic->cmd_lock, flags);
- writeb(irq_mask_none, &nic->csr->scb.cmd_hi);
+ iowrite8(irq_mask_none, &nic->csr->scb.cmd_hi);
e100_write_flush(nic);
spin_unlock_irqrestore(&nic->cmd_lock, flags);
}
@@ -609,7 +605,7 @@ static void e100_disable_irq(struct nic *nic)
unsigned long flags;
spin_lock_irqsave(&nic->cmd_lock, flags);
- writeb(irq_mask_all, &nic->csr->scb.cmd_hi);
+ iowrite8(irq_mask_all, &nic->csr->scb.cmd_hi);
e100_write_flush(nic);
spin_unlock_irqrestore(&nic->cmd_lock, flags);
}
@@ -618,11 +614,11 @@ static void e100_hw_reset(struct nic *nic)
{
/* Put CU and RU into idle with a selective reset to get
* device off of PCI bus */
- writel(selective_reset, &nic->csr->port);
+ iowrite32(selective_reset, &nic->csr->port);
e100_write_flush(nic); udelay(20);
/* Now fully reset device */
- writel(software_reset, &nic->csr->port);
+ iowrite32(software_reset, &nic->csr->port);
e100_write_flush(nic); udelay(20);
/* Mask off our interrupt line - it's unmasked after reset */
@@ -639,7 +635,7 @@ static int e100_self_test(struct nic *nic)
nic->mem->selftest.signature = 0;
nic->mem->selftest.result = 0xFFFFFFFF;
- writel(selftest | dma_addr, &nic->csr->port);
+ iowrite32(selftest | dma_addr, &nic->csr->port);
e100_write_flush(nic);
/* Wait 10 msec for self-test to complete */
msleep(10);
@@ -677,23 +673,23 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data)
for(j = 0; j < 3; j++) {
/* Chip select */
- writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
for(i = 31; i >= 0; i--) {
ctrl = (cmd_addr_data[j] & (1 << i)) ?
eecs | eedi : eecs;
- writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
- writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
}
/* Wait 10 msec for cmd to complete */
msleep(10);
/* Chip deselect */
- writeb(0, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(0, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
}
};
@@ -709,21 +705,21 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
cmd_addr_data = ((op_read << *addr_len) | addr) << 16;
/* Chip select */
- writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
/* Bit-bang to read word from eeprom */
for(i = 31; i >= 0; i--) {
ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
- writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
- writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
/* Eeprom drives a dummy zero to EEDO after receiving
* complete address. Use this to adjust addr_len. */
- ctrl = readb(&nic->csr->eeprom_ctrl_lo);
+ ctrl = ioread8(&nic->csr->eeprom_ctrl_lo);
if(!(ctrl & eedo) && i > 16) {
*addr_len -= (i - 16);
i = 17;
@@ -733,7 +729,7 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
}
/* Chip deselect */
- writeb(0, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(0, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
return le16_to_cpu(data);
@@ -804,7 +800,7 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
/* Previous command is accepted when SCB clears */
for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) {
- if(likely(!readb(&nic->csr->scb.cmd_lo)))
+ if(likely(!ioread8(&nic->csr->scb.cmd_lo)))
break;
cpu_relax();
if(unlikely(i > E100_WAIT_SCB_FAST))
@@ -816,8 +812,8 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
}
if(unlikely(cmd != cuc_resume))
- writel(dma_addr, &nic->csr->scb.gen_ptr);
- writeb(cmd, &nic->csr->scb.cmd_lo);
+ iowrite32(dma_addr, &nic->csr->scb.gen_ptr);
+ iowrite8(cmd, &nic->csr->scb.cmd_lo);
err_unlock:
spin_unlock_irqrestore(&nic->cmd_lock, flags);
@@ -895,7 +891,7 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
*/
spin_lock_irqsave(&nic->mdio_lock, flags);
for (i = 100; i; --i) {
- if (readl(&nic->csr->mdi_ctrl) & mdi_ready)
+ if (ioread32(&nic->csr->mdi_ctrl) & mdi_ready)
break;
udelay(20);
}
@@ -905,11 +901,11 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
spin_unlock_irqrestore(&nic->mdio_lock, flags);
return 0; /* No way to indicate timeout error */
}
- writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
+ iowrite32((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
for (i = 0; i < 100; i++) {
udelay(20);
- if ((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready)
+ if ((data_out = ioread32(&nic->csr->mdi_ctrl)) & mdi_ready)
break;
}
spin_unlock_irqrestore(&nic->mdio_lock, flags);
@@ -951,7 +947,7 @@ static void e100_get_defaults(struct nic *nic)
((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
/* Template for a freshly allocated RFD */
- nic->blank_rfd.command = cpu_to_le16(cb_el);
+ nic->blank_rfd.command = cpu_to_le16(cb_el & cb_s);
nic->blank_rfd.rbd = 0xFFFFFFFF;
nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
@@ -1318,7 +1314,7 @@ static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb,
}
/* ack any interupts, something could have been set */
- writeb(~0, &nic->csr->scb.stat_ack);
+ iowrite8(~0, &nic->csr->scb.stat_ack);
/* if the command failed, or is not OK, notify and return */
if (!counter || !(cb->status & cpu_to_le16(cb_ok))) {
@@ -1580,7 +1576,7 @@ static void e100_watchdog(unsigned long data)
* accidentally, due to hardware that shares a register between the
* interrupt mask bit and the SW Interrupt generation bit */
spin_lock_irq(&nic->cmd_lock);
- writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
+ iowrite8(ioread8(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
e100_write_flush(nic);
spin_unlock_irq(&nic->cmd_lock);
@@ -1746,19 +1742,11 @@ static int e100_alloc_cbs(struct nic *nic)
return 0;
}
-static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
+static inline void e100_start_receiver(struct nic *nic)
{
- if(!nic->rxs) return;
- if(RU_SUSPENDED != nic->ru_running) return;
-
- /* handle init time starts */
- if(!rx) rx = nic->rxs;
-
- /* (Re)start RU if suspended or idle and RFA is non-NULL */
- if(rx->skb) {
- e100_exec_cmd(nic, ruc_start, rx->dma_addr);
- nic->ru_running = RU_RUNNING;
- }
+ /* Start if RFA is non-NULL */
+ if(nic->rx_to_clean->skb)
+ e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
}
#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
@@ -1787,7 +1775,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
put_unaligned(cpu_to_le32(rx->dma_addr),
(u32 *)&prev_rfd->link);
wmb();
- prev_rfd->command &= ~cpu_to_le16(cb_el);
+ prev_rfd->command &= ~cpu_to_le16(cb_el & cb_s);
pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
sizeof(struct rfd), PCI_DMA_TODEVICE);
}
@@ -1825,10 +1813,6 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
pci_unmap_single(nic->pdev, rx->dma_addr,
RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
- /* this allows for a fast restart without re-enabling interrupts */
- if(le16_to_cpu(rfd->command) & cb_el)
- nic->ru_running = RU_SUSPENDED;
-
/* Pull off the RFD and put the actual data (minus eth hdr) */
skb_reserve(skb, sizeof(struct rfd));
skb_put(skb, actual_size);
@@ -1859,45 +1843,18 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
unsigned int work_to_do)
{
struct rx *rx;
- int restart_required = 0;
- struct rx *rx_to_start = NULL;
-
- /* are we already rnr? then pay attention!!! this ensures that
- * the state machine progression never allows a start with a
- * partially cleaned list, avoiding a race between hardware
- * and rx_to_clean when in NAPI mode */
- if(RU_SUSPENDED == nic->ru_running)
- restart_required = 1;
/* Indicate newly arrived packets */
for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
- int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
- if(-EAGAIN == err) {
- /* hit quota so have more work to do, restart once
- * cleanup is complete */
- restart_required = 0;
- break;
- } else if(-ENODATA == err)
+ if(e100_rx_indicate(nic, rx, work_done, work_to_do))
break; /* No more to clean */
}
- /* save our starting point as the place we'll restart the receiver */
- if(restart_required)
- rx_to_start = nic->rx_to_clean;
-
/* Alloc new skbs to refill list */
for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
if(unlikely(e100_rx_alloc_skb(nic, rx)))
break; /* Better luck next time (see watchdog) */
}
-
- if(restart_required) {
- // ack the rnr?
- writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
- e100_start_receiver(nic, rx_to_start);
- if(work_done)
- (*work_done)++;
- }
}
static void e100_rx_clean_list(struct nic *nic)
@@ -1905,8 +1862,6 @@ static void e100_rx_clean_list(struct nic *nic)
struct rx *rx;
unsigned int i, count = nic->params.rfds.count;
- nic->ru_running = RU_UNINITIALIZED;
-
if(nic->rxs) {
for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
if(rx->skb) {
@@ -1928,7 +1883,6 @@ static int e100_rx_alloc_list(struct nic *nic)
unsigned int i, count = nic->params.rfds.count;
nic->rx_to_use = nic->rx_to_clean = NULL;
- nic->ru_running = RU_UNINITIALIZED;
if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC)))
return -ENOMEM;
@@ -1943,7 +1897,6 @@ static int e100_rx_alloc_list(struct nic *nic)
}
nic->rx_to_use = nic->rx_to_clean = nic->rxs;
- nic->ru_running = RU_SUSPENDED;
return 0;
}
@@ -1952,7 +1905,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
{
struct net_device *netdev = dev_id;
struct nic *nic = netdev_priv(netdev);
- u8 stat_ack = readb(&nic->csr->scb.stat_ack);
+ u8 stat_ack = ioread8(&nic->csr->scb.stat_ack);
DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
@@ -1961,11 +1914,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
return IRQ_NONE;
/* Ack interrupt(s) */
- writeb(stat_ack, &nic->csr->scb.stat_ack);
-
- /* We hit Receive No Resource (RNR); restart RU after cleaning */
- if(stat_ack & stat_ack_rnr)
- nic->ru_running = RU_SUSPENDED;
+ iowrite8(stat_ack, &nic->csr->scb.stat_ack);
if(likely(netif_rx_schedule_prep(netdev))) {
e100_disable_irq(nic);
@@ -2058,7 +2007,7 @@ static int e100_up(struct nic *nic)
if((err = e100_hw_init(nic)))
goto err_clean_cbs;
e100_set_multicast_list(nic->netdev);
- e100_start_receiver(nic, NULL);
+ e100_start_receiver(nic);
mod_timer(&nic->watchdog, jiffies);
if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
nic->netdev->name, nic->netdev)))
@@ -2107,7 +2056,7 @@ static void e100_tx_timeout_task(struct work_struct *work)
struct net_device *netdev = nic->netdev;
DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
- readb(&nic->csr->scb.status));
+ ioread8(&nic->csr->scb.status));
e100_down(netdev_priv(netdev));
e100_up(netdev_priv(netdev));
}
@@ -2139,7 +2088,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
BMCR_LOOPBACK);
- e100_start_receiver(nic, NULL);
+ e100_start_receiver(nic);
if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
err = -ENOMEM;
@@ -2230,9 +2179,9 @@ static void e100_get_regs(struct net_device *netdev,
int i;
regs->version = (1 << 24) | nic->rev_id;
- buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 |
- readb(&nic->csr->scb.cmd_lo) << 16 |
- readw(&nic->csr->scb.status);
+ buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 |
+ ioread8(&nic->csr->scb.cmd_lo) << 16 |
+ ioread16(&nic->csr->scb.status);
for(i = E100_PHY_REGS; i >= 0; i--)
buff[1 + E100_PHY_REGS - i] =
mdio_read(netdev, nic->mii.phy_id, i);
@@ -2604,7 +2553,10 @@ static int __devinit e100_probe(struct pci_dev *pdev,
SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
- nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr));
+ if (use_io)
+ DPRINTK(PROBE, INFO, "using i/o access mode\n");
+
+ nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct csr));
if(!nic->csr) {
DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n");
err = -ENOMEM;
@@ -2651,11 +2603,16 @@ static int __devinit e100_probe(struct pci_dev *pdev,
memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
- if(!is_valid_ether_addr(netdev->perm_addr)) {
- DPRINTK(PROBE, ERR, "Invalid MAC address from "
- "EEPROM, aborting.\n");
- err = -EAGAIN;
- goto err_out_free;
+ if (!is_valid_ether_addr(netdev->perm_addr)) {
+ if (!eeprom_bad_csum_allow) {
+ DPRINTK(PROBE, ERR, "Invalid MAC address from "
+ "EEPROM, aborting.\n");
+ err = -EAGAIN;
+ goto err_out_free;
+ } else {
+ DPRINTK(PROBE, ERR, "Invalid MAC address from EEPROM, "
+ "you MUST configure one.\n");
+ }
}
/* Wol magic packet can be enabled from eeprom */
@@ -2676,7 +2633,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
"MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
- (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
+ (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq,
netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
@@ -2685,7 +2642,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
err_out_free:
e100_free(nic);
err_out_iounmap:
- iounmap(nic->csr);
+ pci_iounmap(pdev, nic->csr);
err_out_free_res:
pci_release_regions(pdev);
err_out_disable_pdev:
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index dd4b728ac4b5..a9ea67e75c1b 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -155,9 +155,6 @@ struct e1000_adapter;
/* Number of packet split data buffers (not including the header buffer) */
#define PS_PAGE_BUFFERS MAX_PS_BUFFERS-1
-/* only works for sizes that are powers of 2 */
-#define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
-
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct e1000_buffer {
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 6777887295f5..bb08375b5f13 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -654,14 +654,11 @@ e1000_set_ringparam(struct net_device *netdev,
e1000_mac_type mac_type = adapter->hw.mac_type;
struct e1000_tx_ring *txdr, *tx_old;
struct e1000_rx_ring *rxdr, *rx_old;
- int i, err, tx_ring_size, rx_ring_size;
+ int i, err;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
- tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
- rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
-
while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
msleep(1);
@@ -672,11 +669,11 @@ e1000_set_ringparam(struct net_device *netdev,
rx_old = adapter->rx_ring;
err = -ENOMEM;
- txdr = kzalloc(tx_ring_size, GFP_KERNEL);
+ txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring), GFP_KERNEL);
if (!txdr)
goto err_alloc_tx;
- rxdr = kzalloc(rx_ring_size, GFP_KERNEL);
+ rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring), GFP_KERNEL);
if (!rxdr)
goto err_alloc_rx;
@@ -686,12 +683,12 @@ e1000_set_ringparam(struct net_device *netdev,
rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD);
rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ?
E1000_MAX_RXD : E1000_MAX_82544_RXD));
- E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+ rxdr->count = ALIGN(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD);
txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ?
E1000_MAX_TXD : E1000_MAX_82544_TXD));
- E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+ txdr->count = ALIGN(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
for (i = 0; i < adapter->num_tx_queues; i++)
txdr[i].count = txdr->count;
@@ -742,7 +739,7 @@ err_setup:
uint32_t pat, value; \
uint32_t test[] = \
{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
- for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \
+ for (pat = 0; pat < ARRAY_SIZE(test); pat++) { \
E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \
value = E1000_READ_REG(&adapter->hw, R); \
if (value != (test[pat] & W & M)) { \
@@ -1053,23 +1050,24 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter)
struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
uint32_t rctl;
- int size, i, ret_val;
+ int i, ret_val;
/* Setup Tx descriptor ring and Tx buffers */
if (!txdr->count)
txdr->count = E1000_DEFAULT_TXD;
- size = txdr->count * sizeof(struct e1000_buffer);
- if (!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+ if (!(txdr->buffer_info = kcalloc(txdr->count,
+ sizeof(struct e1000_buffer),
+ GFP_KERNEL))) {
ret_val = 1;
goto err_nomem;
}
- memset(txdr->buffer_info, 0, size);
txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
- E1000_ROUNDUP(txdr->size, 4096);
- if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) {
+ txdr->size = ALIGN(txdr->size, 4096);
+ if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size,
+ &txdr->dma))) {
ret_val = 2;
goto err_nomem;
}
@@ -1116,12 +1114,12 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter)
if (!rxdr->count)
rxdr->count = E1000_DEFAULT_RXD;
- size = rxdr->count * sizeof(struct e1000_buffer);
- if (!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+ if (!(rxdr->buffer_info = kcalloc(rxdr->count,
+ sizeof(struct e1000_buffer),
+ GFP_KERNEL))) {
ret_val = 4;
goto err_nomem;
}
- memset(rxdr->buffer_info, 0, size);
rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
if (!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) {
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 9267f16b1b32..3a03a74c0609 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -748,9 +748,9 @@ e1000_reset(struct e1000_adapter *adapter)
VLAN_TAG_SIZE;
min_tx_space = min_rx_space;
min_tx_space *= 2;
- E1000_ROUNDUP(min_tx_space, 1024);
+ min_tx_space = ALIGN(min_tx_space, 1024);
min_tx_space >>= 10;
- E1000_ROUNDUP(min_rx_space, 1024);
+ min_rx_space = ALIGN(min_rx_space, 1024);
min_rx_space >>= 10;
/* If current Tx allocation is less than the min Tx FIFO size,
@@ -1354,31 +1354,27 @@ e1000_sw_init(struct e1000_adapter *adapter)
static int __devinit
e1000_alloc_queues(struct e1000_adapter *adapter)
{
- int size;
-
- size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
- adapter->tx_ring = kmalloc(size, GFP_KERNEL);
+ adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+ sizeof(struct e1000_tx_ring), GFP_KERNEL);
if (!adapter->tx_ring)
return -ENOMEM;
- memset(adapter->tx_ring, 0, size);
- size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
- adapter->rx_ring = kmalloc(size, GFP_KERNEL);
+ adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+ sizeof(struct e1000_rx_ring), GFP_KERNEL);
if (!adapter->rx_ring) {
kfree(adapter->tx_ring);
return -ENOMEM;
}
- memset(adapter->rx_ring, 0, size);
#ifdef CONFIG_E1000_NAPI
- size = sizeof(struct net_device) * adapter->num_rx_queues;
- adapter->polling_netdev = kmalloc(size, GFP_KERNEL);
+ adapter->polling_netdev = kcalloc(adapter->num_rx_queues,
+ sizeof(struct net_device),
+ GFP_KERNEL);
if (!adapter->polling_netdev) {
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
return -ENOMEM;
}
- memset(adapter->polling_netdev, 0, size);
#endif
return E1000_SUCCESS;
@@ -1560,7 +1556,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter,
/* round up to nearest 4K */
txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
- E1000_ROUNDUP(txdr->size, 4096);
+ txdr->size = ALIGN(txdr->size, 4096);
txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
if (!txdr->desc) {
@@ -1774,18 +1770,18 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
}
memset(rxdr->buffer_info, 0, size);
- size = sizeof(struct e1000_ps_page) * rxdr->count;
- rxdr->ps_page = kmalloc(size, GFP_KERNEL);
+ rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct e1000_ps_page),
+ GFP_KERNEL);
if (!rxdr->ps_page) {
vfree(rxdr->buffer_info);
DPRINTK(PROBE, ERR,
"Unable to allocate memory for the receive descriptor ring\n");
return -ENOMEM;
}
- memset(rxdr->ps_page, 0, size);
- size = sizeof(struct e1000_ps_page_dma) * rxdr->count;
- rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL);
+ rxdr->ps_page_dma = kcalloc(rxdr->count,
+ sizeof(struct e1000_ps_page_dma),
+ GFP_KERNEL);
if (!rxdr->ps_page_dma) {
vfree(rxdr->buffer_info);
kfree(rxdr->ps_page);
@@ -1793,7 +1789,6 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
"Unable to allocate memory for the receive descriptor ring\n");
return -ENOMEM;
}
- memset(rxdr->ps_page_dma, 0, size);
if (adapter->hw.mac_type <= e1000_82547_rev_2)
desc_len = sizeof(struct e1000_rx_desc);
@@ -1803,7 +1798,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
/* Round up to nearest 4K */
rxdr->size = rxdr->count * desc_len;
- E1000_ROUNDUP(rxdr->size, 4096);
+ rxdr->size = ALIGN(rxdr->size, 4096);
rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
@@ -2667,7 +2662,7 @@ e1000_watchdog(unsigned long data)
netif_carrier_on(netdev);
netif_wake_queue(netdev);
- mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+ mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ));
adapter->smartspeed = 0;
} else {
/* make sure the receive unit is started */
@@ -2684,7 +2679,7 @@ e1000_watchdog(unsigned long data)
DPRINTK(LINK, INFO, "NIC Link is Down\n");
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+ mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ));
/* 80003ES2LAN workaround--
* For packet buffer work-around on link down event;
@@ -2736,7 +2731,7 @@ e1000_watchdog(unsigned long data)
e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
/* Reset the timer */
- mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+ mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ));
}
enum latency_range {
@@ -3175,7 +3170,7 @@ e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb)
uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head;
uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR;
- E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR);
+ skb_fifo_len = ALIGN(skb_fifo_len, E1000_FIFO_HDR);
if (adapter->link_duplex != HALF_DUPLEX)
goto no_fifo_stall_required;
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index f8862e203ac9..f485874a63f5 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -305,7 +305,7 @@ e1000_check_options(struct e1000_adapter *adapter)
if (num_TxDescriptors > bd) {
tx_ring->count = TxDescriptors[bd];
e1000_validate_option(&tx_ring->count, &opt, adapter);
- E1000_ROUNDUP(tx_ring->count,
+ tx_ring->count = ALIGN(tx_ring->count,
REQ_TX_DESCRIPTOR_MULTIPLE);
} else {
tx_ring->count = opt.def;
@@ -331,7 +331,7 @@ e1000_check_options(struct e1000_adapter *adapter)
if (num_RxDescriptors > bd) {
rx_ring->count = RxDescriptors[bd];
e1000_validate_option(&rx_ring->count, &opt, adapter);
- E1000_ROUNDUP(rx_ring->count,
+ rx_ring->count = ALIGN(rx_ring->count,
REQ_RX_DESCRIPTOR_MULTIPLE);
} else {
rx_ring->count = opt.def;
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 8aaf5ec0c360..7934ea37f944 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -115,6 +115,7 @@
#include <linux/mca-legacy.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
+#include <linux/jiffies.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -556,7 +557,7 @@ static void unstick_cu(struct net_device *dev)
if (lp->started)
{
- if ((jiffies - dev->trans_start)>50)
+ if (time_after(jiffies, dev->trans_start + 50))
{
if (lp->tx_link==lp->last_tx_restart)
{
@@ -612,7 +613,7 @@ static void unstick_cu(struct net_device *dev)
}
else
{
- if ((jiffies-lp->init_time)>10)
+ if (time_after(jiffies, lp->init_time + 10))
{
unsigned short status = scb_status(dev);
printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
@@ -776,7 +777,7 @@ static unsigned short eexp_start_irq(struct net_device *dev,
static void eexp_cmd_clear(struct net_device *dev)
{
unsigned long int oldtime = jiffies;
- while (scb_rdcmd(dev) && ((jiffies-oldtime)<10));
+ while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
if (scb_rdcmd(dev)) {
printk("%s: command didn't clear\n", dev->name);
}
@@ -1649,7 +1650,7 @@ eexp_set_multicast(struct net_device *dev)
#endif
oj = jiffies;
while ((SCB_CUstat(scb_status(dev)) == 2) &&
- ((jiffies-oj) < 2000));
+ (time_before(jiffies, oj + 2000)));
if (SCB_CUstat(scb_status(dev)) == 2)
printk("%s: warning, CU didn't stop\n", dev->name);
lp->started &= ~(STARTED_CU);
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 42295d61ecd8..602872dbe15f 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,7 +39,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0046"
+#define DRV_VERSION "EHEA_0058"
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -78,10 +78,7 @@
#define EHEA_RQ2_PKT_SIZE 1522
#define EHEA_L_PKT_SIZE 256 /* low latency */
-#define EHEA_POLL_MAX_RWQE 1000
-
/* Send completion signaling */
-#define EHEA_SIG_IV_LONG 1
/* Protection Domain Identifier */
#define EHEA_PD_ID 0xaabcdeff
@@ -108,11 +105,7 @@
#define EHEA_CACHE_LINE 128
/* Memory Regions */
-#define EHEA_MR_MAX_TX_PAGES 20
-#define EHEA_MR_TX_DATA_PN 3
#define EHEA_MR_ACC_CTRL 0x00800000
-#define EHEA_RWQES_PER_MR_RQ2 10
-#define EHEA_RWQES_PER_MR_RQ3 10
#define EHEA_WATCH_DOG_TIMEOUT 10*HZ
@@ -311,6 +304,7 @@ struct ehea_cq {
* Memory Region
*/
struct ehea_mr {
+ struct ehea_adapter *adapter;
u64 handle;
u64 vaddr;
u32 lkey;
@@ -319,17 +313,12 @@ struct ehea_mr {
/*
* Port state information
*/
-struct port_state {
- int poll_max_processed;
+struct port_stats {
int poll_receive_errors;
- int ehea_poll;
int queue_stopped;
- int min_swqe_avail;
- u64 sqc_stop_sum;
- int pkt_send;
- int pkt_xmit;
- int send_tasklet;
- int nwqe;
+ int err_tcp_cksum;
+ int err_ip_cksum;
+ int err_frame_crc;
};
#define EHEA_IRQ_NAME_SIZE 20
@@ -348,6 +337,7 @@ struct ehea_q_skb_arr {
* Port resources
*/
struct ehea_port_res {
+ struct port_stats p_stats;
struct ehea_mr send_mr; /* send memory region */
struct ehea_mr recv_mr; /* receive memory region */
spinlock_t xmit_lock;
@@ -357,9 +347,8 @@ struct ehea_port_res {
struct ehea_qp *qp;
struct ehea_cq *send_cq;
struct ehea_cq *recv_cq;
- struct ehea_eq *send_eq;
- struct ehea_eq *recv_eq;
- spinlock_t send_lock;
+ struct ehea_eq *eq;
+ struct net_device *d_netdev;
struct ehea_q_skb_arr rq1_skba;
struct ehea_q_skb_arr rq2_skba;
struct ehea_q_skb_arr rq3_skba;
@@ -369,21 +358,18 @@ struct ehea_port_res {
int swqe_refill_th;
atomic_t swqe_avail;
int swqe_ll_count;
- int swqe_count;
u32 swqe_id_counter;
u64 tx_packets;
- struct tasklet_struct send_comp_task;
- spinlock_t recv_lock;
- struct port_state p_state;
u64 rx_packets;
u32 poll_counter;
};
+#define EHEA_MAX_PORTS 16
struct ehea_adapter {
u64 handle;
- u8 num_ports;
- struct ehea_port *port[16];
+ struct ibmebus_dev *ebus_dev;
+ struct ehea_port *port[EHEA_MAX_PORTS];
struct ehea_eq *neq; /* notification event queue */
struct workqueue_struct *ehea_wq;
struct tasklet_struct neq_tasklet;
@@ -406,7 +392,7 @@ struct ehea_port {
struct net_device *netdev;
struct net_device_stats stats;
struct ehea_port_res port_res[EHEA_MAX_PORT_RES];
- struct device_node *of_dev_node; /* Open Firmware Device Node */
+ struct of_device ofdev; /* Open Firmware Device */
struct ehea_mc_list *mc_list; /* Multicast MAC addresses */
struct vlan_group *vgrp;
struct ehea_eq *qp_eq;
@@ -415,7 +401,9 @@ struct ehea_port {
char int_aff_name[EHEA_IRQ_NAME_SIZE];
int allmulti; /* Indicates IFF_ALLMULTI state */
int promisc; /* Indicates IFF_PROMISC state */
+ int num_tx_qps;
int num_add_tx_qps;
+ int num_mcs;
int resets;
u64 mac_addr;
u32 logical_port_id;
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index 9f57c2e78ced..decec8cfe96b 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -144,8 +144,8 @@ static int ehea_nway_reset(struct net_device *dev)
static void ehea_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strlcpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
- strlcpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
}
static u32 ehea_get_msglevel(struct net_device *dev)
@@ -166,33 +166,23 @@ static u32 ehea_get_rx_csum(struct net_device *dev)
}
static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
- {"poll_max_processed"},
- {"queue_stopped"},
- {"min_swqe_avail"},
- {"poll_receive_err"},
- {"pkt_send"},
- {"pkt_xmit"},
- {"send_tasklet"},
- {"ehea_poll"},
- {"nwqe"},
- {"swqe_available_0"},
{"sig_comp_iv"},
{"swqe_refill_th"},
{"port resets"},
- {"rxo"},
- {"rx64"},
- {"rx65"},
- {"rx128"},
- {"rx256"},
- {"rx512"},
- {"rx1024"},
- {"txo"},
- {"tx64"},
- {"tx65"},
- {"tx128"},
- {"tx256"},
- {"tx512"},
- {"tx1024"},
+ {"Receive errors"},
+ {"TCP cksum errors"},
+ {"IP cksum errors"},
+ {"Frame cksum errors"},
+ {"num SQ stopped"},
+ {"SQ stopped"},
+ {"PR0 free_swqes"},
+ {"PR1 free_swqes"},
+ {"PR2 free_swqes"},
+ {"PR3 free_swqes"},
+ {"PR4 free_swqes"},
+ {"PR5 free_swqes"},
+ {"PR6 free_swqes"},
+ {"PR7 free_swqes"},
};
static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -211,63 +201,44 @@ static int ehea_get_stats_count(struct net_device *dev)
static void ehea_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
- u64 hret;
- int i;
+ int i, k, tmp;
struct ehea_port *port = netdev_priv(dev);
- struct ehea_adapter *adapter = port->adapter;
- struct ehea_port_res *pr = &port->port_res[0];
- struct port_state *p_state = &pr->p_state;
- struct hcp_ehea_port_cb6 *cb6;
for (i = 0; i < ehea_get_stats_count(dev); i++)
data[i] = 0;
-
i = 0;
- data[i++] = p_state->poll_max_processed;
- data[i++] = p_state->queue_stopped;
- data[i++] = p_state->min_swqe_avail;
- data[i++] = p_state->poll_receive_errors;
- data[i++] = p_state->pkt_send;
- data[i++] = p_state->pkt_xmit;
- data[i++] = p_state->send_tasklet;
- data[i++] = p_state->ehea_poll;
- data[i++] = p_state->nwqe;
- data[i++] = atomic_read(&port->port_res[0].swqe_avail);
data[i++] = port->sig_comp_iv;
data[i++] = port->port_res[0].swqe_refill_th;
data[i++] = port->resets;
- cb6 = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (!cb6) {
- ehea_error("no mem for cb6");
- return;
- }
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp += port->port_res[k].p_stats.poll_receive_errors;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp += port->port_res[k].p_stats.err_tcp_cksum;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp += port->port_res[k].p_stats.err_ip_cksum;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp += port->port_res[k].p_stats.err_frame_crc;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp += port->port_res[k].p_stats.queue_stopped;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp |= port->port_res[k].queue_stopped;
+ data[i++] = tmp;
+
+ for (k = 0; k < 8; k++)
+ data[i++] = atomic_read(&port->port_res[k].swqe_avail);
- hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
- H_PORT_CB6, H_PORT_CB6_ALL, cb6);
- if (netif_msg_hw(port))
- ehea_dump(cb6, sizeof(*cb6), "ehea_get_ethtool_stats");
-
- if (hret == H_SUCCESS) {
- data[i++] = cb6->rxo;
- data[i++] = cb6->rx64;
- data[i++] = cb6->rx65;
- data[i++] = cb6->rx128;
- data[i++] = cb6->rx256;
- data[i++] = cb6->rx512;
- data[i++] = cb6->rx1024;
- data[i++] = cb6->txo;
- data[i++] = cb6->tx64;
- data[i++] = cb6->tx65;
- data[i++] = cb6->tx128;
- data[i++] = cb6->tx256;
- data[i++] = cb6->tx512;
- data[i++] = cb6->tx1024;
- } else
- ehea_error("query_ehea_port failed");
-
- kfree(cb6);
}
const struct ethtool_ops ehea_ethtool_ops = {
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 58364a0ff378..c7a5614e66c0 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -51,13 +51,18 @@ static int rq1_entries = EHEA_DEF_ENTRIES_RQ1;
static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
static int sq_entries = EHEA_DEF_ENTRIES_SQ;
+static int use_mcs = 0;
+static int num_tx_qps = EHEA_NUM_TX_QP;
module_param(msg_level, int, 0);
module_param(rq1_entries, int, 0);
module_param(rq2_entries, int, 0);
module_param(rq3_entries, int, 0);
module_param(sq_entries, int, 0);
+module_param(use_mcs, int, 0);
+module_param(num_tx_qps, int, 0);
+MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS");
MODULE_PARM_DESC(msg_level, "msg_level");
MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
"[2^x - 1], x = [6..14]. Default = "
@@ -71,6 +76,29 @@ MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
"[2^x - 1], x = [6..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
+MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 ");
+
+static int port_name_cnt = 0;
+
+static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
+ const struct of_device_id *id);
+
+static int __devexit ehea_remove(struct ibmebus_dev *dev);
+
+static struct of_device_id ehea_device_table[] = {
+ {
+ .name = "lhea",
+ .compatible = "IBM,lhea",
+ },
+ {},
+};
+
+static struct ibmebus_driver ehea_driver = {
+ .name = "ehea",
+ .id_table = ehea_device_table,
+ .probe = ehea_probe_adapter,
+ .remove = ehea_remove,
+};
void ehea_dump(void *adr, int len, char *msg) {
int x;
@@ -197,7 +225,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
struct sk_buff *skb = netdev_alloc_skb(dev, packet_size);
if (!skb) {
ehea_error("%s: no mem for skb/%d wqes filled",
- dev->name, i);
+ pr->port->netdev->name, i);
q_skba->os_skbs = fill_wqes - i;
ret = -ENOMEM;
break;
@@ -321,6 +349,13 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
{
struct sk_buff *skb;
+ if (cqe->status & EHEA_CQE_STAT_ERR_TCP)
+ pr->p_stats.err_tcp_cksum++;
+ if (cqe->status & EHEA_CQE_STAT_ERR_IP)
+ pr->p_stats.err_ip_cksum++;
+ if (cqe->status & EHEA_CQE_STAT_ERR_CRC)
+ pr->p_stats.err_frame_crc++;
+
if (netif_msg_rx_err(pr->port)) {
ehea_error("CQE Error for QP %d", pr->qp->init_attr.qp_nr);
ehea_dump(cqe, sizeof(*cqe), "CQE");
@@ -345,10 +380,11 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
return 0;
}
-static int ehea_poll(struct net_device *dev, int *budget)
+static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
+ struct ehea_port_res *pr,
+ int *budget)
{
- struct ehea_port *port = netdev_priv(dev);
- struct ehea_port_res *pr = &port->port_res[0];
+ struct ehea_port *port = pr->port;
struct ehea_qp *qp = pr->qp;
struct ehea_cqe *cqe;
struct sk_buff *skb;
@@ -359,14 +395,12 @@ static int ehea_poll(struct net_device *dev, int *budget)
int skb_arr_rq2_len = pr->rq2_skba.len;
int skb_arr_rq3_len = pr->rq3_skba.len;
int processed, processed_rq1, processed_rq2, processed_rq3;
- int wqe_index, last_wqe_index, rq, intreq, my_quota, port_reset;
+ int wqe_index, last_wqe_index, rq, my_quota, port_reset;
processed = processed_rq1 = processed_rq2 = processed_rq3 = 0;
last_wqe_index = 0;
my_quota = min(*budget, dev->quota);
- my_quota = min(my_quota, EHEA_POLL_MAX_RWQE);
- /* rq0 is low latency RQ */
cqe = ehea_poll_rq1(qp, &wqe_index);
while ((my_quota > 0) && cqe) {
ehea_inc_rq1(qp);
@@ -386,7 +420,8 @@ static int ehea_poll(struct net_device *dev, int *budget)
if (unlikely(!skb)) {
if (netif_msg_rx_err(port))
ehea_error("LL rq1: skb=NULL");
- skb = netdev_alloc_skb(dev,
+
+ skb = netdev_alloc_skb(port->netdev,
EHEA_L_PKT_SIZE);
if (!skb)
break;
@@ -402,7 +437,7 @@ static int ehea_poll(struct net_device *dev, int *budget)
ehea_error("rq2: skb=NULL");
break;
}
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(port->netdev, skb, cqe);
processed_rq2++;
} else { /* RQ3 */
skb = get_skb_by_index(skb_arr_rq3,
@@ -412,7 +447,7 @@ static int ehea_poll(struct net_device *dev, int *budget)
ehea_error("rq3: skb=NULL");
break;
}
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(port->netdev, skb, cqe);
processed_rq3++;
}
@@ -421,9 +456,8 @@ static int ehea_poll(struct net_device *dev, int *budget)
cqe->vlan_tag);
else
netif_receive_skb(skb);
-
- } else { /* Error occured */
- pr->p_state.poll_receive_errors++;
+ } else {
+ pr->p_stats.poll_receive_errors++;
port_reset = ehea_treat_poll_error(pr, rq, cqe,
&processed_rq2,
&processed_rq3);
@@ -433,72 +467,32 @@ static int ehea_poll(struct net_device *dev, int *budget)
cqe = ehea_poll_rq1(qp, &wqe_index);
}
- dev->quota -= processed;
- *budget -= processed;
-
- pr->p_state.ehea_poll += 1;
pr->rx_packets += processed;
+ *budget -= processed;
ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
ehea_refill_rq2(pr, processed_rq2);
ehea_refill_rq3(pr, processed_rq3);
- intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF);
-
- if (!cqe || intreq) {
- netif_rx_complete(dev);
- ehea_reset_cq_ep(pr->recv_cq);
- ehea_reset_cq_n1(pr->recv_cq);
- cqe = hw_qeit_get_valid(&qp->hw_rqueue1);
- if (!cqe || intreq)
- return 0;
- if (!netif_rx_reschedule(dev, my_quota))
- return 0;
- }
- return 1;
+ cqe = ehea_poll_rq1(qp, &wqe_index);
+ return cqe;
}
-void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr)
+static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
{
struct sk_buff *skb;
- int index, max_index_mask, i;
-
- index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
- max_index_mask = pr->sq_skba.len - 1;
- for (i = 0; i < EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); i++) {
- skb = pr->sq_skba.arr[index];
- if (likely(skb)) {
- dev_kfree_skb(skb);
- pr->sq_skba.arr[index] = NULL;
- } else {
- ehea_error("skb=NULL, wr_id=%lX, loop=%d, index=%d",
- cqe->wr_id, i, index);
- }
- index--;
- index &= max_index_mask;
- }
-}
-
-#define MAX_SENDCOMP_QUOTA 400
-void ehea_send_irq_tasklet(unsigned long data)
-{
- struct ehea_port_res *pr = (struct ehea_port_res*)data;
struct ehea_cq *send_cq = pr->send_cq;
struct ehea_cqe *cqe;
- int quota = MAX_SENDCOMP_QUOTA;
+ int quota = my_quota;
int cqe_counter = 0;
int swqe_av = 0;
+ int index;
unsigned long flags;
- do {
- cqe = ehea_poll_cq(send_cq);
- if (!cqe) {
- ehea_reset_cq_ep(send_cq);
- ehea_reset_cq_n1(send_cq);
- cqe = ehea_poll_cq(send_cq);
- if (!cqe)
- break;
- }
+ cqe = ehea_poll_cq(send_cq);
+ while(cqe && (quota > 0)) {
+ ehea_inc_cq(send_cq);
+
cqe_counter++;
rmb();
if (cqe->status & EHEA_CQE_STAT_ERR_MASK) {
@@ -514,17 +508,25 @@ void ehea_send_irq_tasklet(unsigned long data)
ehea_dump(cqe, sizeof(*cqe), "CQE");
if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id)
- == EHEA_SWQE2_TYPE))
- free_sent_skbs(cqe, pr);
+ == EHEA_SWQE2_TYPE)) {
+
+ index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
+ skb = pr->sq_skba.arr[index];
+ dev_kfree_skb(skb);
+ pr->sq_skba.arr[index] = NULL;
+ }
swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id);
quota--;
- } while (quota > 0);
+
+ cqe = ehea_poll_cq(send_cq);
+ };
ehea_update_feca(send_cq, cqe_counter);
atomic_add(swqe_av, &pr->swqe_avail);
spin_lock_irqsave(&pr->netif_queue, flags);
+
if (pr->queue_stopped && (atomic_read(&pr->swqe_avail)
>= pr->swqe_refill_th)) {
netif_wake_queue(pr->port->netdev);
@@ -532,22 +534,55 @@ void ehea_send_irq_tasklet(unsigned long data)
}
spin_unlock_irqrestore(&pr->netif_queue, flags);
- if (unlikely(cqe))
- tasklet_hi_schedule(&pr->send_comp_task);
+ return cqe;
}
-static irqreturn_t ehea_send_irq_handler(int irq, void *param)
+#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16
+
+static int ehea_poll(struct net_device *dev, int *budget)
{
- struct ehea_port_res *pr = param;
- tasklet_hi_schedule(&pr->send_comp_task);
- return IRQ_HANDLED;
+ struct ehea_port_res *pr = dev->priv;
+ struct ehea_cqe *cqe;
+ struct ehea_cqe *cqe_skb = NULL;
+ int force_irq, wqe_index;
+
+ cqe = ehea_poll_rq1(pr->qp, &wqe_index);
+ cqe_skb = ehea_poll_cq(pr->send_cq);
+
+ force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ);
+
+ if ((!cqe && !cqe_skb) || force_irq) {
+ pr->poll_counter = 0;
+ netif_rx_complete(dev);
+ ehea_reset_cq_ep(pr->recv_cq);
+ ehea_reset_cq_ep(pr->send_cq);
+ ehea_reset_cq_n1(pr->recv_cq);
+ ehea_reset_cq_n1(pr->send_cq);
+ cqe = ehea_poll_rq1(pr->qp, &wqe_index);
+ cqe_skb = ehea_poll_cq(pr->send_cq);
+
+ if (!cqe && !cqe_skb)
+ return 0;
+
+ if (!netif_rx_reschedule(dev, dev->quota))
+ return 0;
+ }
+
+ cqe = ehea_proc_rwqes(dev, pr, budget);
+ cqe_skb = ehea_proc_cqes(pr, 300);
+
+ if (cqe || cqe_skb)
+ pr->poll_counter++;
+
+ return 1;
}
static irqreturn_t ehea_recv_irq_handler(int irq, void *param)
{
struct ehea_port_res *pr = param;
- struct ehea_port *port = pr->port;
- netif_rx_schedule(port->netdev);
+
+ netif_rx_schedule(pr->d_netdev);
+
return IRQ_HANDLED;
}
@@ -580,7 +615,7 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
{
int i;
- for (i = 0; i < adapter->num_ports; i++)
+ for (i = 0; i < EHEA_MAX_PORTS; i++)
if (adapter->port[i])
if (adapter->port[i]->logical_port_id == logical_port)
return adapter->port[i];
@@ -650,19 +685,25 @@ int ehea_sense_port_attr(struct ehea_port *port)
}
port->autoneg = 1;
+ port->num_mcs = cb0->num_default_qps;
/* Number of default QPs */
- port->num_def_qps = cb0->num_default_qps;
+ if (use_mcs)
+ port->num_def_qps = cb0->num_default_qps;
+ else
+ port->num_def_qps = 1;
if (!port->num_def_qps) {
ret = -EINVAL;
goto out_free;
}
- if (port->num_def_qps >= EHEA_NUM_TX_QP)
+ port->num_tx_qps = num_tx_qps;
+
+ if (port->num_def_qps >= port->num_tx_qps)
port->num_add_tx_qps = 0;
else
- port->num_add_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps;
+ port->num_add_tx_qps = port->num_tx_qps - port->num_def_qps;
ret = 0;
out_free:
@@ -882,23 +923,6 @@ static int ehea_reg_interrupts(struct net_device *dev)
struct ehea_port_res *pr;
int i, ret;
- for (i = 0; i < port->num_def_qps; i++) {
- pr = &port->port_res[i];
- snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1
- , "%s-recv%d", dev->name, i);
- ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1,
- ehea_recv_irq_handler,
- IRQF_DISABLED, pr->int_recv_name, pr);
- if (ret) {
- ehea_error("failed registering irq for ehea_recv_int:"
- "port_res_nr:%d, ist=%X", i,
- pr->recv_eq->attr.ist1);
- goto out_free_seq;
- }
- if (netif_msg_ifup(port))
- ehea_info("irq_handle 0x%X for funct ehea_recv_int %d "
- "registered", pr->recv_eq->attr.ist1, i);
- }
snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff",
dev->name);
@@ -916,41 +940,41 @@ static int ehea_reg_interrupts(struct net_device *dev)
ehea_info("irq_handle 0x%X for function qp_aff_irq_handler "
"registered", port->qp_eq->attr.ist1);
+
for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
pr = &port->port_res[i];
snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
- "%s-send%d", dev->name, i);
- ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1,
- ehea_send_irq_handler,
+ "%s-queue%d", dev->name, i);
+ ret = ibmebus_request_irq(NULL, pr->eq->attr.ist1,
+ ehea_recv_irq_handler,
IRQF_DISABLED, pr->int_send_name,
pr);
if (ret) {
- ehea_error("failed registering irq for ehea_send "
+ ehea_error("failed registering irq for ehea_queue "
"port_res_nr:%d, ist=%X", i,
- pr->send_eq->attr.ist1);
+ pr->eq->attr.ist1);
goto out_free_req;
}
if (netif_msg_ifup(port))
- ehea_info("irq_handle 0x%X for function ehea_send_int "
- "%d registered", pr->send_eq->attr.ist1, i);
+ ehea_info("irq_handle 0x%X for function ehea_queue_int "
+ "%d registered", pr->eq->attr.ist1, i);
}
out:
return ret;
+
out_free_req:
while (--i >= 0) {
- u32 ist = port->port_res[i].send_eq->attr.ist1;
+ u32 ist = port->port_res[i].eq->attr.ist1;
ibmebus_free_irq(NULL, ist, &port->port_res[i]);
}
+
out_free_qpeq:
ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
i = port->num_def_qps;
-out_free_seq:
- while (--i >= 0) {
- u32 ist = port->port_res[i].recv_eq->attr.ist1;
- ibmebus_free_irq(NULL, ist, &port->port_res[i]);
- }
+
goto out;
+
}
static void ehea_free_interrupts(struct net_device *dev)
@@ -960,21 +984,13 @@ static void ehea_free_interrupts(struct net_device *dev)
int i;
/* send */
+
for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
pr = &port->port_res[i];
- ibmebus_free_irq(NULL, pr->send_eq->attr.ist1, pr);
+ ibmebus_free_irq(NULL, pr->eq->attr.ist1, pr);
if (netif_msg_intr(port))
ehea_info("free send irq for res %d with handle 0x%X",
- i, pr->send_eq->attr.ist1);
- }
-
- /* receive */
- for (i = 0; i < port->num_def_qps; i++) {
- pr = &port->port_res[i];
- ibmebus_free_irq(NULL, pr->recv_eq->attr.ist1, pr);
- if (netif_msg_intr(port))
- ehea_info("free recv irq for res %d with handle 0x%X",
- i, pr->recv_eq->attr.ist1);
+ i, pr->eq->attr.ist1);
}
/* associated events */
@@ -1003,8 +1019,13 @@ static int ehea_configure_port(struct ehea_port *port)
PXLY_RC_VLAN_FILTER)
| EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1);
- for (i = 0; i < port->num_def_qps; i++)
- cb0->default_qpn_arr[i] = port->port_res[0].qp->init_attr.qp_nr;
+ for (i = 0; i < port->num_mcs; i++)
+ if (use_mcs)
+ cb0->default_qpn_arr[i] =
+ port->port_res[i].qp->init_attr.qp_nr;
+ else
+ cb0->default_qpn_arr[i] =
+ port->port_res[0].qp->init_attr.qp_nr;
if (netif_msg_ifup(port))
ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port");
@@ -1027,52 +1048,35 @@ out:
return ret;
}
-static int ehea_gen_smrs(struct ehea_port_res *pr)
+int ehea_gen_smrs(struct ehea_port_res *pr)
{
- u64 hret;
+ int ret;
struct ehea_adapter *adapter = pr->port->adapter;
- hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle,
- adapter->mr.vaddr, EHEA_MR_ACC_CTRL,
- adapter->pd, &pr->send_mr);
- if (hret != H_SUCCESS)
+ ret = ehea_gen_smr(adapter, &adapter->mr, &pr->send_mr);
+ if (ret)
goto out;
- hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle,
- adapter->mr.vaddr, EHEA_MR_ACC_CTRL,
- adapter->pd, &pr->recv_mr);
- if (hret != H_SUCCESS)
- goto out_freeres;
+ ret = ehea_gen_smr(adapter, &adapter->mr, &pr->recv_mr);
+ if (ret)
+ goto out_free;
return 0;
-out_freeres:
- hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle);
- if (hret != H_SUCCESS)
- ehea_error("failed freeing SMR");
+out_free:
+ ehea_rem_mr(&pr->send_mr);
out:
+ ehea_error("Generating SMRS failed\n");
return -EIO;
}
-static int ehea_rem_smrs(struct ehea_port_res *pr)
+int ehea_rem_smrs(struct ehea_port_res *pr)
{
- struct ehea_adapter *adapter = pr->port->adapter;
- int ret = 0;
- u64 hret;
-
- hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle);
- if (hret != H_SUCCESS) {
- ret = -EIO;
- ehea_error("failed freeing send SMR for pr=%p", pr);
- }
-
- hret = ehea_h_free_resource(adapter->handle, pr->recv_mr.handle);
- if (hret != H_SUCCESS) {
- ret = -EIO;
- ehea_error("failed freeing recv SMR for pr=%p", pr);
- }
-
- return ret;
+ if ((ehea_rem_mr(&pr->send_mr))
+ || (ehea_rem_mr(&pr->recv_mr)))
+ return -EIO;
+ else
+ return 0;
}
static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
@@ -1103,25 +1107,17 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
memset(pr, 0, sizeof(struct ehea_port_res));
pr->port = port;
- spin_lock_init(&pr->send_lock);
- spin_lock_init(&pr->recv_lock);
spin_lock_init(&pr->xmit_lock);
spin_lock_init(&pr->netif_queue);
- pr->recv_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
- if (!pr->recv_eq) {
- ehea_error("create_eq failed (recv_eq)");
- goto out_free;
- }
-
- pr->send_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
- if (!pr->send_eq) {
- ehea_error("create_eq failed (send_eq)");
+ pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
+ if (!pr->eq) {
+ ehea_error("create_eq failed (eq)");
goto out_free;
}
pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq,
- pr->recv_eq->fw_handle,
+ pr->eq->fw_handle,
port->logical_port_id);
if (!pr->recv_cq) {
ehea_error("create_cq failed (cq_recv)");
@@ -1129,7 +1125,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
}
pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq,
- pr->send_eq->fw_handle,
+ pr->eq->fw_handle,
port->logical_port_id);
if (!pr->send_cq) {
ehea_error("create_cq failed (cq_send)");
@@ -1194,11 +1190,20 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
ret = -EIO;
goto out_free;
}
- tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet,
- (unsigned long)pr);
+
atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1);
kfree(init_attr);
+
+ pr->d_netdev = alloc_netdev(0, "", ether_setup);
+ if (!pr->d_netdev)
+ goto out_free;
+ pr->d_netdev->priv = pr;
+ pr->d_netdev->weight = 64;
+ pr->d_netdev->poll = ehea_poll;
+ set_bit(__LINK_STATE_START, &pr->d_netdev->state);
+ strcpy(pr->d_netdev->name, port->netdev->name);
+
ret = 0;
goto out;
@@ -1211,8 +1216,7 @@ out_free:
ehea_destroy_qp(pr->qp);
ehea_destroy_cq(pr->send_cq);
ehea_destroy_cq(pr->recv_cq);
- ehea_destroy_eq(pr->send_eq);
- ehea_destroy_eq(pr->recv_eq);
+ ehea_destroy_eq(pr->eq);
out:
return ret;
}
@@ -1221,13 +1225,14 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
{
int ret, i;
+ free_netdev(pr->d_netdev);
+
ret = ehea_destroy_qp(pr->qp);
if (!ret) {
ehea_destroy_cq(pr->send_cq);
ehea_destroy_cq(pr->recv_cq);
- ehea_destroy_eq(pr->send_eq);
- ehea_destroy_eq(pr->recv_eq);
+ ehea_destroy_eq(pr->eq);
for (i = 0; i < pr->rq1_skba.len; i++)
if (pr->rq1_skba.arr[i])
@@ -1792,6 +1797,22 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
dev_kfree_skb(skb);
}
+static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps)
+{
+ struct tcphdr *tcp;
+ u32 tmp;
+
+ if ((skb->protocol == htons(ETH_P_IP)) &&
+ (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;
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index bc3c00547264..95c4a7f9cc88 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -478,12 +478,14 @@ u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle)
0, 0, 0, 0, 0, 0); /* R7-R12 */
}
-u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle)
+u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
+ u64 force_bit)
{
return ehea_plpar_hcall_norets(H_FREE_RESOURCE,
adapter_handle, /* R4 */
res_handle, /* R5 */
- 0, 0, 0, 0, 0); /* R6-R10 */
+ force_bit,
+ 0, 0, 0, 0); /* R7-R10 */
}
u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index 90acddb068a1..d17a45a7e717 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -414,7 +414,11 @@ u64 ehea_h_register_rpage(const u64 adapter_handle,
u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle);
-u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle);
+#define FORCE_FREE 1
+#define NORMAL_FREE 0
+
+u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
+ u64 force_bit);
u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
const u64 length, const u32 access_ctrl,
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index 96ff3b679996..f24a8862977d 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -197,7 +197,7 @@ out_kill_hwq:
hw_queue_dtor(&cq->hw_queue);
out_freeres:
- ehea_h_free_resource(adapter->handle, cq->fw_handle);
+ ehea_h_free_resource(adapter->handle, cq->fw_handle, FORCE_FREE);
out_freemem:
kfree(cq);
@@ -206,25 +206,38 @@ out_nomem:
return NULL;
}
-int ehea_destroy_cq(struct ehea_cq *cq)
+u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
{
- u64 adapter_handle, hret;
+ u64 hret;
+ u64 adapter_handle = cq->adapter->handle;
+
+ /* deregister all previous registered pages */
+ hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force);
+ if (hret != H_SUCCESS)
+ return hret;
+
+ hw_queue_dtor(&cq->hw_queue);
+ kfree(cq);
+
+ return hret;
+}
+int ehea_destroy_cq(struct ehea_cq *cq)
+{
+ u64 hret;
if (!cq)
return 0;
- adapter_handle = cq->adapter->handle;
+ if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) {
+ ehea_error_data(cq->adapter, cq->fw_handle);
+ hret = ehea_destroy_cq_res(cq, FORCE_FREE);
+ }
- /* deregister all previous registered pages */
- hret = ehea_h_free_resource(adapter_handle, cq->fw_handle);
if (hret != H_SUCCESS) {
ehea_error("destroy CQ failed");
return -EIO;
}
- hw_queue_dtor(&cq->hw_queue);
- kfree(cq);
-
return 0;
}
@@ -297,7 +310,7 @@ out_kill_hwq:
hw_queue_dtor(&eq->hw_queue);
out_freeres:
- ehea_h_free_resource(adapter->handle, eq->fw_handle);
+ ehea_h_free_resource(adapter->handle, eq->fw_handle, FORCE_FREE);
out_freemem:
kfree(eq);
@@ -316,27 +329,41 @@ struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
return eqe;
}
-int ehea_destroy_eq(struct ehea_eq *eq)
+u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
{
u64 hret;
unsigned long flags;
- if (!eq)
- return 0;
-
spin_lock_irqsave(&eq->spinlock, flags);
- hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle);
+ hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle, force);
spin_unlock_irqrestore(&eq->spinlock, flags);
- if (hret != H_SUCCESS) {
- ehea_error("destroy_eq failed");
- return -EIO;
- }
+ if (hret != H_SUCCESS)
+ return hret;
hw_queue_dtor(&eq->hw_queue);
kfree(eq);
+ return hret;
+}
+
+int ehea_destroy_eq(struct ehea_eq *eq)
+{
+ u64 hret;
+ if (!eq)
+ return 0;
+
+ if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) {
+ ehea_error_data(eq->adapter, eq->fw_handle);
+ hret = ehea_destroy_eq_res(eq, FORCE_FREE);
+ }
+
+ if (hret != H_SUCCESS) {
+ ehea_error("destroy EQ failed");
+ return -EIO;
+ }
+
return 0;
}
@@ -471,41 +498,56 @@ out_kill_hwsq:
out_freeres:
ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle);
- ehea_h_free_resource(adapter->handle, qp->fw_handle);
+ ehea_h_free_resource(adapter->handle, qp->fw_handle, FORCE_FREE);
out_freemem:
kfree(qp);
return NULL;
}
-int ehea_destroy_qp(struct ehea_qp *qp)
+u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
{
- u64 hret;
- struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
+ u64 hret;
+ struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
- if (!qp)
- return 0;
- ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
- hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle);
- if (hret != H_SUCCESS) {
- ehea_error("destroy_qp failed");
- return -EIO;
- }
+ ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
+ hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force);
+ if (hret != H_SUCCESS)
+ return hret;
- hw_queue_dtor(&qp->hw_squeue);
- hw_queue_dtor(&qp->hw_rqueue1);
+ hw_queue_dtor(&qp->hw_squeue);
+ hw_queue_dtor(&qp->hw_rqueue1);
- if (qp_attr->rq_count > 1)
- hw_queue_dtor(&qp->hw_rqueue2);
- if (qp_attr->rq_count > 2)
- hw_queue_dtor(&qp->hw_rqueue3);
- kfree(qp);
+ if (qp_attr->rq_count > 1)
+ hw_queue_dtor(&qp->hw_rqueue2);
+ if (qp_attr->rq_count > 2)
+ hw_queue_dtor(&qp->hw_rqueue3);
+ kfree(qp);
- return 0;
+ return hret;
}
-int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
+int ehea_destroy_qp(struct ehea_qp *qp)
+{
+ u64 hret;
+ if (!qp)
+ return 0;
+
+ if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
+ ehea_error_data(qp->adapter, qp->fw_handle);
+ hret = ehea_destroy_qp_res(qp, FORCE_FREE);
+ }
+
+ if (hret != H_SUCCESS) {
+ ehea_error("destroy QP failed");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
{
int i, k, ret;
u64 hret, pt_abs, start, end, nr_pages;
@@ -526,14 +568,14 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start,
acc_ctrl, adapter->pd,
- &adapter->mr.handle, &adapter->mr.lkey);
+ &mr->handle, &mr->lkey);
if (hret != H_SUCCESS) {
ehea_error("alloc_resource_mr failed");
ret = -EIO;
goto out;
}
- adapter->mr.vaddr = KERNELBASE;
+ mr->vaddr = KERNELBASE;
k = 0;
while (nr_pages > 0) {
@@ -545,7 +587,7 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
EHEA_PAGESIZE)));
hret = ehea_h_register_rpage_mr(adapter->handle,
- adapter->mr.handle, 0,
+ mr->handle, 0,
0, (u64)pt_abs,
num_pages);
nr_pages -= num_pages;
@@ -554,34 +596,68 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
(k * EHEA_PAGESIZE)));
hret = ehea_h_register_rpage_mr(adapter->handle,
- adapter->mr.handle, 0,
+ mr->handle, 0,
0, abs_adr,1);
nr_pages--;
}
if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) {
ehea_h_free_resource(adapter->handle,
- adapter->mr.handle);
- ehea_error("register_rpage_mr failed: hret = %lX",
- hret);
+ mr->handle, FORCE_FREE);
+ ehea_error("register_rpage_mr failed");
ret = -EIO;
goto out;
}
}
if (hret != H_SUCCESS) {
- ehea_h_free_resource(adapter->handle, adapter->mr.handle);
- ehea_error("register_rpage failed for last page: hret = %lX",
- hret);
+ ehea_h_free_resource(adapter->handle, mr->handle,
+ FORCE_FREE);
+ ehea_error("register_rpage failed for last page");
ret = -EIO;
goto out;
}
+
+ mr->adapter = adapter;
ret = 0;
out:
kfree(pt);
return ret;
}
+int ehea_rem_mr(struct ehea_mr *mr)
+{
+ u64 hret;
+
+ if (!mr || !mr->adapter)
+ return -EINVAL;
+
+ hret = ehea_h_free_resource(mr->adapter->handle, mr->handle,
+ FORCE_FREE);
+ if (hret != H_SUCCESS) {
+ ehea_error("destroy MR failed");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
+ struct ehea_mr *shared_mr)
+{
+ u64 hret;
+
+ hret = ehea_h_register_smr(adapter->handle, old_mr->handle,
+ old_mr->vaddr, EHEA_MR_ACC_CTRL,
+ adapter->pd, shared_mr);
+ if (hret != H_SUCCESS)
+ return -EIO;
+
+ shared_mr->adapter = adapter;
+
+ return 0;
+}
+
void print_error_data(u64 *data)
{
int length;
@@ -597,6 +673,14 @@ void print_error_data(u64 *data)
ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, "
"port=%lX", resource, data[6], data[12], data[22]);
+ if (type == 0x4) /* Completion Queue */
+ ehea_error("CQ (resource=%lX) state: AER=0x%lX", resource,
+ data[6]);
+
+ if (type == 0x3) /* Event Queue */
+ ehea_error("EQ (resource=%lX) state: AER=0x%lX", resource,
+ data[6]);
+
ehea_dump(data, length, "error data");
}
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 1ff60983504d..c0eb3e03a102 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -142,6 +142,8 @@ struct ehea_rwqe {
#define EHEA_CQE_STAT_ERR_MASK 0x721F
#define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F
#define EHEA_CQE_STAT_ERR_TCP 0x4000
+#define EHEA_CQE_STAT_ERR_IP 0x2000
+#define EHEA_CQE_STAT_ERR_CRC 0x1000
struct ehea_cqe {
u64 wr_id; /* work request ID from WQE */
@@ -320,6 +322,11 @@ static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index)
return hw_qeit_get_valid(queue);
}
+static inline void ehea_inc_cq(struct ehea_cq *cq)
+{
+ hw_qeit_inc(&cq->hw_queue);
+}
+
static inline void ehea_inc_rq1(struct ehea_qp *qp)
{
hw_qeit_inc(&qp->hw_rqueue1);
@@ -327,7 +334,7 @@ static inline void ehea_inc_rq1(struct ehea_qp *qp)
static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq)
{
- return hw_qeit_get_inc_valid(&my_cq->hw_queue);
+ return hw_qeit_get_valid(&my_cq->hw_queue);
}
#define EHEA_CQ_REGISTER_ORIG 0
@@ -356,7 +363,12 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter, u32 pd,
int ehea_destroy_qp(struct ehea_qp *qp);
-int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
+int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr);
+
+int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
+ struct ehea_mr *shared_mr);
+
+int ehea_rem_mr(struct ehea_mr *mr);
void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index 30baf6ecfc63..17ac6975d70d 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -415,11 +415,18 @@ static int ser12_open(struct net_device *dev)
if (!dev || !bc)
return -ENXIO;
- if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT ||
- dev->irq < 2 || dev->irq > 15)
+ if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT ||
+ dev->irq < 2 || dev->irq > NR_IRQS) {
+ printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) "
+ "or irq (2 <= irq <= %d)\n",
+ 0xffff-SER12_EXTENT, NR_IRQS);
return -ENXIO;
- if (bc->baud < 300 || bc->baud > 4800)
+ }
+ if (bc->baud < 300 || bc->baud > 4800) {
+ printk(KERN_INFO "baycom_ser_fdx: invalid baudrate "
+ "(300...4800)\n");
return -EINVAL;
+ }
if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) {
printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy \n",
dev->base_addr);
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 0573fcfcb2c4..3bec0f733f01 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -93,7 +93,7 @@ static void ibmveth_proc_unregister_driver(void);
static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter);
static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter);
static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance);
-static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
+static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
static struct kobj_type ktype_veth_pool;
#ifdef CONFIG_PROC_FS
@@ -389,7 +389,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
}
}
-static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
+static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
{
ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
@@ -953,14 +953,16 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n",
dev->unit_address);
- mac_addr_p = (unsigned char *) vio_get_attribute(dev, VETH_MAC_ADDR, 0);
+ mac_addr_p = (unsigned char *) vio_get_attribute(dev,
+ VETH_MAC_ADDR, NULL);
if(!mac_addr_p) {
printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR "
"attribute\n", __FILE__, __LINE__);
return 0;
}
- mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0);
+ mcastFilterSize_p = (unsigned int *) vio_get_attribute(dev,
+ VETH_MCAST_FILTER_SIZE, NULL);
if(!mcastFilterSize_p) {
printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find "
"VETH_MCAST_FILTER_SIZE attribute\n",
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index cf30a1059ce0..c8e90861f869 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -111,9 +111,6 @@ struct ixgb_adapter;
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define IXGB_RX_BUFFER_WRITE 8 /* Must be power of 2 */
-/* only works for sizes that are powers of 2 */
-#define IXGB_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
-
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct ixgb_buffer {
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index d6628bd9590a..afde84868bea 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -577,11 +577,11 @@ ixgb_set_ringparam(struct net_device *netdev,
rxdr->count = max(ring->rx_pending,(uint32_t)MIN_RXD);
rxdr->count = min(rxdr->count,(uint32_t)MAX_RXD);
- IXGB_ROUNDUP(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
+ rxdr->count = ALIGN(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
txdr->count = max(ring->tx_pending,(uint32_t)MIN_TXD);
txdr->count = min(txdr->count,(uint32_t)MAX_TXD);
- IXGB_ROUNDUP(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
+ txdr->count = ALIGN(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
if(netif_running(adapter->netdev)) {
/* Try to get new resources before deleting old */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index dfde80e54aef..6d2b059371f1 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -685,7 +685,7 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter)
/* round up to nearest 4K */
txdr->size = txdr->count * sizeof(struct ixgb_tx_desc);
- IXGB_ROUNDUP(txdr->size, 4096);
+ txdr->size = ALIGN(txdr->size, 4096);
txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
if(!txdr->desc) {
@@ -774,7 +774,7 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter)
/* Round up to nearest 4K */
rxdr->size = rxdr->count * sizeof(struct ixgb_rx_desc);
- IXGB_ROUNDUP(rxdr->size, 4096);
+ rxdr->size = ALIGN(rxdr->size, 4096);
rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c
index b27442a121f2..5d5ddabf4360 100644
--- a/drivers/net/ixgb/ixgb_param.c
+++ b/drivers/net/ixgb/ixgb_param.c
@@ -245,8 +245,6 @@ ixgb_validate_option(int *value, struct ixgb_option *opt)
return -1;
}
-#define LIST_LEN(l) (sizeof(l) / sizeof(l[0]))
-
/**
* ixgb_check_options - Range Checking for Command Line Parameters
* @adapter: board private structure
@@ -284,7 +282,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
} else {
tx_ring->count = opt.def;
}
- IXGB_ROUNDUP(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
+ tx_ring->count = ALIGN(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
}
{ /* Receive Descriptor Count */
struct ixgb_option opt = {
@@ -303,7 +301,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
} else {
rx_ring->count = opt.def;
}
- IXGB_ROUNDUP(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
+ rx_ring->count = ALIGN(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
}
{ /* Receive Checksum Offload Enable */
struct ixgb_option opt = {
@@ -335,7 +333,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
.name = "Flow Control",
.err = "reading default settings from EEPROM",
.def = ixgb_fc_tx_pause,
- .arg = { .l = { .nr = LIST_LEN(fc_list),
+ .arg = { .l = { .nr = ARRAY_SIZE(fc_list),
.p = fc_list }}
};
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index 2912a34f597b..92056051f269 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -33,6 +33,13 @@
#include <linux/ethtool.h>
#include <linux/mii.h>
+/**
+ * mii_ethtool_gset - get settings that are specified in @ecmd
+ * @mii: MII interface
+ * @ecmd: requested ethtool_cmd
+ *
+ * Returns 0 for success, negative on error.
+ */
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
struct net_device *dev = mii->dev;
@@ -114,6 +121,13 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
return 0;
}
+/**
+ * mii_ethtool_sset - set settings that are specified in @ecmd
+ * @mii: MII interface
+ * @ecmd: requested ethtool_cmd
+ *
+ * Returns 0 for success, negative on error.
+ */
int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
struct net_device *dev = mii->dev;
@@ -207,6 +221,10 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
return 0;
}
+/**
+ * mii_check_gmii_support - check if the MII supports Gb interfaces
+ * @mii: the MII interface
+ */
int mii_check_gmii_support(struct mii_if_info *mii)
{
int reg;
@@ -221,6 +239,12 @@ int mii_check_gmii_support(struct mii_if_info *mii)
return 0;
}
+/**
+ * mii_link_ok - is link status up/ok
+ * @mii: the MII interface
+ *
+ * Returns 1 if the MII reports link status up/ok, 0 otherwise.
+ */
int mii_link_ok (struct mii_if_info *mii)
{
/* first, a dummy read, needed to latch some MII phys */
@@ -230,6 +254,12 @@ int mii_link_ok (struct mii_if_info *mii)
return 0;
}
+/**
+ * mii_nway_restart - restart NWay (autonegotiation) for this interface
+ * @mii: the MII interface
+ *
+ * Returns 0 on success, negative on error.
+ */
int mii_nway_restart (struct mii_if_info *mii)
{
int bmcr;
@@ -247,6 +277,14 @@ int mii_nway_restart (struct mii_if_info *mii)
return r;
}
+/**
+ * mii_check_link - check MII link status
+ * @mii: MII interface
+ *
+ * If the link status changed (previous != current), call
+ * netif_carrier_on() if current link status is Up or call
+ * netif_carrier_off() if current link status is Down.
+ */
void mii_check_link (struct mii_if_info *mii)
{
int cur_link = mii_link_ok(mii);
@@ -258,6 +296,15 @@ void mii_check_link (struct mii_if_info *mii)
netif_carrier_off(mii->dev);
}
+/**
+ * mii_check_media - check the MII interface for a duplex change
+ * @mii: the MII interface
+ * @ok_to_print: OK to print link up/down messages
+ * @init_media: OK to save duplex mode in @mii
+ *
+ * Returns 1 if the duplex mode changed, 0 if not.
+ * If the media type is forced, always returns 0.
+ */
unsigned int mii_check_media (struct mii_if_info *mii,
unsigned int ok_to_print,
unsigned int init_media)
@@ -326,6 +373,16 @@ unsigned int mii_check_media (struct mii_if_info *mii,
return 0; /* duplex did not change */
}
+/**
+ * generic_mii_ioctl - main MII ioctl interface
+ * @mii_if: the MII interface
+ * @mii_data: MII ioctl data structure
+ * @cmd: MII ioctl command
+ * @duplex_chg_out: pointer to @duplex_changed status if there was no
+ * ioctl error
+ *
+ * Returns 0 on success, negative on error.
+ */
int generic_mii_ioctl(struct mii_if_info *mii_if,
struct mii_ioctl_data *mii_data, int cmd,
unsigned int *duplex_chg_out)
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index 403f63afd201..638a279ec505 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -26,8 +26,6 @@ struct mipsnet_priv {
struct net_device_stats stats;
};
-static struct platform_device *mips_plat_dev;
-
static char mipsnet_string[] = "mipsnet";
/*
@@ -297,64 +295,17 @@ static struct device_driver mipsnet_driver = {
.remove = __devexit_p(mipsnet_device_remove),
};
-static void mipsnet_platform_release(struct device *device)
-{
- struct platform_device *pldev;
-
- /* free device */
- pldev = to_platform_device(device);
- kfree(pldev);
-}
-
static int __init mipsnet_init_module(void)
{
- struct platform_device *pldev;
int err;
printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. "
"(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION);
- if (driver_register(&mipsnet_driver)) {
+ err = driver_register(&mipsnet_driver);
+ if (err)
printk(KERN_ERR "Driver registration failed\n");
- err = -ENODEV;
- goto out;
- }
-
- if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) {
- err = -ENOMEM;
- goto out_unregister_driver;
- }
-
- memset (pldev, 0, sizeof (*pldev));
- pldev->name = mipsnet_string;
- pldev->id = 0;
- pldev->dev.release = mipsnet_platform_release;
- if (platform_device_register(pldev)) {
- err = -ENODEV;
- goto out_free_pldev;
- }
-
- if (!pldev->dev.driver) {
- /*
- * The driver was not bound to this device, there was
- * no hardware at this address. Unregister it, as the
- * release fuction will take care of freeing the
- * allocated structure
- */
- platform_device_unregister (pldev);
- }
-
- mips_plat_dev = pldev;
-
- return 0;
-
-out_free_pldev:
- kfree(pldev);
-
-out_unregister_driver:
- driver_unregister(&mipsnet_driver);
-out:
return err;
}
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index ab15ecd4b3d6..1799eee88db7 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -51,8 +51,8 @@
#include "mv643xx_eth.h"
/* Static function declarations */
-static void eth_port_uc_addr_get(struct net_device *dev,
- unsigned char *MacAddr);
+static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr);
+static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr);
static void eth_port_set_multicast_list(struct net_device *);
static void mv643xx_eth_port_enable_tx(unsigned int port_num,
unsigned int queues);
@@ -1381,7 +1381,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
port_num = mp->port_num = pd->port_number;
/* set default config values */
- eth_port_uc_addr_get(dev, dev->dev_addr);
+ eth_port_uc_addr_get(port_num, dev->dev_addr);
mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE;
@@ -1839,26 +1839,9 @@ static void eth_port_start(struct net_device *dev)
}
/*
- * eth_port_uc_addr_set - This function Set the port Unicast address.
- *
- * DESCRIPTION:
- * This function Set the port Ethernet MAC address.
- *
- * INPUT:
- * unsigned int eth_port_num Port number.
- * char * p_addr Address to be set
- *
- * OUTPUT:
- * Set MAC address low and high registers. also calls
- * eth_port_set_filter_table_entry() to set the unicast
- * table with the proper information.
- *
- * RETURN:
- * N/A.
- *
+ * eth_port_uc_addr_set - Write a MAC address into the port's hw registers
*/
-static void eth_port_uc_addr_set(unsigned int eth_port_num,
- unsigned char *p_addr)
+static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr)
{
unsigned int mac_h;
unsigned int mac_l;
@@ -1868,40 +1851,24 @@ static void eth_port_uc_addr_set(unsigned int eth_port_num,
mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) |
(p_addr[3] << 0);
- mv_write(MV643XX_ETH_MAC_ADDR_LOW(eth_port_num), mac_l);
- mv_write(MV643XX_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h);
+ mv_write(MV643XX_ETH_MAC_ADDR_LOW(port_num), mac_l);
+ mv_write(MV643XX_ETH_MAC_ADDR_HIGH(port_num), mac_h);
- /* Accept frames of this address */
- table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(eth_port_num);
+ /* Accept frames with this address */
+ table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(port_num);
eth_port_set_filter_table_entry(table, p_addr[5] & 0x0f);
}
/*
- * eth_port_uc_addr_get - This function retrieves the port Unicast address
- * (MAC address) from the ethernet hw registers.
- *
- * DESCRIPTION:
- * This function retrieves the port Ethernet MAC address.
- *
- * INPUT:
- * unsigned int eth_port_num Port number.
- * char *MacAddr pointer where the MAC address is stored
- *
- * OUTPUT:
- * Copy the MAC address to the location pointed to by MacAddr
- *
- * RETURN:
- * N/A.
- *
+ * eth_port_uc_addr_get - Read the MAC address from the port's hw registers
*/
-static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *p_addr)
+static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr)
{
- struct mv643xx_private *mp = netdev_priv(dev);
unsigned int mac_h;
unsigned int mac_l;
- mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(mp->port_num));
- mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(mp->port_num));
+ mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(port_num));
+ mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(port_num));
p_addr[0] = (mac_h >> 24) & 0xff;
p_addr[1] = (mac_h >> 16) & 0xff;
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index 7d4e90cf49e8..82f8c0cbfb64 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -346,10 +346,6 @@ static void eth_port_init(struct mv643xx_private *mp);
static void eth_port_reset(unsigned int eth_port_num);
static void eth_port_start(struct net_device *dev);
-/* Port MAC address routines */
-static void eth_port_uc_addr_set(unsigned int eth_port_num,
- unsigned char *p_addr);
-
/* PHY and MIB routines */
static void ethernet_phy_reset(unsigned int eth_port_num);
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index dd8ce35332fe..ad6688eab265 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -64,9 +64,9 @@
#include "netxen_nic_hw.h"
#define _NETXEN_NIC_LINUX_MAJOR 3
-#define _NETXEN_NIC_LINUX_MINOR 3
-#define _NETXEN_NIC_LINUX_SUBVERSION 3
-#define NETXEN_NIC_LINUX_VERSIONID "3.3.3"
+#define _NETXEN_NIC_LINUX_MINOR 4
+#define _NETXEN_NIC_LINUX_SUBVERSION 2
+#define NETXEN_NIC_LINUX_VERSIONID "3.4.2"
#define NUM_FLASH_SECTORS (64)
#define FLASH_SECTOR_SIZE (64 * 1024)
@@ -131,8 +131,8 @@ extern struct workqueue_struct *netxen_workq;
#define FIRST_PAGE_GROUP_START 0
#define FIRST_PAGE_GROUP_END 0x100000
-#define SECOND_PAGE_GROUP_START 0x4000000
-#define SECOND_PAGE_GROUP_END 0x66BC000
+#define SECOND_PAGE_GROUP_START 0x6000000
+#define SECOND_PAGE_GROUP_END 0x68BC000
#define THIRD_PAGE_GROUP_START 0x70E4000
#define THIRD_PAGE_GROUP_END 0x8000000
@@ -205,6 +205,8 @@ enum {
#define MAX_CMD_DESCRIPTORS 1024
#define MAX_RCV_DESCRIPTORS 16384
+#define MAX_CMD_DESCRIPTORS_HOST (MAX_CMD_DESCRIPTORS / 4)
+#define MAX_RCV_DESCRIPTORS_1G (MAX_RCV_DESCRIPTORS / 4)
#define MAX_JUMBO_RCV_DESCRIPTORS 1024
#define MAX_LRO_RCV_DESCRIPTORS 64
#define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS
@@ -230,7 +232,9 @@ enum {
(((index) + (count)) & ((length) - 1))
#define MPORT_SINGLE_FUNCTION_MODE 0x1111
+#define MPORT_MULTI_FUNCTION_MODE 0x2222
+#include "netxen_nic_phan_reg.h"
extern unsigned long long netxen_dma_mask;
extern unsigned long last_schedule_time;
@@ -300,6 +304,8 @@ struct netxen_ring_ctx {
#define netxen_set_cmd_desc_port(cmd_desc, var) \
((cmd_desc)->port_ctxid |= ((var) & 0x0F))
+#define netxen_set_cmd_desc_ctxid(cmd_desc, var) \
+ ((cmd_desc)->port_ctxid |= ((var) & 0xF0))
#define netxen_set_cmd_desc_flags(cmd_desc, val) \
((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x7f), \
@@ -442,7 +448,7 @@ struct status_desc {
/* Bit pattern: 0-6 lro_count indicates frag sequence,
7 last_frag indicates last frag */
u8 lro;
-} __attribute__ ((aligned(8)));
+} __attribute__ ((aligned(16)));
enum {
NETXEN_RCV_PEG_0 = 0,
@@ -703,10 +709,8 @@ extern char netxen_nic_driver_name[];
#else
#define DPRINTK(klevel, fmt, args...) do { \
printk(KERN_##klevel PFX "%s: %s: " fmt, __FUNCTION__,\
- (adapter != NULL && \
- adapter->port[0] != NULL && \
- adapter->port[0]->netdev != NULL) ? \
- adapter->port[0]->netdev->name : NULL, \
+ (adapter != NULL && adapter->netdev != NULL) ? \
+ adapter->netdev->name : NULL, \
## args); } while(0)
#endif
@@ -722,6 +726,18 @@ struct netxen_skb_frag {
u32 length;
};
+#define _netxen_set_bits(config_word, start, bits, val) {\
+ unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));\
+ unsigned long long __tvalue = (val); \
+ (config_word) &= ~__tmask; \
+ (config_word) |= (((__tvalue) << (start)) & __tmask); \
+}
+
+#define _netxen_clear_bits(config_word, start, bits) {\
+ unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start)); \
+ (config_word) &= ~__tmask; \
+}
+
/* Following defines are for the state of the buffers */
#define NETXEN_BUFFER_FREE 0
#define NETXEN_BUFFER_BUSY 1
@@ -766,6 +782,8 @@ struct netxen_hardware_context {
void __iomem *pci_base0;
void __iomem *pci_base1;
void __iomem *pci_base2;
+ unsigned long first_page_group_end;
+ unsigned long first_page_group_start;
void __iomem *db_base;
unsigned long db_len;
@@ -780,6 +798,7 @@ struct netxen_hardware_context {
struct pci_dev *cmd_desc_pdev;
dma_addr_t cmd_desc_phys_addr;
struct netxen_adapter *adapter;
+ int pci_func;
};
#define RCV_RING_LRO RCV_DESC_LRO
@@ -788,17 +807,27 @@ struct netxen_hardware_context {
#define ETHERNET_FCS_SIZE 4
struct netxen_adapter_stats {
- u64 ints;
- u64 hostints;
- u64 otherints;
- u64 process_rcv;
- u64 process_xmit;
- u64 noxmitdone;
- u64 xmitcsummed;
- u64 post_called;
- u64 posted;
- u64 lastposted;
- u64 goodskbposts;
+ u64 rcvdbadskb;
+ u64 xmitcalled;
+ u64 xmitedframes;
+ u64 xmitfinished;
+ u64 badskblen;
+ u64 nocmddescriptor;
+ u64 polled;
+ u64 uphappy;
+ u64 updropped;
+ u64 uplcong;
+ u64 uphcong;
+ u64 upmcong;
+ u64 updunno;
+ u64 skbfreed;
+ u64 txdropped;
+ u64 txnullskb;
+ u64 csummed;
+ u64 no_rcv;
+ u64 rxbytes;
+ u64 txbytes;
+ u64 ints;
};
/*
@@ -846,13 +875,20 @@ struct netxen_dummy_dma {
struct netxen_adapter {
struct netxen_hardware_context ahw;
- int port_count; /* Number of configured ports */
- int active_ports; /* Number of open ports */
- struct netxen_port *port[NETXEN_MAX_PORTS]; /* ptr to each port */
+
+ struct netxen_adapter *master;
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device_stats net_stats;
+ unsigned char mac_addr[ETH_ALEN];
+ int mtu;
+ int portnum;
+
spinlock_t tx_lock;
spinlock_t lock;
struct work_struct watchdog_task;
struct timer_list watchdog_timer;
+ struct work_struct tx_timeout_task;
u32 curr_window;
@@ -875,6 +911,15 @@ struct netxen_adapter {
u32 temp;
struct netxen_adapter_stats stats;
+
+ u16 portno;
+ u16 link_speed;
+ u16 link_duplex;
+ u16 state;
+ u16 link_autoneg;
+ int rcsum;
+ int status;
+ spinlock_t stats_lock;
struct netxen_cmd_buffer *cmd_buf_arr; /* Command buffers for xmit */
@@ -891,65 +936,23 @@ struct netxen_adapter {
struct netxen_ring_ctx *ctx_desc;
struct pci_dev *ctx_desc_pdev;
dma_addr_t ctx_desc_phys_addr;
- int (*enable_phy_interrupts) (struct netxen_adapter *, int);
- int (*disable_phy_interrupts) (struct netxen_adapter *, int);
+ int (*enable_phy_interrupts) (struct netxen_adapter *);
+ int (*disable_phy_interrupts) (struct netxen_adapter *);
void (*handle_phy_intr) (struct netxen_adapter *);
- int (*macaddr_set) (struct netxen_port *, netxen_ethernet_macaddr_t);
- int (*set_mtu) (struct netxen_port *, int);
- int (*set_promisc) (struct netxen_adapter *, int,
- netxen_niu_prom_mode_t);
- int (*unset_promisc) (struct netxen_adapter *, int,
- netxen_niu_prom_mode_t);
- int (*phy_read) (struct netxen_adapter *, long phy, long reg, u32 *);
- int (*phy_write) (struct netxen_adapter *, long phy, long reg, u32 val);
+ int (*macaddr_set) (struct netxen_adapter *, netxen_ethernet_macaddr_t);
+ int (*set_mtu) (struct netxen_adapter *, int);
+ int (*set_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t);
+ int (*unset_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t);
+ int (*phy_read) (struct netxen_adapter *, long reg, u32 *);
+ int (*phy_write) (struct netxen_adapter *, long reg, u32 val);
int (*init_port) (struct netxen_adapter *, int);
void (*init_niu) (struct netxen_adapter *);
- int (*stop_port) (struct netxen_adapter *, int);
+ int (*stop_port) (struct netxen_adapter *);
}; /* netxen_adapter structure */
/* Max number of xmit producer threads that can run simultaneously */
#define MAX_XMIT_PRODUCERS 16
-struct netxen_port_stats {
- u64 rcvdbadskb;
- u64 xmitcalled;
- u64 xmitedframes;
- u64 xmitfinished;
- u64 badskblen;
- u64 nocmddescriptor;
- u64 polled;
- u64 uphappy;
- u64 updropped;
- u64 uplcong;
- u64 uphcong;
- u64 upmcong;
- u64 updunno;
- u64 skbfreed;
- u64 txdropped;
- u64 txnullskb;
- u64 csummed;
- u64 no_rcv;
- u64 rxbytes;
- u64 txbytes;
-};
-
-struct netxen_port {
- struct netxen_adapter *adapter;
-
- u16 portnum; /* GBE port number */
- u16 link_speed;
- u16 link_duplex;
- u16 link_autoneg;
-
- int flags;
-
- struct net_device *netdev;
- struct pci_dev *pdev;
- struct net_device_stats net_stats;
- struct netxen_port_stats stats;
- struct work_struct tx_timeout_task;
-};
-
#define PCI_OFFSET_FIRST_RANGE(adapter, off) \
((adapter)->ahw.pci_base0 + (off))
#define PCI_OFFSET_SECOND_RANGE(adapter, off) \
@@ -987,32 +990,26 @@ static inline void __iomem *pci_base(struct netxen_adapter *adapter,
return NULL;
}
-int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter,
- int port);
-int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
- int port);
-int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter,
- int port);
-int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter,
- int port);
-int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter,
- int port);
-int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter,
- int port);
+int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter);
void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter);
void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter);
void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port,
long enable);
void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port,
long enable);
-int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, long reg,
+int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
__u32 * readval);
-int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long phy,
+int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
long reg, __u32 val);
/* Functions available from netxen_nic_hw.c */
-int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu);
-int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu);
+int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu);
+int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu);
void netxen_nic_init_niu_gb(struct netxen_adapter *adapter);
void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw);
void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val);
@@ -1027,6 +1024,7 @@ int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data,
int len);
void netxen_crb_writelit_adapter(struct netxen_adapter *adapter,
unsigned long off, int data);
+int netxen_nic_erase_pxe(struct netxen_adapter *adapter);
/* Functions from netxen_nic_init.c */
void netxen_free_adapter_offload(struct netxen_adapter *adapter);
@@ -1051,11 +1049,8 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr);
/* Functions from netxen_nic_isr.c */
void netxen_nic_isr_other(struct netxen_adapter *adapter);
-void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 port,
- u32 link);
-void netxen_handle_port_int(struct netxen_adapter *adapter, u32 port,
- u32 enable);
-void netxen_nic_stop_all_ports(struct netxen_adapter *adapter);
+void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link);
+void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable);
void netxen_initialize_adapter_sw(struct netxen_adapter *adapter);
void netxen_initialize_adapter_hw(struct netxen_adapter *adapter);
void *netxen_alloc(struct pci_dev *pdev, size_t sz, dma_addr_t * ptr,
@@ -1110,6 +1105,7 @@ static inline void netxen_nic_enable_int(struct netxen_adapter *adapter)
if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
mask = 0xbff;
+ writel(0X0, NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
writel(mask, PCI_OFFSET_SECOND_RANGE(adapter,
ISR_INT_TARGET_MASK));
}
@@ -1174,4 +1170,5 @@ extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr,
extern struct ethtool_ops netxen_nic_ethtool_ops;
+extern int physical_port[]; /* physical port # from virtual port.*/
#endif /* __NETXEN_NIC_H_ */
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index ee1b5a24cbe7..16fabb377488 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -40,8 +40,8 @@
#include <linux/ethtool.h>
#include <linux/version.h>
-#include "netxen_nic_hw.h"
#include "netxen_nic.h"
+#include "netxen_nic_hw.h"
#include "netxen_nic_phan_reg.h"
struct netxen_nic_stats {
@@ -50,8 +50,8 @@ struct netxen_nic_stats {
int stat_offset;
};
-#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_port *)0)->m), \
- offsetof(struct netxen_port, m)
+#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_adapter *)0)->m), \
+ offsetof(struct netxen_adapter, m)
#define NETXEN_NIC_PORT_WINDOW 0x10000
#define NETXEN_NIC_INVALID_DATA 0xDEADBEEF
@@ -100,8 +100,7 @@ static int netxen_nic_get_eeprom_len(struct net_device *dev)
static void
netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
u32 fw_major = 0;
u32 fw_minor = 0;
u32 fw_build = 0;
@@ -115,7 +114,7 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
fw_build = readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_SUB));
sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
- strncpy(drvinfo->bus_info, pci_name(port->pdev), 32);
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
drvinfo->n_stats = NETXEN_NIC_STATS_LEN;
drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN;
drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
@@ -125,8 +124,7 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
static int
netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
struct netxen_board_info *boardinfo = &adapter->ahw.boardcfg;
/* read which mode */
@@ -146,8 +144,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->port = PORT_TP;
if (netif_running(dev)) {
- ecmd->speed = port->link_speed;
- ecmd->duplex = port->link_duplex;
+ ecmd->speed = adapter->link_speed;
+ ecmd->duplex = adapter->link_duplex;
} else
return -EIO; /* link absent */
} else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
@@ -165,7 +163,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
} else
return -EIO;
- ecmd->phy_address = port->portnum;
+ ecmd->phy_address = adapter->portnum;
ecmd->transceiver = XCVR_EXTERNAL;
switch ((netxen_brdtype_t) boardinfo->board_type) {
@@ -179,7 +177,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->port = PORT_TP;
ecmd->autoneg = (boardinfo->board_type ==
NETXEN_BRDTYPE_P2_SB31_10G_CX4) ?
- (AUTONEG_DISABLE) : (port->link_autoneg);
+ (AUTONEG_DISABLE) : (adapter->link_autoneg);
break;
case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
@@ -206,23 +204,22 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
static int
netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
__u32 status;
/* read which mode */
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
/* autonegotiation */
if (adapter->phy_write
- && adapter->phy_write(adapter, port->portnum,
+ && adapter->phy_write(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
ecmd->autoneg) != 0)
return -EIO;
else
- port->link_autoneg = ecmd->autoneg;
+ adapter->link_autoneg = ecmd->autoneg;
if (adapter->phy_read
- && adapter->phy_read(adapter, port->portnum,
+ && adapter->phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) != 0)
return -EIO;
@@ -245,13 +242,13 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (ecmd->duplex == DUPLEX_FULL)
netxen_set_phy_duplex(status);
if (adapter->phy_write
- && adapter->phy_write(adapter, port->portnum,
+ && adapter->phy_write(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
*((int *)&status)) != 0)
return -EIO;
else {
- port->link_speed = ecmd->speed;
- port->link_duplex = ecmd->duplex;
+ adapter->link_speed = ecmd->speed;
+ adapter->link_duplex = ecmd->duplex;
}
} else
return -EOPNOTSUPP;
@@ -360,15 +357,14 @@ static struct netxen_niu_regs niu_registers[] = {
static void
netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
__u32 mode, *regs_buff = p;
void __iomem *addr;
int i, window;
memset(p, 0, NETXEN_NIC_REGS_LEN);
regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) |
- (port->pdev)->device;
+ (adapter->pdev)->device;
/* which mode */
NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_MODE, &regs_buff[0]);
mode = regs_buff[0];
@@ -383,7 +379,8 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
for (i = 3; niu_registers[mode].reg[i - 3] != -1; i++) {
/* GB: port specific registers */
if (mode == 0 && i >= 19)
- window = port->portnum * NETXEN_NIC_PORT_WINDOW;
+ window = physical_port[adapter->portnum] *
+ NETXEN_NIC_PORT_WINDOW;
NETXEN_NIC_LOCKED_READ_REG(niu_registers[mode].
reg[i - 3] + window,
@@ -395,15 +392,14 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
static u32 netxen_nic_test_link(struct net_device *dev)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
__u32 status;
int val;
/* read which mode */
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
if (adapter->phy_read
- && adapter->phy_read(adapter, port->portnum,
+ && adapter->phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) != 0)
return -EIO;
@@ -422,15 +418,15 @@ static int
netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
u8 * bytes)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
int offset;
int ret;
if (eeprom->len == 0)
return -EINVAL;
- eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16);
+ eeprom->magic = (adapter->pdev)->vendor |
+ ((adapter->pdev)->device << 16);
offset = eeprom->offset;
ret = netxen_rom_fast_read_words(adapter, offset, bytes,
@@ -445,8 +441,7 @@ static int
netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
u8 * bytes)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
int offset = eeprom->offset;
static int flash_start;
static int ready_to_flash;
@@ -516,8 +511,7 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
static void
netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
int i;
ring->rx_pending = 0;
@@ -541,19 +535,45 @@ static void
netxen_nic_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
__u32 val;
+ int port = physical_port[adapter->portnum];
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+ if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ return;
/* get flow control settings */
- netxen_nic_read_w0(adapter,
- NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
- &val);
+ netxen_nic_read_w0(adapter,NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ &val);
pause->rx_pause = netxen_gb_get_rx_flowctl(val);
- pause->tx_pause = netxen_gb_get_tx_flowctl(val);
- /* get autoneg settings */
- pause->autoneg = port->link_autoneg;
+ netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val);
+ switch (port) {
+ case 0:
+ pause->tx_pause = !(netxen_gb_get_gb0_mask(val));
+ break;
+ case 1:
+ pause->tx_pause = !(netxen_gb_get_gb1_mask(val));
+ break;
+ case 2:
+ pause->tx_pause = !(netxen_gb_get_gb2_mask(val));
+ break;
+ case 3:
+ default:
+ pause->tx_pause = !(netxen_gb_get_gb3_mask(val));
+ break;
+ }
+ } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+ if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
+ return;
+ pause->rx_pause = 1;
+ netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val);
+ if (port == 0)
+ pause->tx_pause = !(netxen_xg_get_xg0_mask(val));
+ else
+ pause->tx_pause = !(netxen_xg_get_xg1_mask(val));
+ } else {
+ printk(KERN_ERR"%s: Unknown board type: %x\n",
+ netxen_nic_driver_name, adapter->ahw.board_type);
}
}
@@ -561,42 +581,76 @@ static int
netxen_nic_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
__u32 val;
- unsigned int autoneg;
-
+ int port = physical_port[adapter->portnum];
/* read mode */
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+ if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ return -EIO;
/* set flow control */
netxen_nic_read_w0(adapter,
- NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
- (u32 *) & val);
- if (pause->tx_pause)
- netxen_gb_tx_flowctl(val);
- else
- netxen_gb_unset_tx_flowctl(val);
+ NETXEN_NIU_GB_MAC_CONFIG_0(port), &val);
+
if (pause->rx_pause)
netxen_gb_rx_flowctl(val);
else
netxen_gb_unset_rx_flowctl(val);
- netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
- *&val);
+ netxen_nic_write_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ val);
/* set autoneg */
- autoneg = pause->autoneg;
- if (adapter->phy_write
- && adapter->phy_write(adapter, port->portnum,
- NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
- autoneg) != 0)
+ netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val);
+ switch (port) {
+ case 0:
+ if (pause->tx_pause)
+ netxen_gb_unset_gb0_mask(val);
+ else
+ netxen_gb_set_gb0_mask(val);
+ break;
+ case 1:
+ if (pause->tx_pause)
+ netxen_gb_unset_gb1_mask(val);
+ else
+ netxen_gb_set_gb1_mask(val);
+ break;
+ case 2:
+ if (pause->tx_pause)
+ netxen_gb_unset_gb2_mask(val);
+ else
+ netxen_gb_set_gb2_mask(val);
+ break;
+ case 3:
+ default:
+ if (pause->tx_pause)
+ netxen_gb_unset_gb3_mask(val);
+ else
+ netxen_gb_set_gb3_mask(val);
+ break;
+ }
+ netxen_nic_write_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, val);
+ } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+ if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
return -EIO;
- else {
- port->link_autoneg = pause->autoneg;
- return 0;
+ netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val);
+ if (port == 0) {
+ if (pause->tx_pause)
+ netxen_xg_unset_xg0_mask(val);
+ else
+ netxen_xg_set_xg0_mask(val);
+ } else {
+ if (pause->tx_pause)
+ netxen_xg_unset_xg1_mask(val);
+ else
+ netxen_xg_set_xg1_mask(val);
}
- } else
- return -EOPNOTSUPP;
+ netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val);
+ } else {
+ printk(KERN_ERR "%s: Unknown board type: %x\n",
+ netxen_nic_driver_name,
+ adapter->ahw.board_type);
+ }
+ return 0;
}
static int netxen_nic_reg_test(struct net_device *dev)
@@ -627,23 +681,12 @@ static void
netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
u64 * data)
{
- if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* offline tests */
- /* link test */
- if ((data[1] = (u64) netxen_nic_test_link(dev)))
- eth_test->flags |= ETH_TEST_FL_FAILED;
-
- /* register tests */
- if ((data[0] = netxen_nic_reg_test(dev)))
- eth_test->flags |= ETH_TEST_FL_FAILED;
- } else { /* online tests */
- /* register tests */
- if((data[0] = netxen_nic_reg_test(dev)))
- eth_test->flags |= ETH_TEST_FL_FAILED;
-
- /* link test */
- if ((data[1] = (u64) netxen_nic_test_link(dev)))
- eth_test->flags |= ETH_TEST_FL_FAILED;
- }
+ memset(data, 0, sizeof(uint64_t) * NETXEN_NIC_TEST_LEN);
+ if ((data[0] = netxen_nic_reg_test(dev)))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+ /* link test */
+ if ((data[1] = (u64) netxen_nic_test_link(dev)))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
}
static void
@@ -675,12 +718,13 @@ static void
netxen_nic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 * data)
{
- struct netxen_port *port = netdev_priv(dev);
+ struct netxen_adapter *adapter = netdev_priv(dev);
int index;
for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) {
char *p =
- (char *)port + netxen_nic_gstrings_stats[index].stat_offset;
+ (char *)adapter +
+ netxen_nic_gstrings_stats[index].stat_offset;
data[index] =
(netxen_nic_gstrings_stats[index].sizeof_stat ==
sizeof(u64)) ? *(u64 *) p : *(u32 *) p;
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
index fe8b675f9e72..608e37b349b4 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -467,6 +467,8 @@ enum {
#define NETXEN_PCI_OCM1 (0x05100000UL)
#define NETXEN_PCI_OCM1_MAX (0x051fffffUL)
#define NETXEN_PCI_CRBSPACE (0x06000000UL)
+#define NETXEN_PCI_128MB_SIZE (0x08000000UL)
+#define NETXEN_PCI_32MB_SIZE (0x02000000UL)
#define NETXEN_CRB_CAM NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_CAM)
@@ -484,6 +486,7 @@ enum {
/* 10 seconds before we give up */
#define NETXEN_NIU_PHY_WAITMAX 50
#define NETXEN_NIU_MAX_GBE_PORTS 4
+#define NETXEN_NIU_MAX_XG_PORTS 2
#define NETXEN_NIU_MODE (NETXEN_CRB_NIU + 0x00000)
@@ -527,6 +530,7 @@ enum {
#define NETXEN_NIU_XG_PAUSE_CTL (NETXEN_CRB_NIU + 0x00098)
#define NETXEN_NIU_XG_PAUSE_LEVEL (NETXEN_CRB_NIU + 0x000dc)
#define NETXEN_NIU_XG_SEL (NETXEN_CRB_NIU + 0x00128)
+#define NETXEN_NIU_GB_PAUSE_CTL (NETXEN_CRB_NIU + 0x0030c)
#define NETXEN_NIU_FULL_LEVEL_XG (NETXEN_CRB_NIU + 0x00450)
@@ -649,11 +653,19 @@ enum {
#define PCIX_MS_WINDOW (0x10204)
#define PCIX_SN_WINDOW (0x10208)
#define PCIX_CRB_WINDOW (0x10210)
+#define PCIX_CRB_WINDOW_F0 (0x10210)
+#define PCIX_CRB_WINDOW_F1 (0x10230)
+#define PCIX_CRB_WINDOW_F2 (0x10250)
+#define PCIX_CRB_WINDOW_F3 (0x10270)
#define PCIX_TARGET_STATUS (0x10118)
#define PCIX_TARGET_MASK (0x10128)
#define PCIX_MSI_F0 (0x13000)
+#define PCIX_MSI_F1 (0x13004)
+#define PCIX_MSI_F2 (0x13008)
+#define PCIX_MSI_F3 (0x1300c)
+#define PCIX_MSI_F(i) (0x13000+((i)*4))
#define PCIX_PS_MEM_SPACE (0x90000)
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 0fba8f190762..baff17a24d63 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -33,10 +33,225 @@
#include "netxen_nic.h"
#include "netxen_nic_hw.h"
+#define DEFINE_GLOBAL_RECV_CRB
#include "netxen_nic_phan_reg.h"
+
#include <net/ip.h>
+struct netxen_recv_crb recv_crb_registers[] = {
+ /*
+ * Instance 0.
+ */
+ {
+ /* rcv_desc_crb: */
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x100),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x104),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x108),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x10c),
+
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x110),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x114),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x118),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x11c),
+ },
+ /* LRO */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x120),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x124),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x128),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x12c),
+ }
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x130),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x134),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x138),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x13c),
+ /* crb_status_ring_size */
+ NETXEN_NIC_REG(0x140),
+
+ },
+ /*
+ * Instance 1,
+ */
+ {
+ /* rcv_desc_crb: */
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x144),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x148),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x14c),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x150),
+
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x154),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x158),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x15c),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x160),
+ },
+ /* LRO */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x164),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x168),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x16c),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x170),
+ }
+
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x174),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x178),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x17c),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x180),
+ /* crb_status_ring_size */
+ NETXEN_NIC_REG(0x184),
+ },
+ /*
+ * Instance 2,
+ */
+ {
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x1d8),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x1dc),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x1f0),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x1f4),
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x1f8),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x1fc),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x200),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x204),
+ },
+ /* LRO */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x208),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x20c),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x210),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x214),
+ }
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x218),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x21c),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x220),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x224),
+ /* crb_status_ring_size */
+ NETXEN_NIC_REG(0x228),
+ },
+ /*
+ * Instance 3,
+ */
+ {
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x22c),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x230),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x234),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x238),
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x23c),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x240),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x244),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x248),
+ },
+ /* LRO */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x24c),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x250),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x254),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x258),
+ }
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x25c),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x260),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x264),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x268),
+ /* crb_status_ring_size */
+ NETXEN_NIC_REG(0x26c),
+ },
+};
+
+u64 ctx_addr_sig_regs[][3] = {
+ {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)},
+ {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)},
+ {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)},
+ {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)}
+};
+
+
/* PCI Windowing for DDR regions. */
#define ADDR_IN_RANGE(addr, low, high) \
@@ -70,8 +285,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter);
int netxen_nic_set_mac(struct net_device *netdev, void *p)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
struct sockaddr *addr = p;
if (netif_running(netdev))
@@ -84,7 +298,7 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p)
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
if (adapter->macaddr_set)
- adapter->macaddr_set(port, addr->sa_data);
+ adapter->macaddr_set(adapter, addr->sa_data);
return 0;
}
@@ -94,56 +308,19 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p)
*/
void netxen_nic_set_multi(struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
struct dev_mc_list *mc_ptr;
- __u32 netxen_mac_addr_cntl_data = 0;
mc_ptr = netdev->mc_list;
if (netdev->flags & IFF_PROMISC) {
if (adapter->set_promisc)
adapter->set_promisc(adapter,
- port->portnum,
NETXEN_NIU_PROMISC_MODE);
} else {
- if (adapter->unset_promisc &&
- adapter->ahw.boardcfg.board_type
- != NETXEN_BRDTYPE_P2_SB31_10G_IMEZ)
+ if (adapter->unset_promisc)
adapter->unset_promisc(adapter,
- port->portnum,
NETXEN_NIU_NON_PROMISC_MODE);
}
- if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
- netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x03);
- netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_enable_xtnd0(netxen_mac_addr_cntl_data);
- netxen_nic_mcr_set_enable_xtnd1(netxen_mac_addr_cntl_data);
- netxen_nic_mcr_set_enable_xtnd2(netxen_mac_addr_cntl_data);
- netxen_nic_mcr_set_enable_xtnd3(netxen_mac_addr_cntl_data);
- } else {
- netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x01);
- netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x02);
- netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x03);
- }
- writel(netxen_mac_addr_cntl_data,
- NETXEN_CRB_NORMALIZE(adapter, NETXEN_MAC_ADDR_CNTL_REG));
- if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
- writel(netxen_mac_addr_cntl_data,
- NETXEN_CRB_NORMALIZE(adapter,
- NETXEN_MULTICAST_ADDR_HI_0));
- } else {
- writel(netxen_mac_addr_cntl_data,
- NETXEN_CRB_NORMALIZE(adapter,
- NETXEN_MULTICAST_ADDR_HI_1));
- }
- netxen_mac_addr_cntl_data = 0;
- writel(netxen_mac_addr_cntl_data,
- NETXEN_CRB_NORMALIZE(adapter, NETXEN_NIU_GB_DROP_WRONGADDR));
}
/*
@@ -152,8 +329,7 @@ void netxen_nic_set_multi(struct net_device *netdev)
*/
int netxen_nic_change_mtu(struct net_device *netdev, int mtu)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
int eff_mtu = mtu + NETXEN_ENET_HEADER_SIZE + NETXEN_ETH_FCS_SIZE;
if ((eff_mtu > NETXEN_MAX_MTU) || (eff_mtu < NETXEN_MIN_MTU)) {
@@ -163,7 +339,7 @@ int netxen_nic_change_mtu(struct net_device *netdev, int mtu)
}
if (adapter->set_mtu)
- adapter->set_mtu(port, mtu);
+ adapter->set_mtu(adapter, mtu);
netdev->mtu = mtu;
return 0;
@@ -180,9 +356,9 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
void *addr;
int loops = 0, err = 0;
int ctx, ring;
- u32 card_cmdring = 0;
struct netxen_recv_context *recv_ctx;
struct netxen_rcv_desc_ctx *rcv_desc;
+ int func_id = adapter->portnum;
DPRINTK(INFO, "crb_base: %lx %x", NETXEN_PCI_CRBSPACE,
PCI_OFFSET_SECOND_RANGE(adapter, NETXEN_PCI_CRBSPACE));
@@ -191,11 +367,6 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
DPRINTK(INFO, "cam RAM: %lx %x", NETXEN_CAM_RAM_BASE,
pci_base_offset(adapter, NETXEN_CAM_RAM_BASE));
- /* Window 1 call */
- card_cmdring = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_CMDRING));
-
- DPRINTK(INFO, "Command Peg sends 0x%x for cmdring base\n",
- card_cmdring);
for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
DPRINTK(INFO, "Command Peg ready..waiting for rcv peg\n");
@@ -229,7 +400,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
(dma_addr_t *) & adapter->ctx_desc_phys_addr,
&adapter->ctx_desc_pdev);
- printk("ctx_desc_phys_addr: 0x%llx\n",
+ printk(KERN_INFO "ctx_desc_phys_addr: 0x%llx\n",
(unsigned long long) adapter->ctx_desc_phys_addr);
if (addr == NULL) {
DPRINTK(ERR, "bad return from pci_alloc_consistent\n");
@@ -238,6 +409,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
}
memset(addr, 0, sizeof(struct netxen_ring_ctx));
adapter->ctx_desc = (struct netxen_ring_ctx *)addr;
+ adapter->ctx_desc->ctx_id = cpu_to_le32(adapter->portnum);
adapter->ctx_desc->cmd_consumer_offset =
cpu_to_le64(adapter->ctx_desc_phys_addr +
sizeof(struct netxen_ring_ctx));
@@ -249,7 +421,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
adapter->max_tx_desc_count,
(dma_addr_t *) & hw->cmd_desc_phys_addr,
&adapter->ahw.cmd_desc_pdev);
- printk("cmd_desc_phys_addr: 0x%llx\n",
+ printk(KERN_INFO "cmd_desc_phys_addr: 0x%llx\n",
(unsigned long long) hw->cmd_desc_phys_addr);
if (addr == NULL) {
@@ -308,11 +480,11 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
/* Window = 1 */
writel(lower32(adapter->ctx_desc_phys_addr),
- NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO));
+ NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO(func_id)));
writel(upper32(adapter->ctx_desc_phys_addr),
- NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI));
- writel(NETXEN_CTX_SIGNATURE,
- NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG));
+ NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI(func_id)));
+ writel(NETXEN_CTX_SIGNATURE | func_id,
+ NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG(func_id)));
return err;
}
@@ -339,10 +511,6 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter)
adapter->ahw.cmd_desc_phys_addr);
adapter->ahw.cmd_desc_head = NULL;
}
- /* Special handling: there are 2 ports on this board */
- if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
- adapter->ahw.max_ports = 2;
- }
for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
recv_ctx = &adapter->recv_ctx[ctx];
@@ -385,7 +553,6 @@ void netxen_tso_check(struct netxen_adapter *adapter,
return;
}
}
- adapter->stats.xmitcsummed++;
desc->tcp_hdr_offset = skb_transport_offset(skb);
desc->ip_hdr_offset = skb_network_offset(skb);
}
@@ -475,7 +642,30 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
if (adapter->curr_window == wndw)
return;
-
+ switch(adapter->ahw.pci_func) {
+ case 0:
+ offset = PCI_OFFSET_SECOND_RANGE(adapter,
+ NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
+ break;
+ case 1:
+ offset = PCI_OFFSET_SECOND_RANGE(adapter,
+ NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F1));
+ break;
+ case 2:
+ offset = PCI_OFFSET_SECOND_RANGE(adapter,
+ NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F2));
+ break;
+ case 3:
+ offset = PCI_OFFSET_SECOND_RANGE(adapter,
+ NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F3));
+ break;
+ default:
+ printk(KERN_INFO "Changing the window for PCI function"
+ "%d\n", adapter->ahw.pci_func);
+ offset = PCI_OFFSET_SECOND_RANGE(adapter,
+ NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
+ break;
+ }
/*
* Move the CRB window.
* We need to write to the "direct access" region of PCI
@@ -484,9 +674,6 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
* register address is received by PCI. The direct region bypasses
* the CRB bus.
*/
- offset =
- PCI_OFFSET_SECOND_RANGE(adapter,
- NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
if (wndw & 0x1)
wndw = NETXEN_WINDOW_ONE;
@@ -504,7 +691,10 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
count++;
}
- adapter->curr_window = wndw;
+ if (wndw == NETXEN_WINDOW_ONE)
+ adapter->curr_window = 1;
+ else
+ adapter->curr_window = 0;
}
void netxen_load_firmware(struct netxen_adapter *adapter)
@@ -749,6 +939,17 @@ netxen_nic_pci_set_window(struct netxen_adapter *adapter,
return addr;
}
+int
+netxen_nic_erase_pxe(struct netxen_adapter *adapter)
+{
+ if (netxen_rom_fast_write(adapter, PXE_START, 0) == -1) {
+ printk(KERN_ERR "%s: erase pxe failed\n",
+ netxen_nic_driver_name);
+ return -1;
+ }
+ return 0;
+}
+
int netxen_nic_get_board_info(struct netxen_adapter *adapter)
{
int rv = 0;
@@ -810,43 +1011,29 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
/* NIU access sections */
-int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu)
+int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu)
{
- struct netxen_adapter *adapter = port->adapter;
netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_MAX_FRAME_SIZE(port->portnum),
- new_mtu);
+ NETXEN_NIU_GB_MAX_FRAME_SIZE(
+ physical_port[adapter->portnum]), new_mtu);
return 0;
}
-int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu)
+int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu)
{
- struct netxen_adapter *adapter = port->adapter;
new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE;
- if (port->portnum == 0)
- netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, new_mtu);
- else if (port->portnum == 1)
- netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, new_mtu);
+ if (physical_port[adapter->portnum] == 0)
+ netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE,
+ new_mtu);
+ else
+ netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE,
+ new_mtu);
return 0;
}
void netxen_nic_init_niu_gb(struct netxen_adapter *adapter)
{
- int portno;
- for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++)
- netxen_niu_gbe_init_port(adapter, portno);
-}
-
-void netxen_nic_stop_all_ports(struct netxen_adapter *adapter)
-{
- int port_nr;
- struct netxen_port *port;
-
- for (port_nr = 0; port_nr < adapter->ahw.max_ports; port_nr++) {
- port = adapter->port[port_nr];
- if (adapter->stop_port)
- adapter->stop_port(adapter, port->portnum);
- }
+ netxen_niu_gbe_init_port(adapter, physical_port[adapter->portnum]);
}
void
@@ -865,9 +1052,8 @@ netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off,
}
}
-void netxen_nic_set_link_parameters(struct netxen_port *port)
+void netxen_nic_set_link_parameters(struct netxen_adapter *adapter)
{
- struct netxen_adapter *adapter = port->adapter;
__u32 status;
__u32 autoneg;
__u32 mode;
@@ -876,47 +1062,47 @@ void netxen_nic_set_link_parameters(struct netxen_port *port)
if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */
if (adapter->phy_read
&& adapter->
- phy_read(adapter, port->portnum,
+ phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) == 0) {
if (netxen_get_phy_link(status)) {
switch (netxen_get_phy_speed(status)) {
case 0:
- port->link_speed = SPEED_10;
+ adapter->link_speed = SPEED_10;
break;
case 1:
- port->link_speed = SPEED_100;
+ adapter->link_speed = SPEED_100;
break;
case 2:
- port->link_speed = SPEED_1000;
+ adapter->link_speed = SPEED_1000;
break;
default:
- port->link_speed = -1;
+ adapter->link_speed = -1;
break;
}
switch (netxen_get_phy_duplex(status)) {
case 0:
- port->link_duplex = DUPLEX_HALF;
+ adapter->link_duplex = DUPLEX_HALF;
break;
case 1:
- port->link_duplex = DUPLEX_FULL;
+ adapter->link_duplex = DUPLEX_FULL;
break;
default:
- port->link_duplex = -1;
+ adapter->link_duplex = -1;
break;
}
if (adapter->phy_read
&& adapter->
- phy_read(adapter, port->portnum,
+ phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
&autoneg) != 0)
- port->link_autoneg = autoneg;
+ adapter->link_autoneg = autoneg;
} else
goto link_down;
} else {
link_down:
- port->link_speed = -1;
- port->link_duplex = -1;
+ adapter->link_speed = -1;
+ adapter->link_duplex = -1;
}
}
}
@@ -930,7 +1116,7 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
char brd_name[NETXEN_MAX_SHORT_NAME];
struct netxen_new_user_info user_info;
int i, addr = USER_START;
- u32 *ptr32;
+ __le32 *ptr32;
struct netxen_board_info *board_info = &(adapter->ahw.boardcfg);
if (board_info->magic != NETXEN_BDINFO_MAGIC) {
@@ -956,7 +1142,6 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
netxen_nic_driver_name);
return;
}
- *ptr32 = le32_to_cpu(*ptr32);
ptr32++;
addr += sizeof(u32);
}
diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h
index ab1112eb1b0d..245bf13c7ba2 100644
--- a/drivers/net/netxen/netxen_nic_hw.h
+++ b/drivers/net/netxen/netxen_nic_hw.h
@@ -6,12 +6,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@@ -87,7 +87,7 @@ struct netxen_adapter;
*(u32 *)Y = readl((void __iomem*) addr);
struct netxen_port;
-void netxen_nic_set_link_parameters(struct netxen_port *port);
+void netxen_nic_set_link_parameters(struct netxen_adapter *adapter);
void netxen_nic_flash_print(struct netxen_adapter *adapter);
int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off,
void *data, int len);
@@ -220,6 +220,69 @@ typedef enum {
_netxen_crb_get_bit(config_word, 1)
#define netxen_get_gb_mii_mgmt_notvalid(config_word) \
_netxen_crb_get_bit(config_word, 2)
+/*
+ * NIU XG Pause Ctl Register
+ *
+ * Bit 0 : xg0_mask => 1:disable tx pause frames
+ * Bit 1 : xg0_request => 1:request single pause frame
+ * Bit 2 : xg0_on_off => 1:request is pause on, 0:off
+ * Bit 3 : xg1_mask => 1:disable tx pause frames
+ * Bit 4 : xg1_request => 1:request single pause frame
+ * Bit 5 : xg1_on_off => 1:request is pause on, 0:off
+ */
+
+#define netxen_xg_set_xg0_mask(config_word) \
+ ((config_word) |= 1 << 0)
+#define netxen_xg_set_xg1_mask(config_word) \
+ ((config_word) |= 1 << 3)
+
+#define netxen_xg_get_xg0_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 0)
+#define netxen_xg_get_xg1_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 3)
+
+#define netxen_xg_unset_xg0_mask(config_word) \
+ ((config_word) &= ~(1 << 0))
+#define netxen_xg_unset_xg1_mask(config_word) \
+ ((config_word) &= ~(1 << 3))
+
+/*
+ * NIU XG Pause Ctl Register
+ *
+ * Bit 0 : xg0_mask => 1:disable tx pause frames
+ * Bit 1 : xg0_request => 1:request single pause frame
+ * Bit 2 : xg0_on_off => 1:request is pause on, 0:off
+ * Bit 3 : xg1_mask => 1:disable tx pause frames
+ * Bit 4 : xg1_request => 1:request single pause frame
+ * Bit 5 : xg1_on_off => 1:request is pause on, 0:off
+ */
+#define netxen_gb_set_gb0_mask(config_word) \
+ ((config_word) |= 1 << 0)
+#define netxen_gb_set_gb1_mask(config_word) \
+ ((config_word) |= 1 << 2)
+#define netxen_gb_set_gb2_mask(config_word) \
+ ((config_word) |= 1 << 4)
+#define netxen_gb_set_gb3_mask(config_word) \
+ ((config_word) |= 1 << 6)
+
+#define netxen_gb_get_gb0_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 0)
+#define netxen_gb_get_gb1_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 2)
+#define netxen_gb_get_gb2_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 4)
+#define netxen_gb_get_gb3_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 6)
+
+#define netxen_gb_unset_gb0_mask(config_word) \
+ ((config_word) &= ~(1 << 0))
+#define netxen_gb_unset_gb1_mask(config_word) \
+ ((config_word) &= ~(1 << 2))
+#define netxen_gb_unset_gb2_mask(config_word) \
+ ((config_word) &= ~(1 << 4))
+#define netxen_gb_unset_gb3_mask(config_word) \
+ ((config_word) &= ~(1 << 6))
+
/*
* PHY-Specific MII control/status registers.
@@ -452,21 +515,21 @@ typedef enum {
((config) |= (((val) & 0x0f) << 28))
/* Set promiscuous mode for a GbE interface */
-int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
+int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
netxen_niu_prom_mode_t mode);
int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
- int port, netxen_niu_prom_mode_t mode);
+ netxen_niu_prom_mode_t mode);
/* get/set the MAC address for a given MAC */
-int netxen_niu_macaddr_get(struct netxen_adapter *adapter, int port,
+int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t * addr);
-int netxen_niu_macaddr_set(struct netxen_port *port,
+int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t addr);
/* XG versons */
-int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int port,
+int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t * addr);
-int netxen_niu_xg_macaddr_set(struct netxen_port *port,
+int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t addr);
/* Generic enable for GbE ports. Will detect the speed of the link. */
@@ -475,8 +538,8 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port);
int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port);
/* Disable a GbE interface */
-int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port);
+int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter);
-int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port);
+int netxen_niu_disable_xg_port(struct netxen_adapter *adapter);
#endif /* __NETXEN_NIC_HW_H_ */
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 5cd40562da7c..cf0e96adfe44 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -139,7 +139,7 @@ int netxen_init_firmware(struct netxen_adapter *adapter)
return err;
}
/* Window 1 call */
- writel(MPORT_SINGLE_FUNCTION_MODE,
+ writel(MPORT_MULTI_FUNCTION_MODE,
NETXEN_CRB_NORMALIZE(adapter, CRB_MPORT_MODE));
writel(PHAN_INITIALIZE_ACK,
NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
@@ -226,7 +226,6 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter)
adapter->unset_promisc = netxen_niu_set_promiscuous_mode;
adapter->phy_read = netxen_niu_gbe_phy_read;
adapter->phy_write = netxen_niu_gbe_phy_write;
- adapter->init_port = netxen_niu_gbe_init_port;
adapter->init_niu = netxen_nic_init_niu_gb;
adapter->stop_port = netxen_niu_disable_gbe_port;
break;
@@ -277,8 +276,8 @@ u32 netxen_decode_crb_addr(u32 addr)
return (pci_base + offset);
}
-static long rom_max_timeout = 10000;
-static long rom_lock_timeout = 1000000;
+static long rom_max_timeout = 100;
+static long rom_lock_timeout = 10000;
static long rom_write_timeout = 700;
static inline int rom_lock(struct netxen_adapter *adapter)
@@ -438,9 +437,9 @@ do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
for (addridx = addr; addridx < (addr + size); addridx += 4) {
ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
- *(int *)bytes = cpu_to_le32(*(int *)bytes);
if (ret != 0)
break;
+ *(int *)bytes = cpu_to_le32(*(int *)bytes);
bytes += 4;
}
@@ -499,7 +498,6 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter,
int data;
data = le32_to_cpu((*(u32*)bytes));
-
ret = do_rom_fast_write(adapter, addridx, data);
if (ret < 0)
return ret;
@@ -953,7 +951,8 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
if (!pegtune_val) {
val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
- while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
+ while (val != PHAN_INITIALIZE_COMPLETE &&
+ val != PHAN_INITIALIZE_ACK && loops < 200000) {
udelay(100);
schedule();
val =
@@ -990,9 +989,7 @@ int netxen_nic_rx_has_work(struct netxen_adapter *adapter)
static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
{
- int port_num;
- struct netxen_port *port;
- struct net_device *netdev;
+ struct net_device *netdev = adapter->netdev;
uint32_t temp, temp_state, temp_val;
int rv = 0;
@@ -1006,14 +1003,9 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
"%s: Device temperature %d degrees C exceeds"
" maximum allowed. Hardware has been shut down.\n",
netxen_nic_driver_name, temp_val);
- for (port_num = 0; port_num < adapter->ahw.max_ports;
- port_num++) {
- port = adapter->port[port_num];
- netdev = port->netdev;
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
- }
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
rv = 1;
} else if (temp_state == NX_TEMP_WARN) {
if (adapter->temp == NX_TEMP_NORMAL) {
@@ -1037,29 +1029,23 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
void netxen_watchdog_task(struct work_struct *work)
{
- int port_num;
- struct netxen_port *port;
struct net_device *netdev;
struct netxen_adapter *adapter =
container_of(work, struct netxen_adapter, watchdog_task);
- if (netxen_nic_check_temp(adapter))
+ if ((adapter->portnum == 0) && netxen_nic_check_temp(adapter))
return;
- for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) {
- port = adapter->port[port_num];
- netdev = port->netdev;
-
- if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) {
- printk(KERN_INFO "%s port %d, %s carrier is now ok\n",
- netxen_nic_driver_name, port_num, netdev->name);
- netif_carrier_on(netdev);
- }
-
- if (netif_queue_stopped(netdev))
- netif_wake_queue(netdev);
+ netdev = adapter->netdev;
+ if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) {
+ printk(KERN_INFO "%s port %d, %s carrier is now ok\n",
+ netxen_nic_driver_name, adapter->portnum, netdev->name);
+ netif_carrier_on(netdev);
}
+ if (netif_queue_stopped(netdev))
+ netif_wake_queue(netdev);
+
if (adapter->handle_phy_intr)
adapter->handle_phy_intr(adapter);
mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
@@ -1074,9 +1060,8 @@ void
netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
struct status_desc *desc)
{
- struct netxen_port *port = adapter->port[netxen_get_sts_port(desc)];
- struct pci_dev *pdev = port->pdev;
- struct net_device *netdev = port->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct net_device *netdev = adapter->netdev;
int index = netxen_get_sts_refhandle(desc);
struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]);
struct netxen_rx_buffer *buffer;
@@ -1126,7 +1111,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
skb = (struct sk_buff *)buffer->skb;
if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
- port->stats.csummed++;
+ adapter->stats.csummed++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
if (desc_ctx == RCV_DESC_LRO_CTXID) {
@@ -1146,27 +1131,27 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
*/
switch (ret) {
case NET_RX_SUCCESS:
- port->stats.uphappy++;
+ adapter->stats.uphappy++;
break;
case NET_RX_CN_LOW:
- port->stats.uplcong++;
+ adapter->stats.uplcong++;
break;
case NET_RX_CN_MOD:
- port->stats.upmcong++;
+ adapter->stats.upmcong++;
break;
case NET_RX_CN_HIGH:
- port->stats.uphcong++;
+ adapter->stats.uphcong++;
break;
case NET_RX_DROP:
- port->stats.updropped++;
+ adapter->stats.updropped++;
break;
default:
- port->stats.updunno++;
+ adapter->stats.updunno++;
break;
}
@@ -1178,14 +1163,13 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
/*
* We just consumed one buffer so post a buffer.
*/
- adapter->stats.post_called++;
buffer->skb = NULL;
buffer->state = NETXEN_BUFFER_FREE;
buffer->lro_current_frags = 0;
buffer->lro_expected_frags = 0;
- port->stats.no_rcv++;
- port->stats.rxbytes += length;
+ adapter->stats.no_rcv++;
+ adapter->stats.rxbytes += length;
}
/* Process Receive status ring */
@@ -1226,7 +1210,6 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max)
/* update the consumer index in phantom */
if (count) {
- adapter->stats.process_rcv++;
recv_ctx->status_rx_consumer = consumer;
recv_ctx->status_rx_producer = producer;
@@ -1249,13 +1232,10 @@ int netxen_process_cmd_ring(unsigned long data)
int count1 = 0;
int count2 = 0;
struct netxen_cmd_buffer *buffer;
- struct netxen_port *port; /* port #1 */
- struct netxen_port *nport;
struct pci_dev *pdev;
struct netxen_skb_frag *frag;
u32 i;
struct sk_buff *skb = NULL;
- int p;
int done;
spin_lock(&adapter->tx_lock);
@@ -1276,7 +1256,6 @@ int netxen_process_cmd_ring(unsigned long data)
}
adapter->proc_cmd_buf_counter++;
- adapter->stats.process_xmit++;
/*
* Not needed - does not seem to be used anywhere.
* adapter->cmd_consumer = consumer;
@@ -1285,8 +1264,7 @@ int netxen_process_cmd_ring(unsigned long data)
while ((last_consumer != consumer) && (count1 < MAX_STATUS_HANDLE)) {
buffer = &adapter->cmd_buf_arr[last_consumer];
- port = adapter->port[buffer->port];
- pdev = port->pdev;
+ pdev = adapter->pdev;
frag = &buffer->frag_array[0];
skb = buffer->skb;
if (skb && (cmpxchg(&buffer->skb, skb, 0) == skb)) {
@@ -1299,24 +1277,23 @@ int netxen_process_cmd_ring(unsigned long data)
PCI_DMA_TODEVICE);
}
- port->stats.skbfreed++;
+ adapter->stats.skbfreed++;
dev_kfree_skb_any(skb);
skb = NULL;
} else if (adapter->proc_cmd_buf_counter == 1) {
- port->stats.txnullskb++;
+ adapter->stats.txnullskb++;
}
- if (unlikely(netif_queue_stopped(port->netdev)
- && netif_carrier_ok(port->netdev))
- && ((jiffies - port->netdev->trans_start) >
- port->netdev->watchdog_timeo)) {
- SCHEDULE_WORK(&port->tx_timeout_task);
+ if (unlikely(netif_queue_stopped(adapter->netdev)
+ && netif_carrier_ok(adapter->netdev))
+ && ((jiffies - adapter->netdev->trans_start) >
+ adapter->netdev->watchdog_timeo)) {
+ SCHEDULE_WORK(&adapter->tx_timeout_task);
}
last_consumer = get_next_index(last_consumer,
adapter->max_tx_desc_count);
count1++;
}
- adapter->stats.noxmitdone += count1;
count2 = 0;
spin_lock(&adapter->tx_lock);
@@ -1336,13 +1313,10 @@ int netxen_process_cmd_ring(unsigned long data)
}
}
if (count1 || count2) {
- for (p = 0; p < adapter->ahw.max_ports; p++) {
- nport = adapter->port[p];
- if (netif_queue_stopped(nport->netdev)
- && (nport->flags & NETXEN_NETDEV_STATUS)) {
- netif_wake_queue(nport->netdev);
- nport->flags &= ~NETXEN_NETDEV_STATUS;
- }
+ if (netif_queue_stopped(adapter->netdev)
+ && (adapter->flags & NETXEN_NETDEV_STATUS)) {
+ netif_wake_queue(adapter->netdev);
+ adapter->flags &= ~NETXEN_NETDEV_STATUS;
}
}
/*
@@ -1388,7 +1362,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
netxen_ctx_msg msg = 0;
dma_addr_t dma;
- adapter->stats.post_called++;
rcv_desc = &recv_ctx->rcv_desc[ringid];
producer = rcv_desc->producer;
@@ -1441,8 +1414,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
if (count) {
rcv_desc->begin_alloc = index;
rcv_desc->rcv_pending += count;
- adapter->stats.lastposted = count;
- adapter->stats.posted += count;
rcv_desc->producer = producer;
if (rcv_desc->rcv_free >= 32) {
rcv_desc->rcv_free = 0;
@@ -1450,7 +1421,8 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
writel((producer - 1) &
(rcv_desc->max_rx_desc_count - 1),
NETXEN_CRB_NORMALIZE(adapter,
- recv_crb_registers[0].
+ recv_crb_registers[
+ adapter->portnum].
rcv_desc_crb[ringid].
crb_rcv_producer_offset));
/*
@@ -1463,7 +1435,7 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
((producer -
1) & (rcv_desc->
max_rx_desc_count - 1)));
- netxen_set_msg_ctxid(msg, 0);
+ netxen_set_msg_ctxid(msg, adapter->portnum);
netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid));
writel(msg,
DB_NORMALIZE(adapter,
@@ -1485,7 +1457,6 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
int count = 0;
int index = 0;
- adapter->stats.post_called++;
rcv_desc = &recv_ctx->rcv_desc[ringid];
producer = rcv_desc->producer;
@@ -1532,8 +1503,6 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
if (count) {
rcv_desc->begin_alloc = index;
rcv_desc->rcv_pending += count;
- adapter->stats.lastposted = count;
- adapter->stats.posted += count;
rcv_desc->producer = producer;
if (rcv_desc->rcv_free >= 32) {
rcv_desc->rcv_free = 0;
@@ -1541,7 +1510,8 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
writel((producer - 1) &
(rcv_desc->max_rx_desc_count - 1),
NETXEN_CRB_NORMALIZE(adapter,
- recv_crb_registers[0].
+ recv_crb_registers[
+ adapter->portnum].
rcv_desc_crb[ringid].
crb_rcv_producer_offset));
wmb();
@@ -1562,13 +1532,7 @@ int netxen_nic_tx_has_work(struct netxen_adapter *adapter)
void netxen_nic_clear_stats(struct netxen_adapter *adapter)
{
- struct netxen_port *port;
- int port_num;
-
memset(&adapter->stats, 0, sizeof(adapter->stats));
- for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) {
- port = adapter->port[port_num];
- memset(&port->stats, 0, sizeof(port->stats));
- }
+ return;
}
diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c
index be366e48007c..b213b062eb56 100644
--- a/drivers/net/netxen/netxen_nic_isr.c
+++ b/drivers/net/netxen/netxen_nic_isr.c
@@ -6,12 +6,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@@ -40,35 +40,35 @@
*/
struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct net_device_stats *stats = &port->net_stats;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
+ struct net_device_stats *stats = &adapter->net_stats;
memset(stats, 0, sizeof(*stats));
/* total packets received */
- stats->rx_packets = port->stats.no_rcv;
+ stats->rx_packets = adapter->stats.no_rcv;
/* total packets transmitted */
- stats->tx_packets = port->stats.xmitedframes + port->stats.xmitfinished;
+ stats->tx_packets = adapter->stats.xmitedframes +
+ adapter->stats.xmitfinished;
/* total bytes received */
- stats->rx_bytes = port->stats.rxbytes;
+ stats->rx_bytes = adapter->stats.rxbytes;
/* total bytes transmitted */
- stats->tx_bytes = port->stats.txbytes;
+ stats->tx_bytes = adapter->stats.txbytes;
/* bad packets received */
- stats->rx_errors = port->stats.rcvdbadskb;
+ stats->rx_errors = adapter->stats.rcvdbadskb;
/* packet transmit problems */
- stats->tx_errors = port->stats.nocmddescriptor;
+ stats->tx_errors = adapter->stats.nocmddescriptor;
/* no space in linux buffers */
- stats->rx_dropped = port->stats.updropped;
+ stats->rx_dropped = adapter->stats.updropped;
/* no space available in linux */
- stats->tx_dropped = port->stats.txdropped;
+ stats->tx_dropped = adapter->stats.txdropped;
return stats;
}
-void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno,
- u32 link)
+void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link)
{
- struct net_device *netdev = (adapter->port[portno])->netdev;
+ struct net_device *netdev = adapter->netdev;
if (link)
netif_carrier_on(netdev);
@@ -76,15 +76,13 @@ void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno,
netif_carrier_off(netdev);
}
-void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
- u32 enable)
+void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable)
{
__u32 int_src;
- struct netxen_port *port;
/* This should clear the interrupt source */
if (adapter->phy_read)
- adapter->phy_read(adapter, portno,
+ adapter->phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
&int_src);
if (int_src == 0) {
@@ -92,9 +90,7 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
return;
}
if (adapter->disable_phy_interrupts)
- adapter->disable_phy_interrupts(adapter, portno);
-
- port = adapter->port[portno];
+ adapter->disable_phy_interrupts(adapter);
if (netxen_get_phy_int_jabber(int_src))
DPRINTK(INFO, "Jabber interrupt \n");
@@ -115,64 +111,57 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n");
if (adapter->phy_read
- && adapter->phy_read(adapter, portno,
+ && adapter->phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) == 0) {
if (netxen_get_phy_int_link_status_changed(int_src)) {
if (netxen_get_phy_link(status)) {
- netxen_niu_gbe_init_port(adapter,
- portno);
- printk("%s: %s Link UP\n",
+ printk(KERN_INFO "%s: %s Link UP\n",
netxen_nic_driver_name,
- port->netdev->name);
+ adapter->netdev->name);
} else {
- printk("%s: %s Link DOWN\n",
+ printk(KERN_INFO "%s: %s Link DOWN\n",
netxen_nic_driver_name,
- port->netdev->name);
+ adapter->netdev->name);
}
- netxen_indicate_link_status(adapter, portno,
+ netxen_indicate_link_status(adapter,
netxen_get_phy_link
(status));
}
}
}
if (adapter->enable_phy_interrupts)
- adapter->enable_phy_interrupts(adapter, portno);
+ adapter->enable_phy_interrupts(adapter);
}
void netxen_nic_isr_other(struct netxen_adapter *adapter)
{
- u32 portno;
+ int portno = adapter->portnum;
u32 val, linkup, qg_linksup;
/* verify the offset */
val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
+ val = val >> physical_port[adapter->portnum];
if (val == adapter->ahw.qg_linksup)
return;
qg_linksup = adapter->ahw.qg_linksup;
adapter->ahw.qg_linksup = val;
DPRINTK(INFO, "link update 0x%08x\n", val);
- for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) {
- linkup = val & 1;
- if (linkup != (qg_linksup & 1)) {
- printk(KERN_INFO "%s: %s PORT %d link %s\n",
- adapter->port[portno]->netdev->name,
- netxen_nic_driver_name, portno,
- ((linkup == 0) ? "down" : "up"));
- netxen_indicate_link_status(adapter, portno, linkup);
- if (linkup)
- netxen_nic_set_link_parameters(adapter->
- port[portno]);
- }
- val = val >> 1;
- qg_linksup = qg_linksup >> 1;
- }
+ linkup = val & 1;
- adapter->stats.otherints++;
+ if (linkup != (qg_linksup & 1)) {
+ printk(KERN_INFO "%s: %s PORT %d link %s\n",
+ adapter->netdev->name,
+ netxen_nic_driver_name, portno,
+ ((linkup == 0) ? "down" : "up"));
+ netxen_indicate_link_status(adapter, linkup);
+ if (linkup)
+ netxen_nic_set_link_parameters(adapter);
+ }
}
void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
@@ -182,26 +171,28 @@ void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter)
{
- struct net_device *netdev = adapter->port[0]->netdev;
- u32 val;
+ struct net_device *netdev = adapter->netdev;
+ u32 val, val1;
/* WINDOW = 1 */
val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
+ val >>= (physical_port[adapter->portnum] * 8);
+ val1 = val & 0xff;
- if (adapter->ahw.xg_linkup == 1 && val != XG_LINK_UP) {
+ if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) {
printk(KERN_INFO "%s: %s NIC Link is down\n",
netxen_nic_driver_name, netdev->name);
adapter->ahw.xg_linkup = 0;
/* read twice to clear sticky bits */
/* WINDOW = 0 */
- netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
- netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
+ netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
+ netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
if ((val & 0xffb) != 0xffb) {
printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n",
- netxen_nic_driver_name, val);
+ netxen_nic_driver_name, val1);
}
- } else if (adapter->ahw.xg_linkup == 0 && val == XG_LINK_UP) {
+ } else if (adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) {
printk(KERN_INFO "%s: %s NIC Link is up\n",
netxen_nic_driver_name, netdev->name);
adapter->ahw.xg_linkup = 1;
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index ab25c225a07e..4e32bb678ea9 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -36,7 +36,6 @@
#include "netxen_nic_hw.h"
#include "netxen_nic.h"
-#define DEFINE_GLOBAL_RECV_CRB
#include "netxen_nic_phan_reg.h"
#include <linux/dma-mapping.h>
@@ -77,6 +76,8 @@ static void netxen_nic_poll_controller(struct net_device *netdev);
#endif
static irqreturn_t netxen_intr(int irq, void *data);
+int physical_port[] = {0, 1, 2, 3};
+
/* PCI Device ID Table */
static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
{PCI_DEVICE(0x4040, 0x0001)},
@@ -94,6 +95,67 @@ MODULE_DEVICE_TABLE(pci, netxen_pci_tbl);
struct workqueue_struct *netxen_workq;
static void netxen_watchdog(unsigned long);
+static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
+ uint32_t crb_producer)
+{
+ switch (adapter->portnum) {
+ case 0:
+ writel(crb_producer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_PRODUCER_OFFSET));
+ return;
+ case 1:
+ writel(crb_producer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_PRODUCER_OFFSET_1));
+ return;
+ case 2:
+ writel(crb_producer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_PRODUCER_OFFSET_2));
+ return;
+ case 3:
+ writel(crb_producer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_PRODUCER_OFFSET_3));
+ return;
+ default:
+ printk(KERN_WARNING "We tried to update "
+ "CRB_CMD_PRODUCER_OFFSET for invalid "
+ "PCI function id %d\n",
+ adapter->portnum);
+ return;
+ }
+}
+
+static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter,
+ u32 crb_consumer)
+{
+ switch (adapter->portnum) {
+ case 0:
+ writel(crb_consumer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_CONSUMER_OFFSET));
+ return;
+ case 1:
+ writel(crb_consumer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_CONSUMER_OFFSET_1));
+ return;
+ case 2:
+ writel(crb_consumer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_CONSUMER_OFFSET_2));
+ return;
+ case 3:
+ writel(crb_consumer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_CONSUMER_OFFSET_3));
+ return;
+ default:
+ printk(KERN_WARNING "We tried to update "
+ "CRB_CMD_PRODUCER_OFFSET for invalid "
+ "PCI function id %d\n",
+ adapter->portnum);
+ return;
+ }
+}
+
+#define ADAPTER_LIST_SIZE 12
+int netxen_cards_found;
+
/*
* netxen_nic_probe()
*
@@ -111,26 +173,30 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *netdev = NULL;
struct netxen_adapter *adapter = NULL;
- struct netxen_port *port = NULL;
void __iomem *mem_ptr0 = NULL;
void __iomem *mem_ptr1 = NULL;
void __iomem *mem_ptr2 = NULL;
+ unsigned long first_page_group_end;
+ unsigned long first_page_group_start;
+
u8 __iomem *db_ptr = NULL;
unsigned long mem_base, mem_len, db_base, db_len;
- int pci_using_dac, i, err;
+ int pci_using_dac, i = 0, err;
int ring;
struct netxen_recv_context *recv_ctx = NULL;
struct netxen_rcv_desc_ctx *rcv_desc = NULL;
struct netxen_cmd_buffer *cmd_buf_arr = NULL;
u64 mac_addr[FLASH_NUM_PORTS + 1];
int valid_mac = 0;
+ u32 val;
+ int pci_func_id = PCI_FUNC(pdev->devfn);
printk(KERN_INFO "%s \n", netxen_nic_driver_string);
- /* In current scheme, we use only PCI function 0 */
- if (PCI_FUNC(pdev->devfn) != 0) {
- DPRINTK(ERR, "NetXen function %d will not be enabled.\n",
- PCI_FUNC(pdev->devfn));
+
+ if (pdev->class != 0x020000) {
+ printk(KERN_ERR"NetXen function %d, class %x will not"
+ "be enabled.\n",pci_func_id, pdev->class);
return -ENODEV;
}
if ((err = pci_enable_device(pdev)))
@@ -157,18 +223,52 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_using_dac = 0;
}
+
+ netdev = alloc_etherdev(sizeof(struct netxen_adapter));
+ if(!netdev) {
+ printk(KERN_ERR"%s: Failed to allocate memory for the "
+ "device block.Check system memory resource"
+ " usage.\n", netxen_nic_driver_name);
+ goto err_out_free_res;
+ }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ adapter = netdev->priv;
+ memset(adapter, 0 , sizeof(struct netxen_adapter));
+
+ adapter->ahw.pdev = pdev;
+ adapter->ahw.pci_func = pci_func_id;
+ spin_lock_init(&adapter->tx_lock);
+ spin_lock_init(&adapter->lock);
+
/* remap phys address */
mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
mem_len = pci_resource_len(pdev, 0);
/* 128 Meg of memory */
- mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE);
- mem_ptr1 =
- ioremap(mem_base + SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_SIZE);
- mem_ptr2 =
- ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);
+ if (mem_len == NETXEN_PCI_128MB_SIZE) {
+ mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE);
+ mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START,
+ SECOND_PAGE_GROUP_SIZE);
+ mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START,
+ THIRD_PAGE_GROUP_SIZE);
+ first_page_group_start = FIRST_PAGE_GROUP_START;
+ first_page_group_end = FIRST_PAGE_GROUP_END;
+ } else if (mem_len == NETXEN_PCI_32MB_SIZE) {
+ mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE);
+ mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START -
+ SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);
+ first_page_group_start = 0;
+ first_page_group_end = 0;
+ } else {
+ err = -EIO;
+ goto err_out_free_netdev;
+ }
- if ((mem_ptr0 == 0UL) || (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {
+ if (((mem_ptr0 == 0UL) && (mem_len == NETXEN_PCI_128MB_SIZE)) ||
+ (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {
DPRINTK(ERR,
"Cannot remap adapter memory aborting.:"
"0 -> %p, 1 -> %p, 2 -> %p\n",
@@ -198,30 +298,87 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr);
-/*
- * Allocate a adapter structure which will manage all the initialization
- * as well as the common resources for all ports...
- * all the ports will have pointer to this adapter as well as Adapter
- * will have pointers of all the ports structures.
- */
+ adapter->ahw.pci_base0 = mem_ptr0;
+ adapter->ahw.first_page_group_start = first_page_group_start;
+ adapter->ahw.first_page_group_end = first_page_group_end;
+ adapter->ahw.pci_base1 = mem_ptr1;
+ adapter->ahw.pci_base2 = mem_ptr2;
+ adapter->ahw.db_base = db_ptr;
+ adapter->ahw.db_len = db_len;
- /* One adapter structure for all 4 ports.... */
- adapter = kzalloc(sizeof(struct netxen_adapter), GFP_KERNEL);
- if (adapter == NULL) {
- printk(KERN_ERR "%s: Could not allocate adapter memory:%d\n",
- netxen_nic_driver_name,
- (int)sizeof(struct netxen_adapter));
- err = -ENOMEM;
- goto err_out_dbunmap;
- }
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ adapter->portnum = pci_func_id;
+
+ netdev->open = netxen_nic_open;
+ netdev->stop = netxen_nic_close;
+ netdev->hard_start_xmit = netxen_nic_xmit_frame;
+ netdev->get_stats = netxen_nic_get_stats;
+ netdev->set_multicast_list = netxen_nic_set_multi;
+ netdev->set_mac_address = netxen_nic_set_mac;
+ netdev->change_mtu = netxen_nic_change_mtu;
+ netdev->tx_timeout = netxen_tx_timeout;
+ netdev->watchdog_timeo = HZ;
+
+ netxen_nic_change_mtu(netdev, netdev->mtu);
+
+ SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
+ netdev->poll = netxen_nic_poll;
+ netdev->weight = NETXEN_NETDEV_WEIGHT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = netxen_nic_poll_controller;
+#endif
+ /* ScatterGather support */
+ netdev->features = NETIF_F_SG;
+ netdev->features |= NETIF_F_IP_CSUM;
+ netdev->features |= NETIF_F_TSO;
+
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ if (pci_enable_msi(pdev)) {
+ adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
+ printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
+ " error\n", netxen_nic_driver_name);
+ } else
+ adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+
+ netdev->irq = pdev->irq;
+ INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task);
- adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS;
- adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
+ /*
+ * Set the CRB window to invalid. If any register in window 0 is
+ * accessed it should set the window to 0 and then reset it to 1.
+ */
+ adapter->curr_window = 255;
+
+ /* initialize the adapter */
+ netxen_initialize_adapter_hw(adapter);
+
+#ifdef CONFIG_PPC
+ if ((adapter->ahw.boardcfg.board_type ==
+ NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) &&
+ (pci_func_id == 2))
+ goto err_out_free_adapter;
+#endif /* CONFIG_PPC */
+
+ /*
+ * Adapter in our case is quad port so initialize it before
+ * initializing the ports
+ */
+
+ netxen_initialize_adapter_ops(adapter);
+
+ adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST;
+ if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB35_4G) ||
+ (adapter->ahw.boardcfg.board_type ==
+ NETXEN_BRDTYPE_P2_SB31_2G))
+ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
+ else
+ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS;
adapter->max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS;
- pci_set_drvdata(pdev, adapter);
-
cmd_buf_arr = (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE);
if (cmd_buf_arr == NULL) {
printk(KERN_ERR
@@ -231,6 +388,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_adapter;
}
memset(cmd_buf_arr, 0, TX_RINGSIZE);
+ adapter->cmd_buf_arr = cmd_buf_arr;
for (i = 0; i < MAX_RCV_CTX; ++i) {
recv_ctx = &adapter->recv_ctx[i];
@@ -278,33 +436,20 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
- adapter->cmd_buf_arr = cmd_buf_arr;
- adapter->ahw.pci_base0 = mem_ptr0;
- adapter->ahw.pci_base1 = mem_ptr1;
- adapter->ahw.pci_base2 = mem_ptr2;
- adapter->ahw.db_base = db_ptr;
- adapter->ahw.db_len = db_len;
- spin_lock_init(&adapter->tx_lock);
- spin_lock_init(&adapter->lock);
netxen_initialize_adapter_sw(adapter); /* initialize the buffers in adapter */
-#ifdef CONFIG_IA64
- netxen_pinit_from_rom(adapter, 0);
- udelay(500);
- netxen_load_firmware(adapter);
-#endif
- /*
- * Set the CRB window to invalid. If any register in window 0 is
- * accessed it should set the window to 0 and then reset it to 1.
- */
- adapter->curr_window = 255;
- /*
- * Adapter in our case is quad port so initialize it before
- * initializing the ports
- */
- netxen_initialize_adapter_hw(adapter); /* initialize the adapter */
+ /* Mezz cards have PCI function 0,2,3 enabled */
+ if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ)
+ && (pci_func_id >= 2))
+ adapter->portnum = pci_func_id - 2;
- netxen_initialize_adapter_ops(adapter);
+#ifdef CONFIG_IA64
+ if(adapter->portnum == 0) {
+ netxen_pinit_from_rom(adapter, 0);
+ udelay(500);
+ netxen_load_firmware(adapter);
+ }
+#endif
init_timer(&adapter->watchdog_timer);
adapter->ahw.xg_linkup = 0;
@@ -315,12 +460,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->proc_cmd_buf_counter = 0;
adapter->ahw.revision_id = nx_p2_id;
- if (pci_enable_msi(pdev)) {
- adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
- printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
- " error\n", netxen_nic_driver_name);
- } else
- adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+ /* make sure Window == 1 */
+ netxen_nic_pci_change_crbwindow(adapter, 1);
+
+ netxen_nic_update_cmd_producer(adapter, 0);
+ netxen_nic_update_cmd_consumer(adapter, 0);
+ writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO));
if (netxen_is_flash_supported(adapter) == 0 &&
netxen_get_flash_mac_addr(adapter, mac_addr) == 0)
@@ -328,153 +473,118 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
else
valid_mac = 0;
- /*
- * Initialize all the CRB registers here.
- */
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET));
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_CONSUMER_OFFSET));
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO));
-
- /* do this before waking up pegs so that we have valid dummy dma addr */
- err = netxen_initialize_adapter_offload(adapter);
- if (err) {
- goto err_out_free_dev;
+ if (valid_mac) {
+ unsigned char *p = (unsigned char *)&mac_addr[adapter->portnum];
+ netdev->dev_addr[0] = *(p + 5);
+ netdev->dev_addr[1] = *(p + 4);
+ netdev->dev_addr[2] = *(p + 3);
+ netdev->dev_addr[3] = *(p + 2);
+ netdev->dev_addr[4] = *(p + 1);
+ netdev->dev_addr[5] = *(p + 0);
+
+ memcpy(netdev->perm_addr, netdev->dev_addr,
+ netdev->addr_len);
+ if (!is_valid_ether_addr(netdev->perm_addr)) {
+ printk(KERN_ERR "%s: Bad MAC address "
+ "%02x:%02x:%02x:%02x:%02x:%02x.\n",
+ netxen_nic_driver_name,
+ netdev->dev_addr[0],
+ netdev->dev_addr[1],
+ netdev->dev_addr[2],
+ netdev->dev_addr[3],
+ netdev->dev_addr[4],
+ netdev->dev_addr[5]);
+ } else {
+ if (adapter->macaddr_set)
+ adapter->macaddr_set(adapter,
+ netdev->dev_addr);
+ }
}
- /* Unlock the HW, prompting the boot sequence */
- writel(1,
- NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE));
-
- /* Handshake with the card before we register the devices. */
- netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
-
- /* initialize the all the ports */
- adapter->active_ports = 0;
-
- for (i = 0; i < adapter->ahw.max_ports; i++) {
- netdev = alloc_etherdev(sizeof(struct netxen_port));
- if (!netdev) {
- printk(KERN_ERR "%s: could not allocate netdev for port"
- " %d\n", netxen_nic_driver_name, i + 1);
+ if (adapter->portnum == 0) {
+ err = netxen_initialize_adapter_offload(adapter);
+ if (err)
+ goto err_out_free_rx_buffer;
+ val = readl(NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_CAM_RAM(0x1fc)));
+ if (val == 0x55555555) {
+ /* This is the first boot after power up */
+ val = readl(NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_ROMUSB_GLB_SW_RESET));
+ printk(KERN_INFO"NetXen: read 0x%08x for reset reg.\n",val);
+ if (val != 0x80000f) {
+ /* clear the register for future unloads/loads */
+ writel(0, NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_CAM_RAM(0x1fc)));
+ printk(KERN_ERR "ERROR in NetXen HW init sequence.\n");
+ err = -ENODEV;
goto err_out_free_dev;
- }
+ }
- SET_MODULE_OWNER(netdev);
- SET_NETDEV_DEV(netdev, &pdev->dev);
-
- port = netdev_priv(netdev);
- port->netdev = netdev;
- port->pdev = pdev;
- port->adapter = adapter;
- port->portnum = i; /* Gigabit port number from 0-3 */
-
- netdev->open = netxen_nic_open;
- netdev->stop = netxen_nic_close;
- netdev->hard_start_xmit = netxen_nic_xmit_frame;
- netdev->get_stats = netxen_nic_get_stats;
- netdev->set_multicast_list = netxen_nic_set_multi;
- netdev->set_mac_address = netxen_nic_set_mac;
- netdev->change_mtu = netxen_nic_change_mtu;
- netdev->tx_timeout = netxen_tx_timeout;
- netdev->watchdog_timeo = HZ;
-
- netxen_nic_change_mtu(netdev, netdev->mtu);
-
- SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
- netdev->poll = netxen_nic_poll;
- netdev->weight = NETXEN_NETDEV_WEIGHT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- netdev->poll_controller = netxen_nic_poll_controller;
-#endif
- /* ScatterGather support */
- netdev->features = NETIF_F_SG;
- netdev->features |= NETIF_F_IP_CSUM;
- netdev->features |= NETIF_F_TSO;
-
- if (pci_using_dac)
- netdev->features |= NETIF_F_HIGHDMA;
-
- if (valid_mac) {
- unsigned char *p = (unsigned char *)&mac_addr[i];
- netdev->dev_addr[0] = *(p + 5);
- netdev->dev_addr[1] = *(p + 4);
- netdev->dev_addr[2] = *(p + 3);
- netdev->dev_addr[3] = *(p + 2);
- netdev->dev_addr[4] = *(p + 1);
- netdev->dev_addr[5] = *(p + 0);
-
- memcpy(netdev->perm_addr, netdev->dev_addr,
- netdev->addr_len);
- if (!is_valid_ether_addr(netdev->perm_addr)) {
- printk(KERN_ERR "%s: Bad MAC address "
- "%02x:%02x:%02x:%02x:%02x:%02x.\n",
- netxen_nic_driver_name,
- netdev->dev_addr[0],
- netdev->dev_addr[1],
- netdev->dev_addr[2],
- netdev->dev_addr[3],
- netdev->dev_addr[4],
- netdev->dev_addr[5]);
- } else {
- if (adapter->macaddr_set)
- adapter->macaddr_set(port,
- netdev->dev_addr);
- }
+ /* clear the register for future unloads/loads */
+ writel(0, NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_CAM_RAM(0x1fc)));
}
- INIT_WORK(&port->tx_timeout_task, netxen_tx_timeout_task);
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
+ printk(KERN_INFO "State: 0x%0x\n",
+ readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
- if ((err = register_netdev(netdev))) {
- printk(KERN_ERR "%s: register_netdev failed port #%d"
- " aborting\n", netxen_nic_driver_name, i + 1);
- err = -EIO;
- free_netdev(netdev);
- goto err_out_free_dev;
- }
- adapter->port_count++;
- adapter->port[i] = port;
+ /*
+ * Tell the hardware our version number.
+ */
+ i = (_NETXEN_NIC_LINUX_MAJOR << 16)
+ | ((_NETXEN_NIC_LINUX_MINOR << 8))
+ | (_NETXEN_NIC_LINUX_SUBVERSION);
+ writel(i, NETXEN_CRB_NORMALIZE(adapter, CRB_DRIVER_VERSION));
+
+ /* Unlock the HW, prompting the boot sequence */
+ writel(1,
+ NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_ROMUSB_GLB_PEGTUNE_DONE));
+ /* Handshake with the card before we register the devices. */
+ netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
}
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
- netxen_pinit_from_rom(adapter, 0);
- udelay(500);
- netxen_load_firmware(adapter);
- netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+
/*
- * delay a while to ensure that the Pegs are up & running.
- * Otherwise, we might see some flaky behaviour.
+ * See if the firmware gave us a virtual-physical port mapping.
*/
- udelay(100);
+ i = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_V2P(adapter->portnum)));
+ if (i != 0x55555555)
+ physical_port[adapter->portnum] = i;
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ if ((err = register_netdev(netdev))) {
+ printk(KERN_ERR "%s: register_netdev failed port #%d"
+ " aborting\n", netxen_nic_driver_name,
+ adapter->portnum);
+ err = -EIO;
+ goto err_out_free_dev;
+ }
+
+ pci_set_drvdata(pdev, adapter);
switch (adapter->ahw.board_type) {
- case NETXEN_NIC_GBE:
- printk("%s: QUAD GbE board initialized\n",
- netxen_nic_driver_name);
- break;
+ case NETXEN_NIC_GBE:
+ printk(KERN_INFO "%s: QUAD GbE board initialized\n",
+ netxen_nic_driver_name);
+ break;
- case NETXEN_NIC_XGBE:
- printk("%s: XGbE board initialized\n", netxen_nic_driver_name);
- break;
+ case NETXEN_NIC_XGBE:
+ printk(KERN_INFO "%s: XGbE board initialized\n",
+ netxen_nic_driver_name);
+ break;
}
adapter->driver_mismatch = 0;
return 0;
- err_out_free_dev:
- if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
- pci_disable_msi(pdev);
- for (i = 0; i < adapter->port_count; i++) {
- port = adapter->port[i];
- if ((port) && (port->netdev)) {
- unregister_netdev(port->netdev);
- free_netdev(port->netdev);
- }
- }
+err_out_free_dev:
+ if (adapter->portnum == 0)
+ netxen_free_adapter_offload(adapter);
- netxen_free_adapter_offload(adapter);
-
- err_out_free_rx_buffer:
+err_out_free_rx_buffer:
for (i = 0; i < MAX_RCV_CTX; ++i) {
recv_ctx = &adapter->recv_ctx[i];
for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) {
@@ -487,15 +597,16 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
vfree(cmd_buf_arr);
- err_out_free_adapter:
+err_out_free_adapter:
+ if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
+ pci_disable_msi(pdev);
+
pci_set_drvdata(pdev, NULL);
- kfree(adapter);
- err_out_dbunmap:
if (db_ptr)
iounmap(db_ptr);
- err_out_iounmap:
+err_out_iounmap:
if (mem_ptr0)
iounmap(mem_ptr0);
if (mem_ptr1)
@@ -503,9 +614,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (mem_ptr2)
iounmap(mem_ptr2);
- err_out_free_res:
+err_out_free_netdev:
+ free_netdev(netdev);
+
+err_out_free_res:
pci_release_regions(pdev);
- err_out_disable_pdev:
+
+err_out_disable_pdev:
pci_disable_device(pdev);
return err;
}
@@ -513,7 +628,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
static void __devexit netxen_nic_remove(struct pci_dev *pdev)
{
struct netxen_adapter *adapter;
- struct netxen_port *port;
+ struct net_device *netdev;
struct netxen_rx_buffer *buffer;
struct netxen_recv_context *recv_ctx;
struct netxen_rcv_desc_ctx *rcv_desc;
@@ -524,38 +639,34 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
if (adapter == NULL)
return;
+ netdev = adapter->netdev;
+
+ netxen_nic_disable_int(adapter);
if (adapter->irq)
free_irq(adapter->irq, adapter);
- netxen_nic_stop_all_ports(adapter);
- /* leave the hw in the same state as reboot */
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
- netxen_pinit_from_rom(adapter, 0);
- udelay(500);
- netxen_load_firmware(adapter);
- netxen_free_adapter_offload(adapter);
-
- mdelay(1000); /* Delay for a while to drain the DMA engines */
- for (i = 0; i < adapter->port_count; i++) {
- port = adapter->port[i];
- if ((port) && (port->netdev)) {
- unregister_netdev(port->netdev);
- free_netdev(port->netdev);
- }
- }
+
+ if (adapter->stop_port)
+ adapter->stop_port(adapter);
if ((adapter->flags & NETXEN_NIC_MSI_ENABLED))
pci_disable_msi(pdev);
- if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
- netxen_free_hw_resources(adapter);
- iounmap(adapter->ahw.db_base);
- iounmap(adapter->ahw.pci_base0);
- iounmap(adapter->ahw.pci_base1);
- iounmap(adapter->ahw.pci_base2);
+ if (adapter->portnum == 0)
+ netxen_free_adapter_offload(adapter);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
+ if (adapter->irq)
+ free_irq(adapter->irq, adapter);
+ if(adapter->portnum == 0) {
+ /* leave the hw in the same state as reboot */
+ writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
+ netxen_pinit_from_rom(adapter, 0);
+ udelay(500);
+ netxen_load_firmware(adapter);
+ netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+ }
+
+ if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
+ netxen_free_hw_resources(adapter);
for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) {
recv_ctx = &adapter->recv_ctx[ctxid];
@@ -575,8 +686,20 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
}
}
+ unregister_netdev(netdev);
+
vfree(adapter->cmd_buf_arr);
- kfree(adapter);
+
+ iounmap(adapter->ahw.db_base);
+ iounmap(adapter->ahw.pci_base0);
+ iounmap(adapter->ahw.pci_base1);
+ iounmap(adapter->ahw.pci_base2);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ free_netdev(netdev);
}
/*
@@ -585,8 +708,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
*/
static int netxen_nic_open(struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv;
int err = 0;
int ctx, ring;
@@ -597,8 +719,6 @@ static int netxen_nic_open(struct net_device *netdev)
return -EIO;
}
netxen_nic_flash_print(adapter);
- if (adapter->init_niu)
- adapter->init_niu(adapter);
/* setup all the resources for the Phantom... */
/* this include the descriptors for rcv, tx, and status */
@@ -609,21 +729,14 @@ static int netxen_nic_open(struct net_device *netdev)
err);
return err;
}
- if (adapter->init_port
- && adapter->init_port(adapter, port->portnum) != 0) {
- printk(KERN_ERR "%s: Failed to initialize port %d\n",
- netxen_nic_driver_name, port->portnum);
- netxen_free_hw_resources(adapter);
- return -EIO;
- }
for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++)
netxen_post_rx_buffers(adapter, ctx, ring);
}
adapter->irq = adapter->ahw.pdev->irq;
- err = request_irq(adapter->ahw.pdev->irq, &netxen_intr,
- IRQF_SHARED | IRQF_SAMPLE_RANDOM,
- netdev->name, adapter);
+ err = request_irq(adapter->ahw.pdev->irq, netxen_intr,
+ SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name,
+ adapter);
if (err) {
printk(KERN_ERR "request_irq failed with: %d\n", err);
netxen_free_hw_resources(adapter);
@@ -632,23 +745,28 @@ static int netxen_nic_open(struct net_device *netdev)
adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
}
- adapter->active_ports++;
- if (adapter->active_ports == 1) {
- if (!adapter->driver_mismatch)
- mod_timer(&adapter->watchdog_timer, jiffies);
+ if (!adapter->driver_mismatch)
+ mod_timer(&adapter->watchdog_timer, jiffies);
- netxen_nic_enable_int(adapter);
- }
+ netxen_nic_enable_int(adapter);
/* Done here again so that even if phantom sw overwrote it,
* we set it */
if (adapter->macaddr_set)
- adapter->macaddr_set(port, netdev->dev_addr);
- netxen_nic_set_link_parameters(port);
+ adapter->macaddr_set(adapter, netdev->dev_addr);
+ if (adapter->init_port
+ && adapter->init_port(adapter, adapter->portnum) != 0) {
+ del_timer_sync(&adapter->watchdog_timer);
+ printk(KERN_ERR "%s: Failed to initialize port %d\n",
+ netxen_nic_driver_name, adapter->portnum);
+ return -EIO;
+ }
+
+ netxen_nic_set_link_parameters(adapter);
netxen_nic_set_multi(netdev);
if (adapter->set_mtu)
- adapter->set_mtu(port, netdev->mtu);
+ adapter->set_mtu(adapter, netdev->mtu);
if (!adapter->driver_mismatch)
netif_start_queue(netdev);
@@ -661,8 +779,7 @@ static int netxen_nic_open(struct net_device *netdev)
*/
static int netxen_nic_close(struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
int i, j;
struct netxen_cmd_buffer *cmd_buff;
struct netxen_skb_frag *buffrag;
@@ -670,47 +787,39 @@ static int netxen_nic_close(struct net_device *netdev)
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- adapter->active_ports--;
-
- if (!adapter->active_ports) {
- netxen_nic_disable_int(adapter);
- cmd_buff = adapter->cmd_buf_arr;
- for (i = 0; i < adapter->max_tx_desc_count; i++) {
- buffrag = cmd_buff->frag_array;
+ cmd_buff = adapter->cmd_buf_arr;
+ for (i = 0; i < adapter->max_tx_desc_count; i++) {
+ buffrag = cmd_buff->frag_array;
+ if (buffrag->dma) {
+ pci_unmap_single(adapter->pdev, buffrag->dma,
+ buffrag->length, PCI_DMA_TODEVICE);
+ buffrag->dma = (u64) NULL;
+ }
+ for (j = 0; j < cmd_buff->frag_count; j++) {
+ buffrag++;
if (buffrag->dma) {
- pci_unmap_single(port->pdev, buffrag->dma,
- buffrag->length,
- PCI_DMA_TODEVICE);
+ pci_unmap_page(adapter->pdev, buffrag->dma,
+ buffrag->length,
+ PCI_DMA_TODEVICE);
buffrag->dma = (u64) NULL;
}
- for (j = 0; j < cmd_buff->frag_count; j++) {
- buffrag++;
- if (buffrag->dma) {
- pci_unmap_page(port->pdev,
- buffrag->dma,
- buffrag->length,
- PCI_DMA_TODEVICE);
- buffrag->dma = (u64) NULL;
- }
- }
- /* Free the skb we received in netxen_nic_xmit_frame */
- if (cmd_buff->skb) {
- dev_kfree_skb_any(cmd_buff->skb);
- cmd_buff->skb = NULL;
- }
- cmd_buff++;
}
- FLUSH_SCHEDULED_WORK();
- del_timer_sync(&adapter->watchdog_timer);
+ /* Free the skb we received in netxen_nic_xmit_frame */
+ if (cmd_buff->skb) {
+ dev_kfree_skb_any(cmd_buff->skb);
+ cmd_buff->skb = NULL;
+ }
+ cmd_buff++;
}
+ FLUSH_SCHEDULED_WORK();
+ del_timer_sync(&adapter->watchdog_timer);
return 0;
}
static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
struct netxen_hardware_context *hw = &adapter->ahw;
unsigned int first_seg_len = skb->len - skb->data_len;
struct netxen_skb_frag *buffrag;
@@ -728,12 +837,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
u32 last_cmd_consumer = 0;
int no_of_desc;
- port->stats.xmitcalled++;
+ adapter->stats.xmitcalled++;
frag_count = skb_shinfo(skb)->nr_frags + 1;
if (unlikely(skb->len <= 0)) {
dev_kfree_skb_any(skb);
- port->stats.badskblen++;
+ adapter->stats.badskblen++;
return NETDEV_TX_OK;
}
@@ -742,7 +851,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
"too large, can handle only %d frags\n",
netxen_nic_driver_name, netdev->name,
frag_count, MAX_BUFFERS_PER_CMD);
- port->stats.txdropped++;
+ adapter->stats.txdropped++;
if ((++dropped_packet & 0xff) == 0xff)
printk("%s: %s droppped packets = %d\n",
netxen_nic_driver_name, netdev->name,
@@ -759,7 +868,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
*/
retry_getting_window:
spin_lock_bh(&adapter->tx_lock);
- if (adapter->total_threads == MAX_XMIT_PRODUCERS) {
+ if (adapter->total_threads >= MAX_XMIT_PRODUCERS) {
spin_unlock_bh(&adapter->tx_lock);
/*
* Yield CPU
@@ -792,15 +901,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if ((k + no_of_desc) >=
((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count :
last_cmd_consumer)) {
- port->stats.nocmddescriptor++;
- DPRINTK(ERR, "No command descriptors available,"
- " producer = %d, consumer = %d count=%llu,"
- " dropping packet\n", producer,
- adapter->last_cmd_consumer,
- port->stats.nocmddescriptor);
-
netif_stop_queue(netdev);
- port->flags |= NETXEN_NETDEV_STATUS;
+ adapter->flags |= NETXEN_NETDEV_STATUS;
spin_unlock_bh(&adapter->tx_lock);
return NETDEV_TX_BUSY;
}
@@ -828,16 +930,17 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
pbuf->skb = skb;
pbuf->cmd = TX_ETHER_PKT;
pbuf->frag_count = frag_count;
- pbuf->port = port->portnum;
+ pbuf->port = adapter->portnum;
buffrag = &pbuf->frag_array[0];
- buffrag->dma = pci_map_single(port->pdev, skb->data, first_seg_len,
+ buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len,
PCI_DMA_TODEVICE);
buffrag->length = first_seg_len;
netxen_set_cmd_desc_totallength(hwdesc, skb->len);
netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count);
netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT);
- netxen_set_cmd_desc_port(hwdesc, port->portnum);
+ netxen_set_cmd_desc_port(hwdesc, adapter->portnum);
+ netxen_set_cmd_desc_ctxid(hwdesc, adapter->portnum);
hwdesc->buffer1_length = cpu_to_le16(first_seg_len);
hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
@@ -860,7 +963,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
offset = frag->page_offset;
temp_len = len;
- temp_dma = pci_map_page(port->pdev, frag->page, offset,
+ temp_dma = pci_map_page(adapter->pdev, frag->page, offset,
len, PCI_DMA_TODEVICE);
buffrag++;
@@ -927,21 +1030,29 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
producer = get_next_index(producer, max_tx_desc_count);
}
}
+
+ i = netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]);
+
+ hw->cmd_desc_head[saved_producer].flags_opcode =
+ cpu_to_le16(hw->cmd_desc_head[saved_producer].flags_opcode);
+ hw->cmd_desc_head[saved_producer].num_of_buffers_total_length =
+ cpu_to_le32(hw->cmd_desc_head[saved_producer].
+ num_of_buffers_total_length);
+
spin_lock_bh(&adapter->tx_lock);
- port->stats.txbytes +=
- netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]);
+ adapter->stats.txbytes += i;
+
/* Code to update the adapter considering how many producer threads
are currently working */
if ((--adapter->num_threads) == 0) {
/* This is the last thread */
u32 crb_producer = adapter->cmd_producer;
- writel(crb_producer,
- NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET));
+ netxen_nic_update_cmd_producer(adapter, crb_producer);
wmb();
adapter->total_threads = 0;
}
- port->stats.xmitfinished++;
+ adapter->stats.xmitfinished++;
spin_unlock_bh(&adapter->tx_lock);
netdev->trans_start = jiffies;
@@ -961,27 +1072,26 @@ static void netxen_watchdog(unsigned long v)
static void netxen_tx_timeout(struct net_device *netdev)
{
- struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
-
- SCHEDULE_WORK(&port->tx_timeout_task);
+ struct netxen_adapter *adapter = (struct netxen_adapter *)
+ netdev_priv(netdev);
+ SCHEDULE_WORK(&adapter->tx_timeout_task);
}
static void netxen_tx_timeout_task(struct work_struct *work)
{
- struct netxen_port *port =
- container_of(work, struct netxen_port, tx_timeout_task);
- struct net_device *netdev = port->netdev;
+ struct netxen_adapter *adapter =
+ container_of(work, struct netxen_adapter, tx_timeout_task);
unsigned long flags;
printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
- netxen_nic_driver_name, netdev->name);
-
- spin_lock_irqsave(&port->adapter->lock, flags);
- netxen_nic_close(netdev);
- netxen_nic_open(netdev);
- spin_unlock_irqrestore(&port->adapter->lock, flags);
- netdev->trans_start = jiffies;
- netif_wake_queue(netdev);
+ netxen_nic_driver_name, adapter->netdev->name);
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ netxen_nic_close(adapter->netdev);
+ netxen_nic_open(adapter->netdev);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ adapter->netdev->trans_start = jiffies;
+ netif_wake_queue(adapter->netdev);
}
static int
@@ -990,17 +1100,16 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
u32 ret = 0;
DPRINTK(INFO, "Entered handle ISR\n");
-
adapter->stats.ints++;
if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
int count = 0;
u32 mask;
- mask = readl(pci_base_offset(adapter, ISR_INT_VECTOR));
- if ((mask & 0x80) == 0) {
- /* not our interrupt */
+ u32 our_int = 0;
+ our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+ /* not our interrupt */
+ if ((our_int & (0x80 << adapter->portnum)) == 0)
return ret;
- }
netxen_nic_disable_int(adapter);
/* Window = 0 or 1 */
do {
@@ -1012,7 +1121,6 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
printk("Could not disable interrupt completely\n");
}
- adapter->stats.hostints++;
if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) {
if (netif_rx_schedule_prep(netdev)) {
@@ -1046,33 +1154,24 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
irqreturn_t netxen_intr(int irq, void *data)
{
struct netxen_adapter *adapter;
- struct netxen_port *port;
struct net_device *netdev;
- int i;
if (unlikely(!irq)) {
return IRQ_NONE; /* Not our interrupt */
}
adapter = (struct netxen_adapter *)data;
- for (i = 0; i < adapter->ahw.max_ports; i++) {
- port = adapter->port[i];
- netdev = port->netdev;
-
- /* process our status queue (for all 4 ports) */
- if (netif_running(netdev)) {
- netxen_handle_int(adapter, netdev);
- break;
- }
- }
+ netdev = adapter->netdev;
+ /* process our status queue (for all 4 ports) */
+ if (netif_running(netdev))
+ netxen_handle_int(adapter, netdev);
return IRQ_HANDLED;
}
static int netxen_nic_poll(struct net_device *netdev, int *budget)
{
- struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
int work_to_do = min(*budget, netdev->quota);
int done = 1;
int ctx;
@@ -1080,7 +1179,6 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
int work_done = 0;
DPRINTK(INFO, "polling for %d descriptors\n", *budget);
- port->stats.polled++;
work_done = 0;
for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
@@ -1124,8 +1222,7 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
#ifdef CONFIG_NET_POLL_CONTROLLER
static void netxen_nic_poll_controller(struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
disable_irq(adapter->irq);
netxen_intr(adapter->irq, adapter);
enable_irq(adapter->irq);
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index d5d95074e569..cef90a78351e 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -88,12 +88,13 @@ static inline int phy_unlock(struct netxen_adapter *adapter)
* -1 on error
*
*/
-int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
- long reg, __u32 * readval)
+int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
+ __u32 * readval)
{
long timeout = 0;
long result = 0;
long restore = 0;
+ long phy = physical_port[adapter->portnum];
__u32 address;
__u32 command;
__u32 status;
@@ -183,12 +184,13 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
* -1 on error
*
*/
-int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
- long phy, long reg, __u32 val)
+int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg,
+ __u32 val)
{
long timeout = 0;
long result = 0;
long restore = 0;
+ long phy = physical_port[adapter->portnum];
__u32 address;
__u32 command;
__u32 status;
@@ -258,15 +260,13 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
return result;
}
-int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter)
{
netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f);
return 0;
}
-int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter)
{
int result = 0;
__u32 enable = 0;
@@ -275,7 +275,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
netxen_set_phy_int_speed_changed(enable);
if (0 !=
- netxen_niu_gbe_phy_write(adapter, port,
+ netxen_niu_gbe_phy_write(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE,
enable))
result = -EIO;
@@ -283,38 +283,34 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
return result;
}
-int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter)
{
netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f);
return 0;
}
-int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter)
{
int result = 0;
if (0 !=
- netxen_niu_gbe_phy_write(adapter, port,
+ netxen_niu_gbe_phy_write(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0))
result = -EIO;
return result;
}
-int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter)
{
netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1);
return 0;
}
-int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter)
{
int result = 0;
if (0 !=
- netxen_niu_gbe_phy_write(adapter, port,
+ netxen_niu_gbe_phy_write(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
-EIO))
result = -EIO;
@@ -355,9 +351,9 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter,
0x5);
}
- if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_enable_phy_interrupts(adapter))
printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");
- if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter))
printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
}
@@ -393,9 +389,9 @@ void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter,
0x5);
}
- if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_enable_phy_interrupts(adapter))
printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");
- if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter))
printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
}
@@ -404,11 +400,11 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
int result = 0;
__u32 status;
if (adapter->disable_phy_interrupts)
- adapter->disable_phy_interrupts(adapter, port);
+ adapter->disable_phy_interrupts(adapter);
mdelay(2);
if (0 ==
- netxen_niu_gbe_phy_read(adapter, port,
+ netxen_niu_gbe_phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status)) {
if (netxen_get_phy_link(status)) {
@@ -439,13 +435,13 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
| NETXEN_GB_MAC_ENABLE_TX_RX
|
NETXEN_GB_MAC_PAUSED_FRMS);
- if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter))
printk(KERN_ERR PFX
"ERROR clearing PHY interrupts\n");
- if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_enable_phy_interrupts(adapter))
printk(KERN_ERR PFX
"ERROR enabling PHY interrupts\n");
- if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter))
printk(KERN_ERR PFX
"ERROR clearing PHY interrupts\n");
result = -1;
@@ -458,26 +454,18 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
{
- u32 reg = 0, ret = 0;
+ u32 reg;
+ u32 portnum = physical_port[adapter->portnum];
- if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
- netxen_crb_writelit_adapter(adapter,
- NETXEN_NIU_XG1_CONFIG_0, 0x5);
- /* XXX hack for Mez cards: both ports in promisc mode */
- netxen_nic_hw_read_wx(adapter,
- NETXEN_NIU_XGE_CONFIG_1, &reg, 4);
- reg = (reg | 0x2000UL);
- netxen_crb_writelit_adapter(adapter,
- NETXEN_NIU_XGE_CONFIG_1, reg);
- reg = 0;
- netxen_nic_hw_read_wx(adapter,
- NETXEN_NIU_XG1_CONFIG_1, &reg, 4);
- reg = (reg | 0x2000UL);
- netxen_crb_writelit_adapter(adapter,
- NETXEN_NIU_XG1_CONFIG_1, reg);
- }
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_XGE_CONFIG_0+(0x10000*portnum), 0x5);
+ netxen_nic_hw_read_wx(adapter,
+ NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), &reg, 4);
+ reg = (reg & ~0x2000UL);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), reg);
- return ret;
+ return 0;
}
/*
@@ -498,7 +486,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
* The read of the PHY INT status will clear the pending
* interrupt status
*/
- if (netxen_niu_gbe_phy_read(adapter, port,
+ if (netxen_niu_gbe_phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
&int_src) != 0)
result = -EINVAL;
@@ -535,7 +523,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
printk(KERN_INFO PFX
"speed_changed or link status changed");
if (netxen_niu_gbe_phy_read
- (adapter, port,
+ (adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) == 0) {
if (netxen_get_phy_speed(status) == 2) {
@@ -581,10 +569,11 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
* Note that the passed-in value must already be in network byte order.
*/
int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
- int phy, netxen_ethernet_macaddr_t * addr)
+ netxen_ethernet_macaddr_t * addr)
{
u32 stationhigh;
u32 stationlow;
+ int phy = physical_port[adapter->portnum];
u8 val[8];
if (addr == NULL)
@@ -610,13 +599,12 @@ int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
* Set the station MAC address.
* Note that the passed-in value must already be in network byte order.
*/
-int netxen_niu_macaddr_set(struct netxen_port *port,
+int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t addr)
{
u8 temp[4];
u32 val;
- struct netxen_adapter *adapter = port->adapter;
- int phy = port->portnum;
+ int phy = physical_port[adapter->portnum];
unsigned char mac_addr[6];
int i;
@@ -634,7 +622,7 @@ int netxen_niu_macaddr_set(struct netxen_port *port,
(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4))
return -2;
- netxen_niu_macaddr_get(adapter, phy,
+ netxen_niu_macaddr_get(adapter,
(netxen_ethernet_macaddr_t *) mac_addr);
if (memcmp(mac_addr, addr, 6) == 0)
break;
@@ -642,7 +630,7 @@ int netxen_niu_macaddr_set(struct netxen_port *port,
if (i == 10) {
printk(KERN_ERR "%s: cannot set Mac addr for %s\n",
- netxen_nic_driver_name, port->netdev->name);
+ netxen_nic_driver_name, adapter->netdev->name);
printk(KERN_ERR "MAC address set: "
"%02x:%02x:%02x:%02x:%02x:%02x.\n",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
@@ -735,13 +723,13 @@ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter,
}
/* Disable a GbE interface */
-int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port)
+int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter)
{
__u32 mac_cfg0;
+ u32 port = physical_port[adapter->portnum];
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
return -EINVAL;
-
mac_cfg0 = 0;
netxen_gb_soft_reset(mac_cfg0);
if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
@@ -751,13 +739,13 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port)
}
/* Disable an XG interface */
-int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port)
+int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
{
__u32 mac_cfg;
+ u32 port = physical_port[adapter->portnum];
if (port != 0)
return -EINVAL;
-
mac_cfg = 0;
netxen_xg_soft_reset(mac_cfg);
if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_CONFIG_0,
@@ -767,10 +755,11 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port)
}
/* Set promiscuous mode for a GbE interface */
-int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
+int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
netxen_niu_prom_mode_t mode)
{
__u32 reg;
+ u32 port = physical_port[adapter->portnum];
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
return -EINVAL;
@@ -824,25 +813,50 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
* Set the MAC address for an XG port
* Note that the passed-in value must already be in network byte order.
*/
-int netxen_niu_xg_macaddr_set(struct netxen_port *port,
+int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t addr)
{
+ int phy = physical_port[adapter->portnum];
u8 temp[4];
u32 val;
- struct netxen_adapter *adapter = port->adapter;
+
+ if ((phy < 0) || (phy > NETXEN_NIU_MAX_XG_PORTS))
+ return -EIO;
temp[0] = temp[1] = 0;
- memcpy(temp + 2, addr, 2);
- val = le32_to_cpu(*(__le32 *)temp);
- if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
- &val, 4))
+ switch (phy) {
+ case 0:
+ memcpy(temp + 2, addr, 2);
+ val = le32_to_cpu(*(__le32 *)temp);
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
+ &val, 4))
return -EIO;
- memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
- val = le32_to_cpu(*(__le32 *)temp);
- if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
- &val, 4))
+ memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
+ val = le32_to_cpu(*(__le32 *)temp);
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
+ &val, 4))
+ return -EIO;
+ break;
+
+ case 1:
+ memcpy(temp + 2, addr, 2);
+ val = le32_to_cpu(*(__le32 *)temp);
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1,
+ &val, 4))
+ return -EIO;
+
+ memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
+ val = le32_to_cpu(*(__le32 *)temp);
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI,
+ &val, 4))
return -EIO;
+ break;
+
+ default:
+ printk(KERN_ERR "Unknown port %d\n", phy);
+ break;
+ }
return 0;
}
@@ -851,9 +865,10 @@ int netxen_niu_xg_macaddr_set(struct netxen_port *port,
* Return the current station MAC address.
* Note that the passed-in value must already be in network byte order.
*/
-int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
+int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t * addr)
{
+ int phy = physical_port[adapter->portnum];
u32 stationhigh;
u32 stationlow;
u8 val[8];
@@ -878,21 +893,24 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
}
int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
- int port, netxen_niu_prom_mode_t mode)
+ netxen_niu_prom_mode_t mode)
{
__u32 reg;
+ u32 port = physical_port[adapter->portnum];
- if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
return -EINVAL;
- if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_CONFIG_1, &reg, 4))
- return -EIO;
+ if (netxen_nic_hw_read_wx(adapter,
+ NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), &reg, 4))
+ return -EIO;
if (mode == NETXEN_NIU_PROMISC_MODE)
reg = (reg | 0x2000UL);
else
reg = (reg & ~0x2000UL);
- netxen_crb_writelit_adapter(adapter, NETXEN_NIU_XGE_CONFIG_1, reg);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg);
return 0;
}
diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h
index 0c7c94328b7f..9457fc7249c8 100644
--- a/drivers/net/netxen/netxen_nic_phan_reg.h
+++ b/drivers/net/netxen/netxen_nic_phan_reg.h
@@ -100,8 +100,21 @@
#define CRB_CMD_PRODUCER_OFFSET_1 NETXEN_NIC_REG(0x1ac)
#define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0)
+#define CRB_CMD_PRODUCER_OFFSET_2 NETXEN_NIC_REG(0x1b8)
+#define CRB_CMD_CONSUMER_OFFSET_2 NETXEN_NIC_REG(0x1bc)
+
+// 1c0 to 1cc used for signature reg
+#define CRB_CMD_PRODUCER_OFFSET_3 NETXEN_NIC_REG(0x1d0)
+#define CRB_CMD_CONSUMER_OFFSET_3 NETXEN_NIC_REG(0x1d4)
#define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4)
+#define CRB_V2P_0 NETXEN_NIC_REG(0x290)
+#define CRB_V2P_1 NETXEN_NIC_REG(0x294)
+#define CRB_V2P_2 NETXEN_NIC_REG(0x298)
+#define CRB_V2P_3 NETXEN_NIC_REG(0x29c)
+#define CRB_V2P(port) (CRB_V2P_0+((port)*4))
+#define CRB_DRIVER_VERSION NETXEN_NIC_REG(0x2a0)
+
/* used for ethtool tests */
#define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280)
@@ -139,128 +152,13 @@ struct netxen_recv_crb {
};
#if defined(DEFINE_GLOBAL_RECV_CRB)
-struct netxen_recv_crb recv_crb_registers[] = {
- /*
- * Instance 0.
- */
- {
- /* rcv_desc_crb: */
- {
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x100),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x104),
- /* crb_gloablrcv_ring: */
- NETXEN_NIC_REG(0x108),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x10c),
-
- },
- /* Jumbo frames */
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x110),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x114),
- /* crb_gloablrcv_ring: */
- NETXEN_NIC_REG(0x118),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x11c),
- },
- /* LRO */
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x120),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x124),
- /* crb_gloablrcv_ring: */
- NETXEN_NIC_REG(0x128),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x12c),
- }
- },
- /* crb_rcvstatus_ring: */
- NETXEN_NIC_REG(0x130),
- /* crb_rcv_status_producer: */
- NETXEN_NIC_REG(0x134),
- /* crb_rcv_status_consumer: */
- NETXEN_NIC_REG(0x138),
- /* crb_rcvpeg_state: */
- NETXEN_NIC_REG(0x13c),
- /* crb_status_ring_size */
- NETXEN_NIC_REG(0x140),
-
- },
- /*
- * Instance 1,
- */
- {
- /* rcv_desc_crb: */
- {
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x144),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x148),
- /* crb_globalrcv_ring: */
- NETXEN_NIC_REG(0x14c),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x150),
-
- },
- /* Jumbo frames */
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x154),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x158),
- /* crb_globalrcv_ring: */
- NETXEN_NIC_REG(0x15c),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x160),
- },
- /* LRO */
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x164),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x168),
- /* crb_globalrcv_ring: */
- NETXEN_NIC_REG(0x16c),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x170),
- }
-
- },
- /* crb_rcvstatus_ring: */
- NETXEN_NIC_REG(0x174),
- /* crb_rcv_status_producer: */
- NETXEN_NIC_REG(0x178),
- /* crb_rcv_status_consumer: */
- NETXEN_NIC_REG(0x17c),
- /* crb_rcvpeg_state: */
- NETXEN_NIC_REG(0x180),
- /* crb_status_ring_size */
- NETXEN_NIC_REG(0x184),
-
- },
-};
-
-u64 ctx_addr_sig_regs[][3] = {
- {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)},
- {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)},
- {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)},
- {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)}
-};
-
#else
extern struct netxen_recv_crb recv_crb_registers[];
extern u64 ctx_addr_sig_regs[][3];
-#define CRB_CTX_ADDR_REG_LO (ctx_addr_sig_regs[0][0])
-#define CRB_CTX_ADDR_REG_HI (ctx_addr_sig_regs[0][2])
-#define CRB_CTX_SIGNATURE_REG (ctx_addr_sig_regs[0][1])
#endif /* DEFINE_GLOBAL_RECEIVE_CRB */
+#define CRB_CTX_ADDR_REG_LO(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][0])
+#define CRB_CTX_ADDR_REG_HI(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][2])
+#define CRB_CTX_SIGNATURE_REG(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][1])
/*
* Temperature control.
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 0791360a6a66..9c171a7390e2 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -253,12 +253,12 @@ struct pcnet32_access {
* so the structure should be allocated using pci_alloc_consistent().
*/
struct pcnet32_private {
- struct pcnet32_init_block init_block;
+ struct pcnet32_init_block *init_block;
/* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
struct pcnet32_rx_head *rx_ring;
struct pcnet32_tx_head *tx_ring;
- dma_addr_t dma_addr;/* DMA address of beginning of this
- object, returned by pci_alloc_consistent */
+ dma_addr_t init_dma_addr;/* DMA address of beginning of the init block,
+ returned by pci_alloc_consistent */
struct pci_dev *pci_dev;
const char *name;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
@@ -653,7 +653,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
static void pcnet32_purge_rx_ring(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int i;
/* free all allocated skbuffs */
@@ -681,7 +681,7 @@ static void pcnet32_poll_controller(struct net_device *dev)
static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
int r = -EOPNOTSUPP;
@@ -696,7 +696,7 @@ static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
int r = -EOPNOTSUPP;
@@ -711,7 +711,7 @@ static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static void pcnet32_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
@@ -723,7 +723,7 @@ static void pcnet32_get_drvinfo(struct net_device *dev,
static u32 pcnet32_get_link(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
int r;
@@ -743,19 +743,19 @@ static u32 pcnet32_get_link(struct net_device *dev)
static u32 pcnet32_get_msglevel(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
return lp->msg_enable;
}
static void pcnet32_set_msglevel(struct net_device *dev, u32 value)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
lp->msg_enable = value;
}
static int pcnet32_nway_reset(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
int r = -EOPNOTSUPP;
@@ -770,7 +770,7 @@ static int pcnet32_nway_reset(struct net_device *dev)
static void pcnet32_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ering)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
ering->tx_max_pending = TX_MAX_RING_SIZE;
ering->tx_pending = lp->tx_ring_size;
@@ -781,7 +781,7 @@ static void pcnet32_get_ringparam(struct net_device *dev,
static int pcnet32_set_ringparam(struct net_device *dev,
struct ethtool_ringparam *ering)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
unsigned int size;
ulong ioaddr = dev->base_addr;
@@ -847,7 +847,7 @@ static int pcnet32_self_test_count(struct net_device *dev)
static void pcnet32_ethtool_test(struct net_device *dev,
struct ethtool_test *test, u64 * data)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int rc;
if (test->flags == ETH_TEST_FL_OFFLINE) {
@@ -868,7 +868,7 @@ static void pcnet32_ethtool_test(struct net_device *dev,
static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a; /* access to registers */
ulong ioaddr = dev->base_addr; /* card base I/O address */
struct sk_buff *skb; /* sk buff */
@@ -1047,7 +1047,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
static void pcnet32_led_blink_callback(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
unsigned long flags;
@@ -1064,7 +1064,7 @@ static void pcnet32_led_blink_callback(struct net_device *dev)
static int pcnet32_phys_id(struct net_device *dev, u32 data)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
unsigned long flags;
@@ -1109,7 +1109,7 @@ static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
int can_sleep)
{
int csr5;
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
int ticks;
@@ -1257,7 +1257,7 @@ static void pcnet32_rx_entry(struct net_device *dev,
static int pcnet32_rx(struct net_device *dev, int quota)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int entry = lp->cur_rx & lp->rx_mod_mask;
struct pcnet32_rx_head *rxp = &lp->rx_ring[entry];
int npackets = 0;
@@ -1282,7 +1282,7 @@ static int pcnet32_rx(struct net_device *dev, int quota)
static int pcnet32_tx(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned int dirty_tx = lp->dirty_tx;
int delta;
int must_restart = 0;
@@ -1381,7 +1381,7 @@ static int pcnet32_tx(struct net_device *dev)
#ifdef CONFIG_PCNET32_NAPI
static int pcnet32_poll(struct net_device *dev, int *budget)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int quota = min(dev->quota, *budget);
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
@@ -1428,7 +1428,7 @@ static int pcnet32_poll(struct net_device *dev, int *budget)
#define PCNET32_MAX_PHYS 32
static int pcnet32_get_regs_len(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int j = lp->phycount * PCNET32_REGS_PER_PHY;
return ((PCNET32_NUM_REGS + j) * sizeof(u16));
@@ -1439,7 +1439,7 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
{
int i, csr0;
u16 *buff = ptr;
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
unsigned long flags;
@@ -1592,7 +1592,6 @@ static int __devinit
pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
{
struct pcnet32_private *lp;
- dma_addr_t lp_dma_addr;
int i, media;
int fdx, mii, fset, dxsuflo;
int chip_version;
@@ -1714,7 +1713,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
dxsuflo = 1;
}
- dev = alloc_etherdev(0);
+ dev = alloc_etherdev(sizeof(*lp));
if (!dev) {
if (pcnet32_debug & NETIF_MSG_PROBE)
printk(KERN_ERR PFX "Memory allocation failed.\n");
@@ -1805,25 +1804,22 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
}
dev->base_addr = ioaddr;
+ lp = netdev_priv(dev);
/* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
- if ((lp =
- pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) {
+ if ((lp->init_block =
+ pci_alloc_consistent(pdev, sizeof(*lp->init_block), &lp->init_dma_addr)) == NULL) {
if (pcnet32_debug & NETIF_MSG_PROBE)
printk(KERN_ERR PFX
"Consistent memory allocation failed.\n");
ret = -ENOMEM;
goto err_free_netdev;
}
-
- memset(lp, 0, sizeof(*lp));
- lp->dma_addr = lp_dma_addr;
lp->pci_dev = pdev;
spin_lock_init(&lp->lock);
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- dev->priv = lp;
lp->name = chipname;
lp->shared_irq = shared;
lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */
@@ -1870,23 +1866,21 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
&& dev->dev_addr[2] == 0x75)
lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
- lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */
- lp->init_block.tlen_rlen =
+ lp->init_block->mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */
+ lp->init_block->tlen_rlen =
le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
for (i = 0; i < 6; i++)
- lp->init_block.phys_addr[i] = dev->dev_addr[i];
- lp->init_block.filter[0] = 0x00000000;
- lp->init_block.filter[1] = 0x00000000;
- lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
- lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+ lp->init_block->phys_addr[i] = dev->dev_addr[i];
+ lp->init_block->filter[0] = 0x00000000;
+ lp->init_block->filter[1] = 0x00000000;
+ lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
+ lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
/* switch pcnet32 to 32bit mode */
a->write_bcr(ioaddr, 20, 2);
- a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private,
- init_block)) & 0xffff);
- a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private,
- init_block)) >> 16);
+ a->write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
+ a->write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
if (pdev) { /* use the IRQ provided by PCI */
dev->irq = pdev->irq;
@@ -1992,7 +1986,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
err_free_ring:
pcnet32_free_ring(dev);
err_free_consistent:
- pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+ pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
+ lp->init_block, lp->init_dma_addr);
err_free_netdev:
free_netdev(dev);
err_release_region:
@@ -2003,7 +1998,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
/* if any allocation fails, caller must also call pcnet32_free_ring */
static int pcnet32_alloc_ring(struct net_device *dev, char *name)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
lp->tx_ring = pci_alloc_consistent(lp->pci_dev,
sizeof(struct pcnet32_tx_head) *
@@ -2070,7 +2065,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
static void pcnet32_free_ring(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
kfree(lp->tx_skbuff);
lp->tx_skbuff = NULL;
@@ -2103,7 +2098,7 @@ static void pcnet32_free_ring(struct net_device *dev)
static int pcnet32_open(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
u16 val;
int i;
@@ -2134,8 +2129,7 @@ static int pcnet32_open(struct net_device *dev)
"%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr),
(u32) (lp->rx_ring_dma_addr),
- (u32) (lp->dma_addr +
- offsetof(struct pcnet32_private, init_block)));
+ (u32) (lp->init_dma_addr));
/* set/reset autoselect bit */
val = lp->a.read_bcr(ioaddr, 2) & ~2;
@@ -2274,7 +2268,7 @@ static int pcnet32_open(struct net_device *dev)
}
#endif
- lp->init_block.mode =
+ lp->init_block->mode =
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
pcnet32_load_multicast(dev);
@@ -2284,12 +2278,8 @@ static int pcnet32_open(struct net_device *dev)
}
/* Re-initialize the PCNET32, and start it when done. */
- lp->a.write_csr(ioaddr, 1, (lp->dma_addr +
- offsetof(struct pcnet32_private,
- init_block)) & 0xffff);
- lp->a.write_csr(ioaddr, 2,
- (lp->dma_addr +
- offsetof(struct pcnet32_private, init_block)) >> 16);
+ lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
+ lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
@@ -2316,8 +2306,7 @@ static int pcnet32_open(struct net_device *dev)
printk(KERN_DEBUG
"%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n",
dev->name, i,
- (u32) (lp->dma_addr +
- offsetof(struct pcnet32_private, init_block)),
+ (u32) (lp->init_dma_addr),
lp->a.read_csr(ioaddr, CSR0));
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2355,7 +2344,7 @@ static int pcnet32_open(struct net_device *dev)
static void pcnet32_purge_tx_ring(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int i;
for (i = 0; i < lp->tx_ring_size; i++) {
@@ -2375,7 +2364,7 @@ static void pcnet32_purge_tx_ring(struct net_device *dev)
/* Initialize the PCNET32 Rx and Tx rings. */
static int pcnet32_init_ring(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int i;
lp->tx_full = 0;
@@ -2417,12 +2406,12 @@ static int pcnet32_init_ring(struct net_device *dev)
lp->tx_dma_addr[i] = 0;
}
- lp->init_block.tlen_rlen =
+ lp->init_block->tlen_rlen =
le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
for (i = 0; i < 6; i++)
- lp->init_block.phys_addr[i] = dev->dev_addr[i];
- lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
- lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+ lp->init_block->phys_addr[i] = dev->dev_addr[i];
+ lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
+ lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
wmb(); /* Make sure all changes are visible */
return 0;
}
@@ -2433,7 +2422,7 @@ static int pcnet32_init_ring(struct net_device *dev)
*/
static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
int i;
@@ -2463,7 +2452,7 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
static void pcnet32_tx_timeout(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr, flags;
spin_lock_irqsave(&lp->lock, flags);
@@ -2504,7 +2493,7 @@ static void pcnet32_tx_timeout(struct net_device *dev)
static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
u16 status;
int entry;
@@ -2569,7 +2558,7 @@ pcnet32_interrupt(int irq, void *dev_id)
int boguscnt = max_interrupt_work;
ioaddr = dev->base_addr;
- lp = dev->priv;
+ lp = netdev_priv(dev);
spin_lock(&lp->lock);
@@ -2651,7 +2640,7 @@ pcnet32_interrupt(int irq, void *dev_id)
static int pcnet32_close(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr;
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
@@ -2692,7 +2681,7 @@ static int pcnet32_close(struct net_device *dev)
static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
@@ -2706,8 +2695,8 @@ static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
/* taken from the sunlance driver, which it took from the depca driver */
static void pcnet32_load_multicast(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
- volatile struct pcnet32_init_block *ib = &lp->init_block;
+ struct pcnet32_private *lp = netdev_priv(dev);
+ volatile struct pcnet32_init_block *ib = lp->init_block;
volatile u16 *mcast_table = (u16 *) & ib->filter;
struct dev_mc_list *dmi = dev->mc_list;
unsigned long ioaddr = dev->base_addr;
@@ -2756,7 +2745,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
static void pcnet32_set_multicast_list(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr, flags;
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int csr15, suspended;
spin_lock_irqsave(&lp->lock, flags);
@@ -2767,12 +2756,12 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
if (netif_msg_hw(lp))
printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
dev->name);
- lp->init_block.mode =
+ lp->init_block->mode =
le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
} else {
- lp->init_block.mode =
+ lp->init_block->mode =
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
pcnet32_load_multicast(dev);
@@ -2795,7 +2784,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
/* This routine assumes that the lp->lock is held */
static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
u16 val_out;
@@ -2811,7 +2800,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
/* This routine assumes that the lp->lock is held */
static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
if (!lp->mii)
@@ -2823,7 +2812,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int rc;
unsigned long flags;
@@ -2841,7 +2830,7 @@ static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static int pcnet32_check_otherphy(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct mii_if_info mii = lp->mii_if;
u16 bmcr;
int i;
@@ -2888,7 +2877,7 @@ static int pcnet32_check_otherphy(struct net_device *dev)
static void pcnet32_check_media(struct net_device *dev, int verbose)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int curr_link;
int prev_link = netif_carrier_ok(dev) ? 1 : 0;
u32 bcr9;
@@ -2944,7 +2933,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
static void pcnet32_watchdog(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
/* Print the link status if it has changed */
@@ -2960,12 +2949,13 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
if (dev) {
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unregister_netdev(dev);
pcnet32_free_ring(dev);
release_region(dev->base_addr, PCNET32_TOTAL_SIZE);
- pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+ pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
+ lp->init_block, lp->init_dma_addr);
free_netdev(dev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
@@ -3040,12 +3030,13 @@ static void __exit pcnet32_cleanup_module(void)
struct net_device *next_dev;
while (pcnet32_dev) {
- struct pcnet32_private *lp = pcnet32_dev->priv;
+ struct pcnet32_private *lp = netdev_priv(pcnet32_dev);
next_dev = lp->next;
unregister_netdev(pcnet32_dev);
pcnet32_free_ring(pcnet32_dev);
release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
- pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+ pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
+ lp->init_block, lp->init_dma_addr);
free_netdev(pcnet32_dev);
pcnet32_dev = next_dev;
}
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index b31ce278bf35..fc4aee96cdfd 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -35,10 +35,14 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-/* mdiobus_register
+/**
+ * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
+ * @bus: target mii_bus
*
- * description: Called by a bus driver to bring up all the PHYs
- * on a given bus, and attach them to the bus
+ * Description: Called by a bus driver to bring up all the PHYs
+ * on a given bus, and attach them to the bus.
+ *
+ * Returns 0 on success or < 0 on error.
*/
int mdiobus_register(struct mii_bus *bus)
{
@@ -114,10 +118,13 @@ void mdiobus_unregister(struct mii_bus *bus)
}
EXPORT_SYMBOL(mdiobus_unregister);
-/* mdio_bus_match
+/**
+ * mdio_bus_match - determine if given PHY driver supports the given PHY device
+ * @dev: target PHY device
+ * @drv: given PHY driver
*
- * description: Given a PHY device, and a PHY driver, return 1 if
- * the driver supports the device. Otherwise, return 0
+ * Description: Given a PHY device, and a PHY driver, return 1 if
+ * the driver supports the device. Otherwise, return 0.
*/
static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index c94a1fb3a4be..eed433d6056a 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -39,7 +39,9 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-/* Convenience function to print out the current phy status
+/**
+ * phy_print_status - Convenience function to print out the current phy status
+ * @phydev: the phy_device struct
*/
void phy_print_status(struct phy_device *phydev)
{
@@ -55,10 +57,15 @@ void phy_print_status(struct phy_device *phydev)
EXPORT_SYMBOL(phy_print_status);
-/* Convenience functions for reading/writing a given PHY
- * register. They MUST NOT be called from interrupt context,
+/**
+ * phy_read - Convenience function for reading a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to read
+ *
+ * NOTE: MUST NOT be called from interrupt context,
* because the bus read/write functions may wait for an interrupt
- * to conclude the operation. */
+ * to conclude the operation.
+ */
int phy_read(struct phy_device *phydev, u16 regnum)
{
int retval;
@@ -72,6 +79,16 @@ int phy_read(struct phy_device *phydev, u16 regnum)
}
EXPORT_SYMBOL(phy_read);
+/**
+ * phy_write - Convenience function for writing a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
{
int err;
@@ -85,7 +102,15 @@ int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
}
EXPORT_SYMBOL(phy_write);
-
+/**
+ * phy_clear_interrupt - Ack the phy device's interrupt
+ * @phydev: the phy_device struct
+ *
+ * If the @phydev driver has an ack_interrupt function, call it to
+ * ack and clear the phy device's interrupt.
+ *
+ * Returns 0 on success on < 0 on error.
+ */
int phy_clear_interrupt(struct phy_device *phydev)
{
int err = 0;
@@ -96,7 +121,13 @@ int phy_clear_interrupt(struct phy_device *phydev)
return err;
}
-
+/**
+ * phy_config_interrupt - configure the PHY device for the requested interrupts
+ * @phydev: the phy_device struct
+ * @interrupts: interrupt flags to configure for this @phydev
+ *
+ * Returns 0 on success on < 0 on error.
+ */
int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
{
int err = 0;
@@ -109,9 +140,11 @@ int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
}
-/* phy_aneg_done
+/**
+ * phy_aneg_done - return auto-negotiation status
+ * @phydev: target phy_device struct
*
- * description: Reads the status register and returns 0 either if
+ * Description: Reads the status register and returns 0 either if
* auto-negotiation is incomplete, or if there was an error.
* Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
*/
@@ -173,9 +206,12 @@ static const struct phy_setting settings[] = {
#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))
-/* phy_find_setting
+/**
+ * phy_find_setting - find a PHY settings array entry that matches speed & duplex
+ * @speed: speed to match
+ * @duplex: duplex to match
*
- * description: Searches the settings array for the setting which
+ * Description: Searches the settings array for the setting which
* matches the desired speed and duplex, and returns the index
* of that setting. Returns the index of the last setting if
* none of the others match.
@@ -192,11 +228,12 @@ static inline int phy_find_setting(int speed, int duplex)
return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
}
-/* phy_find_valid
- * idx: The first index in settings[] to search
- * features: A mask of the valid settings
+/**
+ * phy_find_valid - find a PHY setting that matches the requested features mask
+ * @idx: The first index in settings[] to search
+ * @features: A mask of the valid settings
*
- * description: Returns the index of the first valid setting less
+ * Description: Returns the index of the first valid setting less
* than or equal to the one pointed to by idx, as determined by
* the mask in features. Returns the index of the last setting
* if nothing else matches.
@@ -209,11 +246,13 @@ static inline int phy_find_valid(int idx, u32 features)
return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
}
-/* phy_sanitize_settings
+/**
+ * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex
+ * @phydev: the target phy_device struct
*
- * description: Make sure the PHY is set to supported speeds and
+ * Description: Make sure the PHY is set to supported speeds and
* duplexes. Drop down by one in this order: 1000/FULL,
- * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF
+ * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
*/
void phy_sanitize_settings(struct phy_device *phydev)
{
@@ -232,16 +271,17 @@ void phy_sanitize_settings(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_sanitize_settings);
-/* phy_ethtool_sset:
- * A generic ethtool sset function. Handles all the details
+/**
+ * phy_ethtool_sset - generic ethtool sset function, handles all the details
+ * @phydev: target phy_device struct
+ * @cmd: ethtool_cmd
*
* A few notes about parameter checking:
* - We don't set port or transceiver, so we don't care what they
* were set to.
* - phy_start_aneg() will make sure forced settings are sane, and
* choose the next best ones from the ones selected, so we don't
- * care if ethtool tries to give us bad values
- *
+ * care if ethtool tries to give us bad values.
*/
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
{
@@ -304,9 +344,15 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
}
EXPORT_SYMBOL(phy_ethtool_gset);
-/* Note that this function is currently incompatible with the
+/**
+ * phy_mii_ioctl - generic PHY MII ioctl interface
+ * @phydev: the phy_device struct
+ * @mii_data: MII ioctl data
+ * @cmd: ioctl cmd to execute
+ *
+ * Note that this function is currently incompatible with the
* PHYCONTROL layer. It changes registers without regard to
- * current state. Use at own risk
+ * current state. Use at own risk.
*/
int phy_mii_ioctl(struct phy_device *phydev,
struct mii_ioctl_data *mii_data, int cmd)
@@ -336,6 +382,12 @@ int phy_mii_ioctl(struct phy_device *phydev,
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
+ if ((!phydev->autoneg) &&
+ (val & BMCR_SPEED1000))
+ phydev->speed = SPEED_1000;
+ else if ((!phydev->autoneg) &&
+ (val & BMCR_SPEED100))
+ phydev->speed = SPEED_100;
break;
case MII_ADVERTISE:
phydev->advertising = val;
@@ -358,13 +410,14 @@ int phy_mii_ioctl(struct phy_device *phydev,
return 0;
}
-/* phy_start_aneg
+/**
+ * phy_start_aneg - start auto-negotiation for this PHY device
+ * @phydev: the phy_device struct
*
- * description: Sanitizes the settings (if we're not
- * autonegotiating them), and then calls the driver's
- * config_aneg function. If the PHYCONTROL Layer is operating,
- * we change the state to reflect the beginning of
- * Auto-negotiation or forcing.
+ * Description: Sanitizes the settings (if we're not autonegotiating
+ * them), and then calls the driver's config_aneg function.
+ * If the PHYCONTROL Layer is operating, we change the state to
+ * reflect the beginning of Auto-negotiation or forcing.
*/
int phy_start_aneg(struct phy_device *phydev)
{
@@ -400,15 +453,19 @@ EXPORT_SYMBOL(phy_start_aneg);
static void phy_change(struct work_struct *work);
static void phy_timer(unsigned long data);
-/* phy_start_machine:
+/**
+ * phy_start_machine - start PHY state machine tracking
+ * @phydev: the phy_device struct
+ * @handler: callback function for state change notifications
*
- * description: The PHY infrastructure can run a state machine
+ * Description: The PHY infrastructure can run a state machine
* which tracks whether the PHY is starting up, negotiating,
* etc. This function starts the timer which tracks the state
- * of the PHY. If you want to be notified when the state
- * changes, pass in the callback, otherwise, pass NULL. If you
+ * of the PHY. If you want to be notified when the state changes,
+ * pass in the callback @handler, otherwise, pass NULL. If you
* want to maintain your own state machine, do not call this
- * function. */
+ * function.
+ */
void phy_start_machine(struct phy_device *phydev,
void (*handler)(struct net_device *))
{
@@ -420,9 +477,11 @@ void phy_start_machine(struct phy_device *phydev,
mod_timer(&phydev->phy_timer, jiffies + HZ);
}
-/* phy_stop_machine
+/**
+ * phy_stop_machine - stop the PHY state machine tracking
+ * @phydev: target phy_device struct
*
- * description: Stops the state machine timer, sets the state to UP
+ * Description: Stops the state machine timer, sets the state to UP
* (unless it wasn't up yet). This function must be called BEFORE
* phy_detach.
*/
@@ -438,12 +497,14 @@ void phy_stop_machine(struct phy_device *phydev)
phydev->adjust_state = NULL;
}
-/* phy_force_reduction
+/**
+ * phy_force_reduction - reduce PHY speed/duplex settings by one step
+ * @phydev: target phy_device struct
*
- * description: Reduces the speed/duplex settings by
- * one notch. The order is so:
- * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF,
- * 10/FULL, 10/HALF. The function bottoms out at 10/HALF.
+ * Description: Reduces the speed/duplex settings by one notch,
+ * in this order--
+ * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
+ * The function bottoms out at 10/HALF.
*/
static void phy_force_reduction(struct phy_device *phydev)
{
@@ -464,7 +525,9 @@ static void phy_force_reduction(struct phy_device *phydev)
}
-/* phy_error:
+/**
+ * phy_error - enter HALTED state for this PHY device
+ * @phydev: target phy_device struct
*
* Moves the PHY to the HALTED state in response to a read
* or write error, and tells the controller the link is down.
@@ -478,9 +541,12 @@ void phy_error(struct phy_device *phydev)
spin_unlock(&phydev->lock);
}
-/* phy_interrupt
+/**
+ * phy_interrupt - PHY interrupt handler
+ * @irq: interrupt line
+ * @phy_dat: phy_device pointer
*
- * description: When a PHY interrupt occurs, the handler disables
+ * Description: When a PHY interrupt occurs, the handler disables
* interrupts, and schedules a work task to clear the interrupt.
*/
static irqreturn_t phy_interrupt(int irq, void *phy_dat)
@@ -501,7 +567,10 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
return IRQ_HANDLED;
}
-/* Enable the interrupts from the PHY side */
+/**
+ * phy_enable_interrupts - Enable the interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
int phy_enable_interrupts(struct phy_device *phydev)
{
int err;
@@ -517,7 +586,10 @@ int phy_enable_interrupts(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_enable_interrupts);
-/* Disable the PHY interrupts from the PHY side */
+/**
+ * phy_disable_interrupts - Disable the PHY interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
int phy_disable_interrupts(struct phy_device *phydev)
{
int err;
@@ -543,13 +615,15 @@ phy_err:
}
EXPORT_SYMBOL(phy_disable_interrupts);
-/* phy_start_interrupts
+/**
+ * phy_start_interrupts - request and enable interrupts for a PHY device
+ * @phydev: target phy_device struct
*
- * description: Request the interrupt for the given PHY. If
- * this fails, then we set irq to PHY_POLL.
+ * Description: Request the interrupt for the given PHY.
+ * If this fails, then we set irq to PHY_POLL.
* Otherwise, we enable the interrupts in the PHY.
- * Returns 0 on success.
* This should only be called with a valid IRQ number.
+ * Returns 0 on success or < 0 on error.
*/
int phy_start_interrupts(struct phy_device *phydev)
{
@@ -574,6 +648,10 @@ int phy_start_interrupts(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_start_interrupts);
+/**
+ * phy_stop_interrupts - disable interrupts from a PHY device
+ * @phydev: target phy_device struct
+ */
int phy_stop_interrupts(struct phy_device *phydev)
{
int err;
@@ -596,7 +674,10 @@ int phy_stop_interrupts(struct phy_device *phydev)
EXPORT_SYMBOL(phy_stop_interrupts);
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
+/**
+ * phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes
+ * @work: work_struct that describes the work to be done
+ */
static void phy_change(struct work_struct *work)
{
int err;
@@ -630,7 +711,10 @@ phy_err:
phy_error(phydev);
}
-/* Bring down the PHY link, and stop checking the status. */
+/**
+ * phy_stop - Bring down the PHY link, and stop checking the status
+ * @phydev: target phy_device struct
+ */
void phy_stop(struct phy_device *phydev)
{
spin_lock(&phydev->lock);
@@ -659,9 +743,11 @@ out_unlock:
}
-/* phy_start
+/**
+ * phy_start - start or restart a PHY device
+ * @phydev: target phy_device struct
*
- * description: Indicates the attached device's readiness to
+ * Description: Indicates the attached device's readiness to
* handle PHY-related work. Used during startup to start the
* PHY, and after a call to phy_stop() to resume operation.
* Also used to indicate the MDIO bus has cleared an error
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8f01952c4850..a8b74cdab1ea 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -74,11 +74,13 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
}
EXPORT_SYMBOL(phy_device_create);
-/* get_phy_device
+/**
+ * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
*
- * description: Reads the ID registers of the PHY at addr on the
- * bus, then allocates and returns the phy_device to
- * represent it.
+ * Description: Reads the ID registers of the PHY at @addr on the
+ * @bus, then allocates and returns the phy_device to represent it.
*/
struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
{
@@ -112,23 +114,33 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
return dev;
}
-/* phy_prepare_link:
+/**
+ * phy_prepare_link - prepares the PHY layer to monitor link status
+ * @phydev: target phy_device struct
+ * @handler: callback function for link status change notifications
*
- * description: Tells the PHY infrastructure to handle the
+ * Description: Tells the PHY infrastructure to handle the
* gory details on monitoring link status (whether through
* polling or an interrupt), and to call back to the
* connected device driver when the link status changes.
* If you want to monitor your own link state, don't call
- * this function */
+ * this function.
+ */
void phy_prepare_link(struct phy_device *phydev,
void (*handler)(struct net_device *))
{
phydev->adjust_link = handler;
}
-/* phy_connect:
+/**
+ * phy_connect - connect an ethernet device to a PHY device
+ * @dev: the network device to connect
+ * @phy_id: the PHY device to connect
+ * @handler: callback function for state change notifications
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
*
- * description: Convenience function for connecting ethernet
+ * Description: Convenience function for connecting ethernet
* devices to PHY devices. The default behavior is for
* the PHY infrastructure to handle everything, and only notify
* the connected driver when the link status changes. If you
@@ -158,6 +170,10 @@ struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
}
EXPORT_SYMBOL(phy_connect);
+/**
+ * phy_disconnect - disable interrupts, stop state machine, and detach a PHY device
+ * @phydev: target phy_device struct
+ */
void phy_disconnect(struct phy_device *phydev)
{
if (phydev->irq > 0)
@@ -171,21 +187,25 @@ void phy_disconnect(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_disconnect);
-/* phy_attach:
+static int phy_compare_id(struct device *dev, void *data)
+{
+ return strcmp((char *)data, dev->bus_id) ? 0 : 1;
+}
+
+/**
+ * phy_attach - attach a network device to a particular PHY device
+ * @dev: network device to attach
+ * @phy_id: PHY device to attach
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
*
- * description: Called by drivers to attach to a particular PHY
+ * Description: Called by drivers to attach to a particular PHY
* device. The phy_device is found, and properly hooked up
* to the phy_driver. If no driver is attached, then the
* genphy_driver is used. The phy_device is given a ptr to
* the attaching device, and given a callback for link status
- * change. The phy_device is returned to the attaching
- * driver.
+ * change. The phy_device is returned to the attaching driver.
*/
-static int phy_compare_id(struct device *dev, void *data)
-{
- return strcmp((char *)data, dev->bus_id) ? 0 : 1;
-}
-
struct phy_device *phy_attach(struct net_device *dev,
const char *phy_id, u32 flags, phy_interface_t interface)
{
@@ -246,6 +266,10 @@ struct phy_device *phy_attach(struct net_device *dev,
}
EXPORT_SYMBOL(phy_attach);
+/**
+ * phy_detach - detach a PHY device from its network device
+ * @phydev: target phy_device struct
+ */
void phy_detach(struct phy_device *phydev)
{
phydev->attached_dev = NULL;
@@ -262,11 +286,13 @@ EXPORT_SYMBOL(phy_detach);
/* Generic PHY support and helper functions */
-/* genphy_config_advert
+/**
+ * genphy_config_advert - sanitize and advertise auto-negotation parameters
+ * @phydev: target phy_device struct
*
- * description: Writes MII_ADVERTISE with the appropriate values,
+ * Description: Writes MII_ADVERTISE with the appropriate values,
* after sanitizing the values to make sure we only advertise
- * what is supported
+ * what is supported.
*/
int genphy_config_advert(struct phy_device *phydev)
{
@@ -328,11 +354,14 @@ int genphy_config_advert(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_config_advert);
-/* genphy_setup_forced
+/**
+ * genphy_setup_forced - configures/forces speed/duplex from @phydev
+ * @phydev: target phy_device struct
*
- * description: Configures MII_BMCR to force speed/duplex
+ * Description: Configures MII_BMCR to force speed/duplex
* to the values in phydev. Assumes that the values are valid.
- * Please see phy_sanitize_settings() */
+ * Please see phy_sanitize_settings().
+ */
int genphy_setup_forced(struct phy_device *phydev)
{
int ctl = BMCR_RESET;
@@ -361,7 +390,10 @@ int genphy_setup_forced(struct phy_device *phydev)
}
-/* Enable and Restart Autonegotiation */
+/**
+ * genphy_restart_aneg - Enable and Restart Autonegotiation
+ * @phydev: target phy_device struct
+ */
int genphy_restart_aneg(struct phy_device *phydev)
{
int ctl;
@@ -382,11 +414,13 @@ int genphy_restart_aneg(struct phy_device *phydev)
}
-/* genphy_config_aneg
+/**
+ * genphy_config_aneg - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
*
- * description: If auto-negotiation is enabled, we configure the
+ * Description: If auto-negotiation is enabled, we configure the
* advertising, and then restart auto-negotiation. If it is not
- * enabled, then we write the BMCR
+ * enabled, then we write the BMCR.
*/
int genphy_config_aneg(struct phy_device *phydev)
{
@@ -406,11 +440,13 @@ int genphy_config_aneg(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_config_aneg);
-/* genphy_update_link
+/**
+ * genphy_update_link - update link status in @phydev
+ * @phydev: target phy_device struct
*
- * description: Update the value in phydev->link to reflect the
+ * Description: Update the value in phydev->link to reflect the
* current link value. In order to do this, we need to read
- * the status register twice, keeping the second value
+ * the status register twice, keeping the second value.
*/
int genphy_update_link(struct phy_device *phydev)
{
@@ -437,9 +473,11 @@ int genphy_update_link(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_update_link);
-/* genphy_read_status
+/**
+ * genphy_read_status - check the link status and update current link state
+ * @phydev: target phy_device struct
*
- * description: Check the link, then figure out the current state
+ * Description: Check the link, then figure out the current state
* by comparing what we advertise with what the link partner
* advertises. Start by checking the gigabit possibilities,
* then move on to 10/100.
@@ -579,9 +617,11 @@ static int genphy_config_init(struct phy_device *phydev)
}
-/* phy_probe
+/**
+ * phy_probe - probe and init a PHY device
+ * @dev: device to probe and init
*
- * description: Take care of setting up the phy_device structure,
+ * Description: Take care of setting up the phy_device structure,
* set the state to READY (the driver's init function should
* set it to STARTING if needed).
*/
@@ -643,6 +683,10 @@ static int phy_remove(struct device *dev)
return 0;
}
+/**
+ * phy_driver_register - register a phy_driver with the PHY layer
+ * @new_driver: new phy_driver to register
+ */
int phy_driver_register(struct phy_driver *new_driver)
{
int retval;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 7b80fb7a9d9b..d8766c0e8255 100755
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -39,7 +39,7 @@
#define DRV_NAME "qla3xxx"
#define DRV_STRING "QLogic ISP3XXX Network Driver"
-#define DRV_VERSION "v2.03.00-k3"
+#define DRV_VERSION "v2.03.00-k4"
#define PFX DRV_NAME " "
static const char ql3xxx_driver_name[] = DRV_NAME;
@@ -72,6 +72,30 @@ static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl);
/*
+ * These are the known PHY's which are used
+ */
+typedef enum {
+ PHY_TYPE_UNKNOWN = 0,
+ PHY_VITESSE_VSC8211,
+ PHY_AGERE_ET1011C,
+ MAX_PHY_DEV_TYPES
+} PHY_DEVICE_et;
+
+typedef struct {
+ PHY_DEVICE_et phyDevice;
+ u32 phyIdOUI;
+ u16 phyIdModel;
+ char *name;
+} PHY_DEVICE_INFO_t;
+
+static const PHY_DEVICE_INFO_t PHY_DEVICES[] =
+ {{PHY_TYPE_UNKNOWN, 0x000000, 0x0, "PHY_TYPE_UNKNOWN"},
+ {PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"},
+ {PHY_AGERE_ET1011C, 0x00a0bc, 0x1, "PHY_AGERE_ET1011C"},
+};
+
+
+/*
* Caller must take hw_lock.
*/
static int ql_sem_spinlock(struct ql3_adapter *qdev,
@@ -662,7 +686,7 @@ static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev)
}
static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
- u16 regAddr, u16 value, u32 mac_index)
+ u16 regAddr, u16 value, u32 phyAddr)
{
struct ql3xxx_port_registers __iomem *port_regs =
qdev->mem_map_registers;
@@ -680,7 +704,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
}
ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
- PHYAddr[mac_index] | regAddr);
+ phyAddr | regAddr);
ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
@@ -701,7 +725,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
}
static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
- u16 * value, u32 mac_index)
+ u16 * value, u32 phyAddr)
{
struct ql3xxx_port_registers __iomem *port_regs =
qdev->mem_map_registers;
@@ -720,7 +744,7 @@ static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
}
ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
- PHYAddr[mac_index] | regAddr);
+ phyAddr | regAddr);
ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
(MAC_MII_CONTROL_RC << 16));
@@ -850,28 +874,31 @@ static void ql_petbi_start_neg(struct ql3_adapter *qdev)
}
-static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_reset_ex(struct ql3_adapter *qdev)
{
ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET,
- mac_index);
+ PHYAddr[qdev->mac_index]);
}
-static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev)
{
u16 reg;
/* Enable Auto-negotiation sense */
- ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg, mac_index);
+ ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg,
+ PHYAddr[qdev->mac_index]);
reg |= PETBI_TBI_AUTO_SENSE;
- ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, mac_index);
+ ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg,
+ PHYAddr[qdev->mac_index]);
ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
- PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index);
+ PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX,
+ PHYAddr[qdev->mac_index]);
ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG,
PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000,
- mac_index);
+ PHYAddr[qdev->mac_index]);
}
static void ql_petbi_init(struct ql3_adapter *qdev)
@@ -880,10 +907,10 @@ static void ql_petbi_init(struct ql3_adapter *qdev)
ql_petbi_start_neg(qdev);
}
-static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_init_ex(struct ql3_adapter *qdev)
{
- ql_petbi_reset_ex(qdev, mac_index);
- ql_petbi_start_neg_ex(qdev, mac_index);
+ ql_petbi_reset_ex(qdev);
+ ql_petbi_start_neg_ex(qdev);
}
static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
@@ -896,33 +923,128 @@ static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE;
}
+static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
+{
+ printk(KERN_INFO "%s: enabling Agere specific PHY\n", qdev->ndev->name);
+ /* power down device bit 11 = 1 */
+ ql_mii_write_reg_ex(qdev, 0x00, 0x1940, miiAddr);
+ /* enable diagnostic mode bit 2 = 1 */
+ ql_mii_write_reg_ex(qdev, 0x12, 0x840e, miiAddr);
+ /* 1000MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x10, 0x8805, miiAddr);
+ /* 1000MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x11, 0xf03e, miiAddr);
+ /* 100MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x10, 0x8806, miiAddr);
+ /* 100MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x11, 0x003e, miiAddr);
+ /* 10MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x10, 0x8807, miiAddr);
+ /* 10MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x11, 0x1f00, miiAddr);
+ /* point to hidden reg 0x2806 */
+ ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr);
+ /* Write new PHYAD w/bit 5 set */
+ ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
+ /*
+ * Disable diagnostic mode bit 2 = 0
+ * Power up device bit 11 = 0
+ * Link up (on) and activity (blink)
+ */
+ ql_mii_write_reg(qdev, 0x12, 0x840a);
+ ql_mii_write_reg(qdev, 0x00, 0x1140);
+ ql_mii_write_reg(qdev, 0x1c, 0xfaf0);
+}
+
+static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
+ u16 phyIdReg0, u16 phyIdReg1)
+{
+ PHY_DEVICE_et result = PHY_TYPE_UNKNOWN;
+ u32 oui;
+ u16 model;
+ int i;
+
+ if (phyIdReg0 == 0xffff) {
+ return result;
+ }
+
+ if (phyIdReg1 == 0xffff) {
+ return result;
+ }
+
+ /* oui is split between two registers */
+ oui = (phyIdReg0 << 6) | ((phyIdReg1 & PHY_OUI_1_MASK) >> 10);
+
+ model = (phyIdReg1 & PHY_MODEL_MASK) >> 4;
+
+ /* Scan table for this PHY */
+ for(i = 0; i < MAX_PHY_DEV_TYPES; i++) {
+ if ((oui == PHY_DEVICES[i].phyIdOUI) && (model == PHY_DEVICES[i].phyIdModel))
+ {
+ result = PHY_DEVICES[i].phyDevice;
+
+ printk(KERN_INFO "%s: Phy: %s\n",
+ qdev->ndev->name, PHY_DEVICES[i].name);
+
+ break;
+ }
+ }
+
+ return result;
+}
+
static int ql_phy_get_speed(struct ql3_adapter *qdev)
{
u16 reg;
+ switch(qdev->phyType) {
+ case PHY_AGERE_ET1011C:
+ {
+ if (ql_mii_read_reg(qdev, 0x1A, &reg) < 0)
+ return 0;
+
+ reg = (reg >> 8) & 3;
+ break;
+ }
+ default:
if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
return 0;
reg = (((reg & 0x18) >> 3) & 3);
+ }
- if (reg == 2)
+ switch(reg) {
+ case 2:
return SPEED_1000;
- else if (reg == 1)
+ case 1:
return SPEED_100;
- else if (reg == 0)
+ case 0:
return SPEED_10;
- else
+ default:
return -1;
+ }
}
static int ql_is_full_dup(struct ql3_adapter *qdev)
{
u16 reg;
- if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
- return 0;
-
- return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+ switch(qdev->phyType) {
+ case PHY_AGERE_ET1011C:
+ {
+ if (ql_mii_read_reg(qdev, 0x1A, &reg))
+ return 0;
+
+ return ((reg & 0x0080) && (reg & 0x1000)) != 0;
+ }
+ case PHY_VITESSE_VSC8211:
+ default:
+ {
+ if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+ return 0;
+ return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+ }
+ }
}
static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
@@ -935,6 +1057,73 @@ static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
return (reg & PHY_NEG_PAUSE) != 0;
}
+static int PHY_Setup(struct ql3_adapter *qdev)
+{
+ u16 reg1;
+ u16 reg2;
+ bool agereAddrChangeNeeded = false;
+ u32 miiAddr = 0;
+ int err;
+
+ /* Determine the PHY we are using by reading the ID's */
+ err = ql_mii_read_reg(qdev, PHY_ID_0_REG, &reg1);
+ if(err != 0) {
+ printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
+ qdev->ndev->name);
+ return err;
+ }
+
+ err = ql_mii_read_reg(qdev, PHY_ID_1_REG, &reg2);
+ if(err != 0) {
+ printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
+ qdev->ndev->name);
+ return err;
+ }
+
+ /* Check if we have a Agere PHY */
+ if ((reg1 == 0xffff) || (reg2 == 0xffff)) {
+
+ /* Determine which MII address we should be using
+ determined by the index of the card */
+ if (qdev->mac_index == 0) {
+ miiAddr = MII_AGERE_ADDR_1;
+ } else {
+ miiAddr = MII_AGERE_ADDR_2;
+ }
+
+ err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
+ if(err != 0) {
+ printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
+ qdev->ndev->name);
+ return err;
+ }
+
+ err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, &reg2, miiAddr);
+ if(err != 0) {
+ printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
+ qdev->ndev->name);
+ return err;
+ }
+
+ /* We need to remember to initialize the Agere PHY */
+ agereAddrChangeNeeded = true;
+ }
+
+ /* Determine the particular PHY we have on board to apply
+ PHY specific initializations */
+ qdev->phyType = getPhyType(qdev, reg1, reg2);
+
+ if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) {
+ /* need this here so address gets changed */
+ phyAgereSpecificInit(qdev, miiAddr);
+ } else if (qdev->phyType == PHY_TYPE_UNKNOWN) {
+ printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name);
+ return -EIO;
+ }
+
+ return 0;
+}
+
/*
* Caller holds hw_lock.
*/
@@ -1205,15 +1394,14 @@ static int ql_link_down_detect_clear(struct ql3_adapter *qdev)
/*
* Caller holds hw_lock.
*/
-static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
- u32 mac_index)
+static int ql_this_adapter_controls_port(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
qdev->mem_map_registers;
u32 bitToCheck = 0;
u32 temp;
- switch (mac_index) {
+ switch (qdev->mac_index) {
case 0:
bitToCheck = PORT_STATUS_F1_ENABLED;
break;
@@ -1238,27 +1426,96 @@ static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
}
}
-static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_reset_ex(struct ql3_adapter *qdev)
{
- ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index);
+ ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET,
+ PHYAddr[qdev->mac_index]);
}
-static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
{
u16 reg;
+ u16 portConfiguration;
+
+ if(qdev->phyType == PHY_AGERE_ET1011C) {
+ /* turn off external loopback */
+ ql_mii_write_reg(qdev, 0x13, 0x0000);
+ }
+
+ if(qdev->mac_index == 0)
+ portConfiguration = qdev->nvram_data.macCfg_port0.portConfiguration;
+ else
+ portConfiguration = qdev->nvram_data.macCfg_port1.portConfiguration;
+
+ /* Some HBA's in the field are set to 0 and they need to
+ be reinterpreted with a default value */
+ if(portConfiguration == 0)
+ portConfiguration = PORT_CONFIG_DEFAULT;
+
+ /* Set the 1000 advertisements */
+ ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, &reg,
+ PHYAddr[qdev->mac_index]);
+ reg &= ~PHY_GIG_ALL_PARAMS;
+
+ if(portConfiguration &
+ PORT_CONFIG_FULL_DUPLEX_ENABLED &
+ PORT_CONFIG_1000MB_SPEED) {
+ reg |= PHY_GIG_ADV_1000F;
+ }
+
+ if(portConfiguration &
+ PORT_CONFIG_HALF_DUPLEX_ENABLED &
+ PORT_CONFIG_1000MB_SPEED) {
+ reg |= PHY_GIG_ADV_1000H;
+ }
- ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER,
- PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index);
+ ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg,
+ PHYAddr[qdev->mac_index]);
- ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, mac_index);
- ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG,
- mac_index);
+ /* Set the 10/100 & pause negotiation advertisements */
+ ql_mii_read_reg_ex(qdev, PHY_NEG_ADVER, &reg,
+ PHYAddr[qdev->mac_index]);
+ reg &= ~PHY_NEG_ALL_PARAMS;
+
+ if(portConfiguration & PORT_CONFIG_SYM_PAUSE_ENABLED)
+ reg |= PHY_NEG_ASY_PAUSE | PHY_NEG_SYM_PAUSE;
+
+ if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
+ if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+ reg |= PHY_NEG_ADV_100F;
+
+ if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+ reg |= PHY_NEG_ADV_10F;
+ }
+
+ if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
+ if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+ reg |= PHY_NEG_ADV_100H;
+
+ if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+ reg |= PHY_NEG_ADV_10H;
+ }
+
+ if(portConfiguration &
+ PORT_CONFIG_1000MB_SPEED) {
+ reg |= 1;
+ }
+
+ ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg,
+ PHYAddr[qdev->mac_index]);
+
+ ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, PHYAddr[qdev->mac_index]);
+
+ ql_mii_write_reg_ex(qdev, CONTROL_REG,
+ reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG,
+ PHYAddr[qdev->mac_index]);
}
-static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_init_ex(struct ql3_adapter *qdev)
{
- ql_phy_reset_ex(qdev, mac_index);
- ql_phy_start_neg_ex(qdev, mac_index);
+ ql_phy_reset_ex(qdev);
+ PHY_Setup(qdev);
+ ql_phy_start_neg_ex(qdev);
}
/*
@@ -1295,14 +1552,17 @@ static int ql_port_start(struct ql3_adapter *qdev)
{
if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
- 2) << 7))
+ 2) << 7)) {
+ printk(KERN_ERR "%s: Could not get hw lock for GIO\n",
+ qdev->ndev->name);
return -1;
+ }
if (ql_is_fiber(qdev)) {
ql_petbi_init(qdev);
} else {
/* Copper port */
- ql_phy_init_ex(qdev, qdev->mac_index);
+ ql_phy_init_ex(qdev);
}
ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
@@ -1453,7 +1713,7 @@ static void ql_link_state_machine(struct ql3_adapter *qdev)
*/
static void ql_get_phy_owner(struct ql3_adapter *qdev)
{
- if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+ if (ql_this_adapter_controls_port(qdev))
set_bit(QL_LINK_MASTER,&qdev->flags);
else
clear_bit(QL_LINK_MASTER,&qdev->flags);
@@ -1467,11 +1727,11 @@ static void ql_init_scan_mode(struct ql3_adapter *qdev)
ql_mii_enable_scan_mode(qdev);
if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
- if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
- ql_petbi_init_ex(qdev, qdev->mac_index);
+ if (ql_this_adapter_controls_port(qdev))
+ ql_petbi_init_ex(qdev);
} else {
- if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
- ql_phy_init_ex(qdev, qdev->mac_index);
+ if (ql_this_adapter_controls_port(qdev))
+ ql_phy_init_ex(qdev);
}
}
@@ -1624,6 +1884,23 @@ static void ql_set_msglevel(struct net_device *ndev, u32 value)
qdev->msg_enable = value;
}
+static void ql_get_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+ u32 reg;
+ if(qdev->mac_index == 0)
+ reg = ql_read_page0_reg(qdev, &port_regs->mac0ConfigReg);
+ else
+ reg = ql_read_page0_reg(qdev, &port_regs->mac1ConfigReg);
+
+ pause->autoneg = ql_get_auto_cfg_status(qdev);
+ pause->rx_pause = (reg & MAC_CONFIG_REG_RF) >> 2;
+ pause->tx_pause = (reg & MAC_CONFIG_REG_TF) >> 1;
+}
+
static const struct ethtool_ops ql3xxx_ethtool_ops = {
.get_settings = ql_get_settings,
.get_drvinfo = ql_get_drvinfo,
@@ -1631,6 +1908,7 @@ static const struct ethtool_ops ql3xxx_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_msglevel = ql_get_msglevel,
.set_msglevel = ql_set_msglevel,
+ .get_pauseparam = ql_get_pauseparam,
};
static int ql_populate_free_queue(struct ql3_adapter *qdev)
@@ -1815,14 +2093,14 @@ invalid_seg_count:
atomic_inc(&qdev->tx_count);
}
-void ql_get_sbuf(struct ql3_adapter *qdev)
+static void ql_get_sbuf(struct ql3_adapter *qdev)
{
if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
qdev->small_buf_index = 0;
qdev->small_buf_release_cnt++;
}
-struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
+static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
{
struct ql_rcv_buf_cb *lrg_buf_cb = NULL;
lrg_buf_cb = &qdev->lrg_buf[qdev->lrg_buf_index];
@@ -3074,6 +3352,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
goto out;
}
+ PHY_Setup(qdev);
ql_init_scan_mode(qdev);
ql_get_phy_owner(qdev);
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
index 0203f88f0544..4a832c46c274 100755
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -293,6 +293,16 @@ struct net_rsp_iocb {
#define MII_SCAN_REGISTER 0x00000001
+#define PHY_ID_0_REG 2
+#define PHY_ID_1_REG 3
+
+#define PHY_OUI_1_MASK 0xfc00
+#define PHY_MODEL_MASK 0x03f0
+
+/* Address for the Agere Phy */
+#define MII_AGERE_ADDR_1 0x00001000
+#define MII_AGERE_ADDR_2 0x00001100
+
/* 32-bit ispControlStatus */
enum {
ISP_CONTROL_NP_MASK = 0x0003,
@@ -789,6 +799,7 @@ enum {
PHY_CTRL_LOOPBACK = 0x4000,
PETBI_CONTROL_REG = 0x00,
+ PETBI_CTRL_ALL_PARAMS = 0x7140,
PETBI_CTRL_SOFT_RESET = 0x8000,
PETBI_CTRL_AUTO_NEG = 0x1000,
PETBI_CTRL_RESTART_NEG = 0x0200,
@@ -811,6 +822,23 @@ enum {
PETBI_EXPANSION_REG = 0x06,
PETBI_EXP_PAGE_RX = 0x0002,
+ PHY_GIG_CONTROL = 9,
+ PHY_GIG_ENABLE_MAN = 0x1000, /* Enable Master/Slave Manual Config*/
+ PHY_GIG_SET_MASTER = 0x0800, /* Set Master (slave if clear)*/
+ PHY_GIG_ALL_PARAMS = 0x0300,
+ PHY_GIG_ADV_1000F = 0x0200,
+ PHY_GIG_ADV_1000H = 0x0100,
+
+ PHY_NEG_ADVER = 4,
+ PHY_NEG_ALL_PARAMS = 0x0fe0,
+ PHY_NEG_ASY_PAUSE = 0x0800,
+ PHY_NEG_SYM_PAUSE = 0x0400,
+ PHY_NEG_ADV_SPEED = 0x01e0,
+ PHY_NEG_ADV_100F = 0x0100,
+ PHY_NEG_ADV_100H = 0x0080,
+ PHY_NEG_ADV_10F = 0x0040,
+ PHY_NEG_ADV_10H = 0x0020,
+
PETBI_TBI_CTRL = 0x11,
PETBI_TBI_RESET = 0x8000,
PETBI_TBI_AUTO_SENSE = 0x0100,
@@ -826,8 +854,7 @@ enum {
PHY_AUX_RESET_STICK = 0x0002,
PHY_NEG_PAUSE = 0x0400,
PHY_CTRL_SOFT_RESET = 0x8000,
- PHY_NEG_ADVER = 4,
- PHY_NEG_ADV_SPEED = 0x01e0,
+ PHY_CTRL_AUTO_NEG = 0x1000,
PHY_CTRL_RESTART_NEG = 0x0200,
};
enum {
@@ -892,6 +919,7 @@ enum {EEPROM_SIZE = FM93C86A_SIZE_16,
u16 pauseThreshold_mac;
u16 resumeThreshold_mac;
u16 portConfiguration;
+#define PORT_CONFIG_DEFAULT 0xf700
#define PORT_CONFIG_AUTO_NEG_ENABLED 0x8000
#define PORT_CONFIG_SYM_PAUSE_ENABLED 0x4000
#define PORT_CONFIG_FULL_DUPLEX_ENABLED 0x2000
@@ -1259,6 +1287,7 @@ struct ql3_adapter {
struct delayed_work tx_timeout_work;
u32 max_frame_size;
u32 device_id;
+ u16 phyType;
};
#endif /* _QLA3XXX_H_ */
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 33fb7f3b7041..4cb710bbe729 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -1,6 +1,6 @@
/************************************************************************
* regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 600d3ff347fc..290e1c1f30c6 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -1,6 +1,6 @@
/************************************************************************
* s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
@@ -84,7 +84,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.17.1"
+#define DRV_VERSION "2.0.22.1"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -316,7 +316,7 @@ static void s2io_vlan_rx_register(struct net_device *dev,
}
/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
-int vlan_strip_flag;
+static int vlan_strip_flag;
/* Unregister the vlan */
static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
@@ -394,7 +394,6 @@ static const u64 fix_mac[] = {
END_SIGN
};
-MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
@@ -516,7 +515,7 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->fifos[i].list_info = kmalloc(list_holder_size,
GFP_KERNEL);
if (!mac_control->fifos[i].list_info) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"Malloc failed for list_info\n");
return -ENOMEM;
}
@@ -542,9 +541,9 @@ static int init_shared_mem(struct s2io_nic *nic)
tmp_v = pci_alloc_consistent(nic->pdev,
PAGE_SIZE, &tmp_p);
if (!tmp_v) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"pci_alloc_consistent ");
- DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+ DBG_PRINT(INFO_DBG, "failed for TxDL\n");
return -ENOMEM;
}
/* If we got a zero DMA address(can happen on
@@ -561,9 +560,9 @@ static int init_shared_mem(struct s2io_nic *nic)
tmp_v = pci_alloc_consistent(nic->pdev,
PAGE_SIZE, &tmp_p);
if (!tmp_v) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"pci_alloc_consistent ");
- DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+ DBG_PRINT(INFO_DBG, "failed for TxDL\n");
return -ENOMEM;
}
}
@@ -2187,7 +2186,7 @@ static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
/* skb_shinfo(skb)->frag_list will have L4 data payload */
skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
if (skb_shinfo(skb)->frag_list == NULL) {
- DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
+ DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
return -ENOMEM ;
}
frag_list = skb_shinfo(skb)->frag_list;
@@ -2242,6 +2241,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
struct buffAdd *ba;
unsigned long flags;
struct RxD_t *first_rxdp = NULL;
+ u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
mac_control = &nic->mac_control;
config = &nic->config;
@@ -2313,8 +2313,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
/* allocate skb */
skb = dev_alloc_skb(size);
if(!skb) {
- DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
- DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+ DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
if (first_rxdp) {
wmb();
first_rxdp->Control_1 |= RXD_OWN_XENA;
@@ -2342,7 +2342,14 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* payload
*/
+ /* save the buffer pointers to avoid frequent dma mapping */
+ Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr;
+ Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr;
memset(rxdp, 0, sizeof(struct RxD3));
+ /* restore the buffer pointers for dma sync*/
+ ((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr;
+ ((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr;
+
ba = &mac_control->rings[ring_no].ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
tmp = (u64)(unsigned long) skb->data;
@@ -2573,8 +2580,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
}
}
@@ -2590,8 +2597,8 @@ no_rx:
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
}
}
@@ -2640,8 +2647,8 @@ static void s2io_netpoll(struct net_device *dev)
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
break;
}
}
@@ -3307,6 +3314,7 @@ static void s2io_reset(struct s2io_nic * sp)
u16 subid, pci_cmd;
int i;
u16 val16;
+ unsigned long long reset_cnt = 0;
DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
__FUNCTION__, sp->dev->name);
@@ -3372,6 +3380,11 @@ new_way:
/* Reset device statistics maintained by OS */
memset(&sp->stats, 0, sizeof (struct net_device_stats));
+ /* save reset count */
+ reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt;
+ memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
+ /* restore reset count */
+ sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt;
/* SXE-002: Configure link and activity LED to turn it off */
subid = sp->pdev->subsystem_device;
@@ -3659,7 +3672,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
GFP_KERNEL);
if (nic->entries == NULL) {
- DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+ DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
return -ENOMEM;
}
memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
@@ -3668,7 +3681,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
GFP_KERNEL);
if (nic->s2io_entries == NULL) {
- DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+ DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
kfree(nic->entries);
return -ENOMEM;
}
@@ -4019,7 +4032,7 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
DBG_PRINT(INTR_DBG, "PANIC levels\n");
if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "Out of memory in %s",
+ DBG_PRINT(INFO_DBG, "Out of memory in %s",
__FUNCTION__);
clear_bit(0, (&sp->tasklet_status));
return -1;
@@ -4029,8 +4042,8 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
tasklet_schedule(&sp->task);
} else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
}
@@ -4279,9 +4292,7 @@ static void s2io_updt_stats(struct s2io_nic *sp)
if (cnt == 5)
break; /* Updt failed */
} while(1);
- } else {
- memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
- }
+ }
}
/**
@@ -5949,12 +5960,12 @@ static void s2io_tasklet(unsigned long dev_addr)
for (i = 0; i < config->rx_ring_num; i++) {
ret = fill_rx_buffers(sp, i);
if (ret == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s: Out of ",
+ DBG_PRINT(INFO_DBG, "%s: Out of ",
dev->name);
DBG_PRINT(ERR_DBG, "memory in tasklet\n");
break;
} else if (ret == -EFILL) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"%s: Rx Ring %d is full\n",
dev->name, i);
break;
@@ -6065,8 +6076,8 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
- DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
- DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+ DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
return -ENOMEM ;
}
/* storing the mapped addr in a temp variable
@@ -6088,7 +6099,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
- DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
+ DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n",
dev->name);
return -ENOMEM;
}
@@ -6115,7 +6126,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
- DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
+ DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n",
dev->name);
return -ENOMEM;
}
@@ -6616,7 +6627,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
/* Updating statistics */
rxdp->Host_Control = 0;
- sp->rx_pkt_count++;
sp->stats.rx_packets++;
if (sp->rxd_mode == RXD_MODE_1) {
int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
@@ -7252,7 +7262,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
goto register_failed;
}
s2io_vpd_read(sp);
- DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
+ DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n");
DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
sp->product_name, get_xena_rev_id(sp->pdev));
DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 803137ca4b6c..a656d18b33df 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -1,6 +1,6 @@
/************************************************************************
* s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
@@ -760,7 +760,6 @@ struct s2io_nic {
#define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED];
- struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED];
struct net_device_stats stats;
int high_dma_flag;
@@ -794,11 +793,6 @@ struct s2io_nic {
u16 all_multi_pos;
u16 promisc_flg;
- u16 tx_pkt_count;
- u16 rx_pkt_count;
- u16 tx_err_count;
- u16 rx_err_count;
-
/* Id timer, used to blink NIC to physically identify NIC. */
struct timer_list id_timer;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 0a3a379b634c..132e2148b21c 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -95,19 +95,28 @@ MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS));
#endif
#ifdef CONFIG_SBMAC_COALESCE
-static int int_pktcnt = 0;
-module_param(int_pktcnt, int, S_IRUGO);
-MODULE_PARM_DESC(int_pktcnt, "Packet count");
+static int int_pktcnt_tx = 255;
+module_param(int_pktcnt_tx, int, S_IRUGO);
+MODULE_PARM_DESC(int_pktcnt_tx, "TX packet count");
-static int int_timeout = 0;
-module_param(int_timeout, int, S_IRUGO);
-MODULE_PARM_DESC(int_timeout, "Timeout value");
+static int int_timeout_tx = 255;
+module_param(int_timeout_tx, int, S_IRUGO);
+MODULE_PARM_DESC(int_timeout_tx, "TX timeout value");
+
+static int int_pktcnt_rx = 64;
+module_param(int_pktcnt_rx, int, S_IRUGO);
+MODULE_PARM_DESC(int_pktcnt_rx, "RX packet count");
+
+static int int_timeout_rx = 64;
+module_param(int_timeout_rx, int, S_IRUGO);
+MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
#endif
#include <asm/sibyte/sb1250.h>
#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
#include <asm/sibyte/bcm1480_regs.h>
#include <asm/sibyte/bcm1480_int.h>
+#define R_MAC_DMA_OODPKTLOST_RX R_MAC_DMA_OODPKTLOST
#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_int.h>
@@ -155,8 +164,8 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
#define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES)
-#define SBMAC_MAX_TXDESCR 32
-#define SBMAC_MAX_RXDESCR 32
+#define SBMAC_MAX_TXDESCR 256
+#define SBMAC_MAX_RXDESCR 256
#define ETHER_ALIGN 2
#define ETHER_ADDR_LEN 6
@@ -185,10 +194,10 @@ typedef struct sbmacdma_s {
* associated with it.
*/
- struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */
- int sbdma_channel; /* channel number */
+ struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */
+ int sbdma_channel; /* channel number */
int sbdma_txdir; /* direction (1=transmit) */
- int sbdma_maxdescr; /* total # of descriptors in ring */
+ int sbdma_maxdescr; /* total # of descriptors in ring */
#ifdef CONFIG_SBMAC_COALESCE
int sbdma_int_pktcnt; /* # descriptors rx/tx before interrupt*/
int sbdma_int_timeout; /* # usec rx/tx interrupt */
@@ -197,13 +206,16 @@ typedef struct sbmacdma_s {
volatile void __iomem *sbdma_config0; /* DMA config register 0 */
volatile void __iomem *sbdma_config1; /* DMA config register 1 */
volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */
- volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */
+ volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */
volatile void __iomem *sbdma_curdscr; /* current descriptor address */
+ volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */
+
/*
* This stuff is for maintenance of the ring
*/
+ sbdmadscr_t *sbdma_dscrtable_unaligned;
sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */
sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */
@@ -286,8 +298,8 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m);
static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
static void sbdma_emptyring(sbmacdma_t *d);
static void sbdma_fillring(sbmacdma_t *d);
-static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d);
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll);
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll);
static int sbmac_initctx(struct sbmac_softc *s);
static void sbmac_channel_start(struct sbmac_softc *s);
static void sbmac_channel_stop(struct sbmac_softc *s);
@@ -308,6 +320,8 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev);
static void sbmac_set_rx_mode(struct net_device *dev);
static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int sbmac_close(struct net_device *dev);
+static int sbmac_poll(struct net_device *poll_dev, int *budget);
+
static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
static int sbmac_mii_probe(struct net_device *dev);
@@ -679,6 +693,10 @@ static void sbdma_initctx(sbmacdma_t *d,
int txrx,
int maxdescr)
{
+#ifdef CONFIG_SBMAC_COALESCE
+ int int_pktcnt, int_timeout;
+#endif
+
/*
* Save away interesting stuff in the structure
*/
@@ -728,6 +746,11 @@ static void sbdma_initctx(sbmacdma_t *d,
s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT);
d->sbdma_curdscr =
s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR);
+ if (d->sbdma_txdir)
+ d->sbdma_oodpktlost = NULL;
+ else
+ d->sbdma_oodpktlost =
+ s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_OODPKTLOST_RX);
/*
* Allocate memory for the ring
@@ -735,6 +758,7 @@ static void sbdma_initctx(sbmacdma_t *d,
d->sbdma_maxdescr = maxdescr;
+ d->sbdma_dscrtable_unaligned =
d->sbdma_dscrtable = (sbdmadscr_t *)
kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL);
@@ -765,12 +789,14 @@ static void sbdma_initctx(sbmacdma_t *d,
* Setup Rx/Tx DMA coalescing defaults
*/
+ int_pktcnt = (txrx == DMA_TX) ? int_pktcnt_tx : int_pktcnt_rx;
if ( int_pktcnt ) {
d->sbdma_int_pktcnt = int_pktcnt;
} else {
d->sbdma_int_pktcnt = 1;
}
+ int_timeout = (txrx == DMA_TX) ? int_timeout_tx : int_timeout_rx;
if ( int_timeout ) {
d->sbdma_int_timeout = int_timeout;
} else {
@@ -1125,32 +1151,63 @@ static void sbdma_fillring(sbmacdma_t *d)
}
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sbmac_netpoll(struct net_device *netdev)
+{
+ struct sbmac_softc *sc = netdev_priv(netdev);
+ int irq = sc->sbm_dev->irq;
+
+ __raw_writeq(0, sc->sbm_imr);
+
+ sbmac_intr(irq, netdev, NULL);
+
+#ifdef CONFIG_SBMAC_COALESCE
+ __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
+ ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0),
+ sc->sbm_imr);
+#else
+ __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+ (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr);
+#endif
+}
+#endif
/**********************************************************************
- * SBDMA_RX_PROCESS(sc,d)
+ * SBDMA_RX_PROCESS(sc,d,work_to_do,poll)
*
* Process "completed" receive buffers on the specified DMA channel.
- * Note that this isn't really ideal for priority channels, since
- * it processes all of the packets on a given channel before
- * returning.
*
* Input parameters:
- * sc - softc structure
- * d - DMA channel context
+ * sc - softc structure
+ * d - DMA channel context
+ * work_to_do - no. of packets to process before enabling interrupt
+ * again (for NAPI)
+ * poll - 1: using polling (for NAPI)
*
* Return value:
* nothing
********************************************************************* */
-static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d,
+ int work_to_do, int poll)
{
int curidx;
int hwidx;
sbdmadscr_t *dsc;
struct sk_buff *sb;
int len;
+ int work_done = 0;
+ int dropped = 0;
- for (;;) {
+ prefetch(d);
+
+again:
+ /* Check if the HW dropped any frames */
+ sc->sbm_stats.rx_fifo_errors
+ += __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff;
+ __raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost);
+
+ while (work_to_do-- > 0) {
/*
* figure out where we are (as an index) and where
* the hardware is (also as an index)
@@ -1162,7 +1219,12 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
*/
- curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+ dsc = d->sbdma_remptr;
+ curidx = dsc - d->sbdma_dscrtable;
+
+ prefetch(dsc);
+ prefetch(&d->sbdma_ctxtable[curidx]);
+
hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
@@ -1173,13 +1235,12 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
*/
if (curidx == hwidx)
- break;
+ goto done;
/*
* Otherwise, get the packet's sk_buff ptr back
*/
- dsc = &(d->sbdma_dscrtable[curidx]);
sb = d->sbdma_ctxtable[curidx];
d->sbdma_ctxtable[curidx] = NULL;
@@ -1191,7 +1252,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* receive ring.
*/
- if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
+ if (likely (!(dsc->dscr_a & M_DMA_ETHRX_BAD))) {
/*
* Add a new buffer to replace the old one. If we fail
@@ -1199,9 +1260,14 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* packet and put it right back on the receive ring.
*/
- if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
- sc->sbm_stats.rx_dropped++;
+ if (unlikely (sbdma_add_rcvbuffer(d,NULL) ==
+ -ENOBUFS)) {
+ sc->sbm_stats.rx_dropped++;
sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
+ /* No point in continuing at the moment */
+ printk(KERN_ERR "dropped packet (1)\n");
+ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+ goto done;
} else {
/*
* Set length into the packet
@@ -1213,8 +1279,6 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* receive ring. Pass the buffer to
* the kernel
*/
- sc->sbm_stats.rx_bytes += len;
- sc->sbm_stats.rx_packets++;
sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
/* Check hw IPv4/TCP checksum if supported */
if (sc->rx_hw_checksum == ENABLE) {
@@ -1226,8 +1290,22 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
sb->ip_summed = CHECKSUM_NONE;
}
}
-
- netif_rx(sb);
+ prefetch(sb->data);
+ prefetch((const void *)(((char *)sb->data)+32));
+ if (poll)
+ dropped = netif_receive_skb(sb);
+ else
+ dropped = netif_rx(sb);
+
+ if (dropped == NET_RX_DROP) {
+ sc->sbm_stats.rx_dropped++;
+ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+ goto done;
+ }
+ else {
+ sc->sbm_stats.rx_bytes += len;
+ sc->sbm_stats.rx_packets++;
+ }
}
} else {
/*
@@ -1244,12 +1322,16 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
*/
d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
-
+ work_done++;
}
+ if (!poll) {
+ work_to_do = 32;
+ goto again; /* collect fifo drop statistics again */
+ }
+done:
+ return work_done;
}
-
-
/**********************************************************************
* SBDMA_TX_PROCESS(sc,d)
*
@@ -1261,22 +1343,30 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
*
* Input parameters:
* sc - softc structure
- * d - DMA channel context
+ * d - DMA channel context
+ * poll - 1: using polling (for NAPI)
*
* Return value:
* nothing
********************************************************************* */
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
{
int curidx;
int hwidx;
sbdmadscr_t *dsc;
struct sk_buff *sb;
unsigned long flags;
+ int packets_handled = 0;
spin_lock_irqsave(&(sc->sbm_lock), flags);
+ if (d->sbdma_remptr == d->sbdma_addptr)
+ goto end_unlock;
+
+ hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+ d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+
for (;;) {
/*
* figure out where we are (as an index) and where
@@ -1290,8 +1380,6 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
*/
curidx = d->sbdma_remptr - d->sbdma_dscrtable;
- hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
- d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
/*
* If they're the same, that means we've processed all
@@ -1329,6 +1417,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+ packets_handled++;
+
}
/*
@@ -1337,8 +1427,10 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* watermark on the transmit queue.
*/
- netif_wake_queue(d->sbdma_eth->sbm_dev);
+ if (packets_handled)
+ netif_wake_queue(d->sbdma_eth->sbm_dev);
+end_unlock:
spin_unlock_irqrestore(&(sc->sbm_lock), flags);
}
@@ -1412,9 +1504,9 @@ static int sbmac_initctx(struct sbmac_softc *s)
static void sbdma_uninitctx(struct sbmacdma_s *d)
{
- if (d->sbdma_dscrtable) {
- kfree(d->sbdma_dscrtable);
- d->sbdma_dscrtable = NULL;
+ if (d->sbdma_dscrtable_unaligned) {
+ kfree(d->sbdma_dscrtable_unaligned);
+ d->sbdma_dscrtable_unaligned = d->sbdma_dscrtable = NULL;
}
if (d->sbdma_ctxtable) {
@@ -1612,15 +1704,9 @@ static void sbmac_channel_start(struct sbmac_softc *s)
#endif
#ifdef CONFIG_SBMAC_COALESCE
- /*
- * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0
- */
__raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr);
#else
- /*
- * Accept any kind of interrupt on TX and RX DMA channel 0
- */
__raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
(M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr);
#endif
@@ -2053,57 +2139,46 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance)
uint64_t isr;
int handled = 0;
- for (;;) {
-
- /*
- * Read the ISR (this clears the bits in the real
- * register, except for counter addr)
- */
+ /*
+ * Read the ISR (this clears the bits in the real
+ * register, except for counter addr)
+ */
- isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
+ isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
- if (isr == 0)
- break;
+ if (isr == 0)
+ return IRQ_RETVAL(0);
+ handled = 1;
- handled = 1;
-
- /*
- * Transmits on channel 0
- */
+ /*
+ * Transmits on channel 0
+ */
- if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
- sbdma_tx_process(sc,&(sc->sbm_txdma));
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+ sbdma_tx_process(sc,&(sc->sbm_txdma), 0);
+#ifdef CONFIG_NETPOLL_TRAP
+ if (netpoll_trap()) {
+ if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
+ __netif_schedule(dev);
}
+#endif
+ }
- /*
- * Receives on channel 0
- */
-
- /*
- * It's important to test all the bits (or at least the
- * EOP_SEEN bit) when deciding to do the RX process
- * particularly when coalescing, to make sure we
- * take care of the following:
- *
- * If you have some packets waiting (have been received
- * but no interrupt) and get a TX interrupt before
- * the RX timer or counter expires, reading the ISR
- * above will clear the timer and counter, and you
- * won't get another interrupt until a packet shows
- * up to start the timer again. Testing
- * EOP_SEEN here takes care of this case.
- * (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0)
- */
-
-
- if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
- sbdma_rx_process(sc,&(sc->sbm_rxdma));
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
+ if (netif_rx_schedule_prep(dev)) {
+ __raw_writeq(0, sc->sbm_imr);
+ __netif_rx_schedule(dev);
+ /* Depend on the exit from poll to reenable intr */
+ }
+ else {
+ /* may leave some packets behind */
+ sbdma_rx_process(sc,&(sc->sbm_rxdma),
+ SBMAC_MAX_RXDESCR * 2, 0);
}
}
return IRQ_RETVAL(handled);
}
-
/**********************************************************************
* SBMAC_START_TX(skb,dev)
*
@@ -2233,8 +2308,6 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
}
}
-
-
#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
/**********************************************************************
* SBMAC_PARSE_XDIGIT(str)
@@ -2397,8 +2470,13 @@ static int sbmac_init(struct net_device *dev, int idx)
dev->do_ioctl = sbmac_mii_ioctl;
dev->tx_timeout = sbmac_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+ dev->poll = sbmac_poll;
+ dev->weight = 16;
dev->change_mtu = sb1250_change_mtu;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = sbmac_netpoll;
+#endif
/* This is needed for PASS2 for Rx H/W checksum feature */
sbmac_set_iphdr_offset(sc);
@@ -2796,7 +2874,39 @@ static int sbmac_close(struct net_device *dev)
return 0;
}
+static int sbmac_poll(struct net_device *dev, int *budget)
+{
+ int work_to_do;
+ int work_done;
+ struct sbmac_softc *sc = netdev_priv(dev);
+
+ work_to_do = min(*budget, dev->quota);
+ work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), work_to_do, 1);
+ if (work_done > work_to_do)
+ printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n",
+ sc->sbm_dev->name, *budget, dev->quota, work_done);
+
+ sbdma_tx_process(sc, &(sc->sbm_txdma), 1);
+
+ *budget -= work_done;
+ dev->quota -= work_done;
+
+ if (work_done < work_to_do) {
+ netif_rx_complete(dev);
+
+#ifdef CONFIG_SBMAC_COALESCE
+ __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
+ ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0),
+ sc->sbm_imr);
+#else
+ __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+ (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr);
+#endif
+ }
+
+ return (work_done >= work_to_do);
+}
#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
static void
@@ -2883,7 +2993,7 @@ sbmac_init_module(void)
/*
* The R_MAC_ETHERNET_ADDR register will be set to some nonzero
- * value for us by the firmware if we're going to use this MAC.
+ * value for us by the firmware if we are going to use this MAC.
* If we find a zero, skip this MAC.
*/
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index d8c9c5d66d4f..1fc77300b055 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -624,7 +624,7 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs)
#define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf))
-static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
+static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom)
{
struct sgiseeq_init_block *sr;
struct sgiseeq_private *sp;
@@ -650,7 +650,9 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
#define EADDR_NVOFS 250
for (i = 0; i < 3; i++) {
- unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i);
+ unsigned short tmp = has_eeprom ?
+ ip22_eeprom_read(&hpcregs->eeprom, EADDR_NVOFS / 2+i) :
+ ip22_nvram_read(EADDR_NVOFS / 2+i);
dev->dev_addr[2 * i] = tmp >> 8;
dev->dev_addr[2 * i + 1] = tmp & 0xff;
@@ -683,6 +685,11 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
+ /* Setup PIO and DMA transfer timing */
+ sp->hregs->pconfig = 0x161;
+ sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
+ HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
+
/* Reset the chip. */
hpc3_eth_reset(sp->hregs);
@@ -729,8 +736,23 @@ err_out:
static int __init sgiseeq_probe(void)
{
+ unsigned int tmp, ret1, ret2 = 0;
+
/* On board adapter on 1st HPC is always present */
- return sgiseeq_init(hpc3c0, SGI_ENET_IRQ);
+ ret1 = sgiseeq_init(hpc3c0, SGI_ENET_IRQ, 0);
+ /* Let's see if second HPC is there */
+ if (!(ip22_is_fullhouse()) &&
+ get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]) == 0) {
+ sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 |
+ SGIMC_GIOPAR_EXP164 |
+ SGIMC_GIOPAR_HPC264;
+ hpc3c1->pbus_piocfg[0][0] = 0x3ffff;
+ /* interrupt/config register on Challenge S Mezz board */
+ hpc3c1->pbus_extregs[0][0] = 0x30;
+ ret2 = sgiseeq_init(hpc3c1, SGI_GIO_0_IRQ, 1);
+ }
+
+ return (ret1 & ret2) ? ret1 : 0;
}
static void __exit sgiseeq_exit(void)
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index e0a93005e6dc..bf218621db16 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -5123,7 +5123,12 @@ static int skge_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ printk(KERN_WARNING "sk98lin: unable to enable device %s "
+ "in resume\n", dev->name);
+ goto err_out;
+ }
pci_set_master(pdev);
if (pAC->GIni.GIMacsFound == 2)
ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
@@ -5131,10 +5136,8 @@ static int skge_resume(struct pci_dev *pdev)
ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev);
if (ret) {
printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq);
- pAC->AllocFlag &= ~SK_ALLOC_IRQ;
- dev->irq = 0;
- pci_disable_device(pdev);
- return -EBUSY;
+ ret = -EBUSY;
+ goto err_out_disable_pdev;
}
netif_device_attach(dev);
@@ -5151,6 +5154,13 @@ static int skge_resume(struct pci_dev *pdev)
}
return 0;
+
+err_out_disable_pdev:
+ pci_disable_device(pdev);
+err_out:
+ pAC->AllocFlag &= ~SK_ALLOC_IRQ;
+ dev->irq = 0;
+ return ret;
}
#else
#define skge_suspend NULL
diff --git a/drivers/net/skfp/h/lnkstat.h b/drivers/net/skfp/h/lnkstat.h
deleted file mode 100644
index c73dcd96a40f..000000000000
--- a/drivers/net/skfp/h/lnkstat.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/******************************************************************************
- *
- * (C)Copyright 1998,1999 SysKonnect,
- * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-/*
- * Definition of the Error Log Structure
- * This structure will be copied into the Error Log buffer
- * during the NDIS General Request ReadErrorLog by the MAC Driver
- */
-
-struct s_error_log {
-
- /*
- * place holder for token ring adapter error log (zeros)
- */
- u_char reserved_0 ; /* byte 0 inside Error Log */
- u_char reserved_1 ; /* byte 1 */
- u_char reserved_2 ; /* byte 2 */
- u_char reserved_3 ; /* byte 3 */
- u_char reserved_4 ; /* byte 4 */
- u_char reserved_5 ; /* byte 5 */
- u_char reserved_6 ; /* byte 6 */
- u_char reserved_7 ; /* byte 7 */
- u_char reserved_8 ; /* byte 8 */
- u_char reserved_9 ; /* byte 9 */
- u_char reserved_10 ; /* byte 10 */
- u_char reserved_11 ; /* byte 11 */
- u_char reserved_12 ; /* byte 12 */
- u_char reserved_13 ; /* byte 13 */
-
- /*
- * FDDI link statistics
- */
-/*
- * smt error low
- */
-#define SMT_ERL_AEB (1<<15) /* A elast. buffer */
-#define SMT_ERL_BLC (1<<14) /* B link error condition */
-#define SMT_ERL_ALC (1<<13) /* A link error condition */
-#define SMT_ERL_NCC (1<<12) /* not copied condition */
-#define SMT_ERL_FEC (1<<11) /* frame error condition */
-
-/*
- * smt event low
- */
-#define SMT_EVL_NCE (1<<5)
-
- u_short smt_error_low ; /* byte 14/15 */
- u_short smt_error_high ; /* byte 16/17 */
- u_short smt_event_low ; /* byte 18/19 */
- u_short smt_event_high ; /* byte 20/21 */
- u_short connection_policy_violation ; /* byte 22/23 */
- u_short port_event ; /* byte 24/25 */
- u_short set_count_low ; /* byte 26/27 */
- u_short set_count_high ; /* byte 28/29 */
- u_short aci_id_code ; /* byte 30/31 */
- u_short purge_frame_counter ; /* byte 32/33 */
-
- /*
- * CMT and RMT state machines
- */
- u_short ecm_state ; /* byte 34/35 */
- u_short pcm_a_state ; /* byte 36/37 */
- u_short pcm_b_state ; /* byte 38/39 */
- u_short cfm_state ; /* byte 40/41 */
- u_short rmt_state ; /* byte 42/43 */
-
- u_short not_used[30] ; /* byte 44-103 */
-
- u_short ucode_version_level ; /* byte 104/105 */
-
- u_short not_used_1 ; /* byte 106/107 */
- u_short not_used_2 ; /* byte 108/109 */
-} ;
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index f1a0e6c0fbdd..21afe108d3cb 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -42,7 +42,7 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.10"
+#define DRV_VERSION "1.11"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -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)
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 86467ae74d45..edd71468220c 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -232,7 +232,6 @@ enum {
IS_R2_PAR_ERR = 1<<0, /* Queue R2 Parity Error */
IS_ERR_MSK = IS_IRQ_MST_ERR | IS_IRQ_STAT
- | IS_NO_STAT_M1 | IS_NO_STAT_M2
| IS_RAM_RD_PAR | IS_RAM_WR_PAR
| IS_M1_PAR_ERR | IS_M2_PAR_ERR
| IS_R1_PAR_ERR | IS_R2_PAR_ERR,
@@ -2447,15 +2446,15 @@ enum pause_status {
struct skge_port {
- u32 msg_enable;
struct skge_hw *hw;
struct net_device *netdev;
int port;
+ u32 msg_enable;
struct skge_ring tx_ring;
- struct skge_ring rx_ring;
- struct net_device_stats net_stats;
+ struct skge_ring rx_ring ____cacheline_aligned_in_smp;
+ unsigned int rx_buf_size;
struct timer_list link_timer;
enum pause_control flow_control;
@@ -2471,7 +2470,8 @@ struct skge_port {
void *mem; /* PCI memory for rings */
dma_addr_t dma;
unsigned long mem_size;
- unsigned int rx_buf_size;
+
+ struct net_device_stats net_stats;
};
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 8a2109a913b6..81f24847c963 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -499,7 +499,7 @@ static inline void smc911x_rcv(struct net_device *dev)
SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_));
SMC_PULL_DATA(data, pkt_len+2+3);
- DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name,);
+ DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name);
PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64);
dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, dev);
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index d7741e23f8de..f1e2dfc795a2 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1,35 +1,34 @@
-/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ahennessy@mvista.com
+/*
+ * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
*
* Based on skelton.c by Donald Becker.
- * Copyright (C) 2000-2001 Toshiba Corporation
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * This driver is a replacement of older and less maintained version.
+ * This is a header of the older version:
+ * -----<snip>-----
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ahennessy@mvista.com
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ * static const char *version =
+ * "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+ * -----<snip>-----
*
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2005
+ * All Rights Reserved.
*/
-static const char *version =
- "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+#ifdef TC35815_NAPI
+#define DRV_VERSION "1.35-NAPI"
+#else
+#define DRV_VERSION "1.35"
+#endif
+static const char *version = "tc35815.c:v" DRV_VERSION "\n";
+#define MODNAME "tc35815"
#include <linux/module.h>
#include <linux/kernel.h>
@@ -40,6 +39,7 @@ static const char *version =
#include <linux/in.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/netdevice.h>
@@ -47,36 +47,47 @@ static const char *version =
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
#include <asm/io.h>
-#include <asm/dma.h>
#include <asm/byteorder.h>
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-static const char* cardname = "TC35815CF";
-#define TC35815_PROC_ENTRY "net/tc35815"
-
-#define TC35815_MODULE_NAME "TC35815CF"
-#define TX_TIMEOUT (4*HZ)
-
/* First, a few definitions that the brave might change. */
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef TC35815_DEBUG
-#define TC35815_DEBUG 1
-#endif
-static unsigned int tc35815_debug = TC35815_DEBUG;
-
#define GATHER_TXINT /* On-Demand Tx Interrupt */
+#define WORKAROUND_LOSTCAR
+#define WORKAROUND_100HALF_PROMISC
+/* #define TC35815_USE_PACKEDBUFFER */
+
+typedef enum {
+ TC35815CF = 0,
+ TC35815_NWU,
+ TC35815_TX4939,
+} board_t;
+
+/* indexed by board_t, above */
+static const struct {
+ const char *name;
+} board_info[] __devinitdata = {
+ { "TOSHIBA TC35815CF 10/100BaseTX" },
+ { "TOSHIBA TC35815 with Wake on LAN" },
+ { "TOSHIBA TC35815/TX4939" },
+};
+
+static const struct pci_device_id tc35815_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
+ {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
+ {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
+ {0,}
+};
+MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
-#define vtonocache(p) KSEG1ADDR(virt_to_phys(p))
+/* see MODULE_PARM_DESC */
+static struct tc35815_options {
+ int speed;
+ int duplex;
+ int doforce;
+} options;
/*
* Registers
@@ -119,6 +130,11 @@ struct tc35815_regs {
* Bit assignments
*/
/* DMA_Ctl bit asign ------------------------------------------------------- */
+#define DMA_RxAlign 0x00c00000 /* 1:Reception Alignment */
+#define DMA_RxAlign_1 0x00400000
+#define DMA_RxAlign_2 0x00800000
+#define DMA_RxAlign_3 0x00c00000
+#define DMA_M66EnStat 0x00080000 /* 1:66MHz Enable State */
#define DMA_IntMask 0x00040000 /* 1:Interupt mask */
#define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */
#define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */
@@ -269,42 +285,6 @@ struct tc35815_regs {
#define MD_CA_Wr 0x00000400 /* 1:Write 0:Read */
-/* MII register offsets */
-#define MII_CONTROL 0x0000
-#define MII_STATUS 0x0001
-#define MII_PHY_ID0 0x0002
-#define MII_PHY_ID1 0x0003
-#define MII_ANAR 0x0004
-#define MII_ANLPAR 0x0005
-#define MII_ANER 0x0006
-/* MII Control register bit definitions. */
-#define MIICNTL_FDX 0x0100
-#define MIICNTL_RST_AUTO 0x0200
-#define MIICNTL_ISOLATE 0x0400
-#define MIICNTL_PWRDWN 0x0800
-#define MIICNTL_AUTO 0x1000
-#define MIICNTL_SPEED 0x2000
-#define MIICNTL_LPBK 0x4000
-#define MIICNTL_RESET 0x8000
-/* MII Status register bit significance. */
-#define MIISTAT_EXT 0x0001
-#define MIISTAT_JAB 0x0002
-#define MIISTAT_LINK 0x0004
-#define MIISTAT_CAN_AUTO 0x0008
-#define MIISTAT_FAULT 0x0010
-#define MIISTAT_AUTO_DONE 0x0020
-#define MIISTAT_CAN_T 0x0800
-#define MIISTAT_CAN_T_FDX 0x1000
-#define MIISTAT_CAN_TX 0x2000
-#define MIISTAT_CAN_TX_FDX 0x4000
-#define MIISTAT_CAN_T4 0x8000
-/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */
-#define MII_AN_TX_FDX 0x0100
-#define MII_AN_TX_HDX 0x0080
-#define MII_AN_10_FDX 0x0040
-#define MII_AN_10_HDX 0x0020
-
-
/*
* Descriptors
*/
@@ -352,32 +332,51 @@ struct BDesc {
#ifdef NO_CHECK_CARRIER
#define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
- Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
- Tx_En) /* maybe 0x7d01 */
+ Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
+ Tx_En) /* maybe 0x7b01 */
#else
#define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
- Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
- Tx_En) /* maybe 0x7f01 */
+ Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
+ Tx_En) /* maybe 0x7b01 */
#endif
#define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
| Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */
-
#define INT_EN_CMD (Int_NRAbtEn | \
- Int_DParDEn | Int_DParErrEn | \
+ Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \
Int_STargAbtEn | \
Int_BLExEn | Int_FDAExEn) /* maybe 0xb7f*/
+#define DMA_CTL_CMD DMA_BURST_SIZE
+#define HAVE_DMA_RXALIGN(lp) likely((lp)->boardtype != TC35815CF)
/* Tuning parameters */
#define DMA_BURST_SIZE 32
#define TX_THRESHOLD 1024
+#define TX_THRESHOLD_MAX 1536 /* used threshold with packet max byte for low pci transfer ability.*/
+#define TX_THRESHOLD_KEEP_LIMIT 10 /* setting threshold max value when overrun error occured this count. */
+/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */
+#ifdef TC35815_USE_PACKEDBUFFER
#define FD_PAGE_NUM 2
-#define FD_PAGE_ORDER 1
-/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */
-#define RX_BUF_PAGES 8 /* >= 2 */
+#define RX_BUF_NUM 8 /* >= 2 */
#define RX_FD_NUM 250 /* >= 32 */
#define TX_FD_NUM 128
+#define RX_BUF_SIZE PAGE_SIZE
+#else /* TC35815_USE_PACKEDBUFFER */
+#define FD_PAGE_NUM 4
+#define RX_BUF_NUM 128 /* < 256 */
+#define RX_FD_NUM 256 /* >= 32 */
+#define TX_FD_NUM 128
+#if RX_CTL_CMD & Rx_LongEn
+#define RX_BUF_SIZE PAGE_SIZE
+#elif RX_CTL_CMD & Rx_StripCRC
+#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */
+#else
+#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */
+#endif
+#endif /* TC35815_USE_PACKEDBUFFER */
+#define RX_FD_RESERVE (2 / 2) /* max 2 BD per RxFD */
+#define NAPI_WEIGHT 16
struct TxFD {
struct FDesc fd;
@@ -392,18 +391,27 @@ struct RxFD {
struct FrFD {
struct FDesc fd;
- struct BDesc bd[RX_BUF_PAGES];
+ struct BDesc bd[RX_BUF_NUM];
};
-extern unsigned long tc_readl(volatile __u32 *addr);
-extern void tc_writel(unsigned long data, volatile __u32 *addr);
+#define tc_readl(addr) readl(addr)
+#define tc_writel(d, addr) writel(d, addr)
+
+#define TC35815_TX_TIMEOUT msecs_to_jiffies(400)
-dma_addr_t priv_dma_handle;
+/* Timer state engine. */
+enum tc35815_timer_state {
+ arbwait = 0, /* Waiting for auto negotiation to complete. */
+ lupwait = 1, /* Auto-neg complete, awaiting link-up status. */
+ ltrywait = 2, /* Forcing try of all modes, from fastest to slowest. */
+ asleep = 3, /* Time inactive. */
+ lcheck = 4, /* Check link status. */
+};
/* Information that need to be kept for each board. */
struct tc35815_local {
- struct net_device *next_module;
+ struct pci_dev *pci_dev;
/* statistics */
struct net_device_stats stats;
@@ -411,216 +419,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;
+}
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq);
+#define TC35815_DMA_SYNC_ONDEMAND
+static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+ void *buf;
+ /* pci_map + pci_dma_sync will be more effective than
+ * pci_alloc_consistent on some archs. */
+ if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL)
+ return NULL;
+ *dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(*dma_handle)) {
+ free_page((unsigned long)buf);
+ return NULL;
+ }
+ return buf;
+#else
+ return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle);
+#endif
+}
+
+static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+ pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ free_page((unsigned long)buf);
+#else
+ pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle);
+#endif
+}
+#else /* TC35815_USE_PACKEDBUFFER */
+static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
+ struct pci_dev *hwdev,
+ dma_addr_t *dma_handle)
+{
+ struct sk_buff *skb;
+ skb = dev_alloc_skb(RX_BUF_SIZE);
+ if (!skb)
+ return NULL;
+ 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 */
+
+/* Index to functions, as function prototypes. */
static int tc35815_open(struct net_device *dev);
static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void tc35815_tx_timeout(struct net_device *dev);
-static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
+static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
+#ifdef TC35815_NAPI
+static int tc35815_rx(struct net_device *dev, int limit);
+static int tc35815_poll(struct net_device *dev, int *budget);
+#else
static void tc35815_rx(struct net_device *dev);
+#endif
static void tc35815_txdone(struct net_device *dev);
static int tc35815_close(struct net_device *dev);
static struct net_device_stats *tc35815_get_stats(struct net_device *dev);
static void tc35815_set_multicast_list(struct net_device *dev);
+static void tc35815_tx_timeout(struct net_device *dev);
+static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tc35815_poll_controller(struct net_device *dev);
+#endif
+static const struct ethtool_ops tc35815_ethtool_ops;
+/* Example routines you must write ;->. */
static void tc35815_chip_reset(struct net_device *dev);
static void tc35815_chip_init(struct net_device *dev);
+static void tc35815_find_phy(struct net_device *dev);
static void tc35815_phy_chip_init(struct net_device *dev);
-/* A list of all installed tc35815 devices. */
-static struct net_device *root_tc35815_dev = NULL;
+#ifdef DEBUG
+static void panic_queues(struct net_device *dev);
+#endif
-/*
- * PCI device identifiers for "new style" Linux PCI Device Drivers
- */
-static struct pci_device_id tc35815_pci_tbl[] = {
- { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { 0, }
-};
+static void tc35815_timer(unsigned long data);
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+ struct ethtool_cmd *ep);
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location);
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+ int val);
-MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
+static void __devinit tc35815_init_dev_addr (struct net_device *dev)
+{
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ int i;
-int
-tc35815_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ /* dev_addr will be overwritten on NETDEV_REGISTER event */
+ while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+ ;
+ for (i = 0; i < 6; i += 2) {
+ unsigned short data;
+ tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
+ while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+ ;
+ data = tc_readl(&tr->PROM_Data);
+ dev->dev_addr[i] = data & 0xff;
+ dev->dev_addr[i+1] = data >> 8;
+ }
+}
+
+static int __devinit tc35815_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- int err = 0;
- int ret;
- unsigned long pci_memaddr;
- unsigned int pci_irq_line;
+ void __iomem *ioaddr = NULL;
+ struct net_device *dev;
+ struct tc35815_local *lp;
+ int rc;
+ unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+
+ static int printed_version;
+ if (!printed_version++) {
+ printk(version);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "speed:%d duplex:%d doforce:%d\n",
+ options.speed, options.duplex, options.doforce);
+ }
- printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device);
+ if (!pdev->irq) {
+ dev_warn(&pdev->dev, "no IRQ assigned.\n");
+ return -ENODEV;
+ }
- err = pci_enable_device(pdev);
- if (err)
- return err;
+ /* dev zeroed in alloc_etherdev */
+ dev = alloc_etherdev (sizeof (*lp));
+ if (dev == NULL) {
+ dev_err(&pdev->dev, "unable to alloc new ethernet\n");
+ return -ENOMEM;
+ }
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ lp = dev->priv;
+
+ /* enable device (incl. PCI PM wakeup), and bus-mastering */
+ rc = pci_enable_device (pdev);
+ if (rc)
+ goto err_out;
- pci_memaddr = pci_resource_start (pdev, 1);
+ mmio_start = pci_resource_start (pdev, 1);
+ mmio_end = pci_resource_end (pdev, 1);
+ mmio_flags = pci_resource_flags (pdev, 1);
+ mmio_len = pci_resource_len (pdev, 1);
- printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0));
+ /* set this immediately, we need to know before
+ * we talk to the chip directly */
- if (!pci_memaddr) {
- printk(KERN_WARNING "no PCI MEM resources, aborting\n");
- ret = -ENODEV;
+ /* make sure PCI base addr 1 is MMIO */
+ if (!(mmio_flags & IORESOURCE_MEM)) {
+ dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
+ rc = -ENODEV;
goto err_out;
}
- pci_irq_line = pdev->irq;
- /* irq disabled. */
- if (pci_irq_line == 0) {
- printk(KERN_WARNING "no PCI irq, aborting\n");
- ret = -ENODEV;
+
+ /* check for weird/broken PCI region reporting */
+ if ((mmio_len < sizeof(struct tc35815_regs))) {
+ dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
+ rc = -ENODEV;
goto err_out;
}
- ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line);
- if (ret)
+ rc = pci_request_regions (pdev, MODNAME);
+ if (rc)
goto err_out;
- pci_set_master(pdev);
-
- return 0;
+ pci_set_master (pdev);
-err_out:
- pci_disable_device(pdev);
- return ret;
-}
+ /* ioremap MMIO region */
+ ioaddr = ioremap (mmio_start, mmio_len);
+ if (ioaddr == NULL) {
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
+ rc = -EIO;
+ goto err_out_free_res;
+ }
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq)
-{
- static unsigned version_printed = 0;
- int i, ret;
- struct tc35815_local *lp;
- struct tc35815_regs *tr;
- struct net_device *dev;
+ /* Initialize the device structure. */
+ dev->open = tc35815_open;
+ dev->hard_start_xmit = tc35815_send_packet;
+ dev->stop = tc35815_close;
+ dev->get_stats = tc35815_get_stats;
+ dev->set_multicast_list = tc35815_set_multicast_list;
+ dev->do_ioctl = tc35815_ioctl;
+ dev->ethtool_ops = &tc35815_ethtool_ops;
+ dev->tx_timeout = tc35815_tx_timeout;
+ dev->watchdog_timeo = TC35815_TX_TIMEOUT;
+#ifdef TC35815_NAPI
+ dev->poll = tc35815_poll;
+ dev->weight = NAPI_WEIGHT;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = tc35815_poll_controller;
+#endif
- /* Allocate a new 'dev' if needed. */
- dev = alloc_etherdev(sizeof(struct tc35815_local));
- if (dev == NULL)
- return -ENOMEM;
+ dev->irq = pdev->irq;
+ dev->base_addr = (unsigned long) ioaddr;
- /*
- * alloc_etherdev allocs and zeros dev->priv
- */
+ /* dev->priv/lp zeroed and aligned in alloc_etherdev */
lp = dev->priv;
+ spin_lock_init(&lp->lock);
+ lp->pci_dev = pdev;
+ lp->boardtype = ent->driver_data;
- if (tc35815_debug && version_printed++ == 0)
- printk(KERN_DEBUG "%s", version);
-
- /* Fill in the 'dev' fields. */
- dev->irq = irq;
- dev->base_addr = (unsigned long)ioremap(base_addr,
- sizeof(struct tc35815_regs));
- if (!dev->base_addr) {
- ret = -ENOMEM;
- goto err_out;
- }
- tr = (struct tc35815_regs*)dev->base_addr;
+ lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
+ pci_set_drvdata(pdev, dev);
+ /* Soft reset the chip. */
tc35815_chip_reset(dev);
- /* Retrieve and print the ethernet address. */
- while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
- ;
- for (i = 0; i < 6; i += 2) {
- unsigned short data;
- tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
- while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
- ;
- data = tc_readl(&tr->PROM_Data);
- dev->dev_addr[i] = data & 0xff;
- dev->dev_addr[i+1] = data >> 8;
- }
+ /* Retrieve the ethernet address. */
+ tc35815_init_dev_addr(dev);
+
+ rc = register_netdev (dev);
+ if (rc)
+ goto err_out_unmap;
+
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+ printk(KERN_INFO "%s: %s at 0x%lx, "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+ "IRQ %d\n",
+ dev->name,
+ board_info[ent->driver_data].name,
+ dev->base_addr,
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5],
+ dev->irq);
+
+ setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev);
+ lp->mii.dev = dev;
+ lp->mii.mdio_read = tc_mdio_read;
+ lp->mii.mdio_write = tc_mdio_write;
+ lp->mii.phy_id_mask = 0x1f;
+ lp->mii.reg_num_mask = 0x1f;
+ tc35815_find_phy(dev);
+ lp->mii.phy_id = lp->phy_addr;
+ lp->mii.full_duplex = 0;
+ lp->mii.force_media = 0;
- /* Initialize the device structure. */
- lp->pdev = pdev;
- lp->next_module = root_tc35815_dev;
- root_tc35815_dev = dev;
+ return 0;
- spin_lock_init(&lp->lock);
+err_out_unmap:
+ iounmap(ioaddr);
+err_out_free_res:
+ pci_release_regions (pdev);
+err_out:
+ free_netdev (dev);
+ return rc;
+}
- if (dev->mem_start > 0) {
- lp->option = dev->mem_start;
- if ((lp->option & TC35815_OPT_10M) &&
- (lp->option & TC35815_OPT_100M)) {
- /* if both speed speficied, auto select. */
- lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M);
- }
- }
- //XXX fixme
- lp->option |= TC35815_OPT_10M;
- /* do auto negotiation */
- tc35815_phy_chip_init(dev);
+static void __devexit tc35815_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+ unsigned long mmio_addr;
- dev->open = tc35815_open;
- dev->stop = tc35815_close;
- dev->tx_timeout = tc35815_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
- dev->hard_start_xmit = tc35815_send_packet;
- dev->get_stats = tc35815_get_stats;
- dev->set_multicast_list = tc35815_set_multicast_list;
- SET_MODULE_OWNER(dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
+ mmio_addr = dev->base_addr;
- ret = register_netdev(dev);
- if (ret)
- goto err_out_iounmap;
+ unregister_netdev (dev);
- printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC",
- dev->name, cardname, base_addr, irq);
- for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i]);
- printk("\n");
- printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n",
- dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half");
+ if (mmio_addr) {
+ iounmap ((void __iomem *)mmio_addr);
+ pci_release_regions (pdev);
+ }
- return 0;
+ free_netdev (dev);
-err_out_iounmap:
- iounmap((void *) dev->base_addr);
-err_out:
- free_netdev(dev);
- return ret;
+ pci_set_drvdata (pdev, NULL);
}
-
static int
tc35815_init_queues(struct net_device *dev)
{
@@ -629,44 +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_page((unsigned long)lp->data_buf[i]);
- lp->data_buf[i] = 0;
+ free_rxbuf_page(lp->pci_dev,
+ lp->data_buf[i],
+ lp->data_buf_dma[i]);
+ lp->data_buf[i] = NULL;
}
- free_page((unsigned long)lp->fd_buf);
- lp->fd_buf = 0;
+ pci_free_consistent(lp->pci_dev,
+ PAGE_SIZE * FD_PAGE_NUM,
+ lp->fd_buf,
+ lp->fd_buf_dma);
+ lp->fd_buf = NULL;
+ return -ENOMEM;
+ }
+#else
+ lp->rx_skbs[i].skb =
+ alloc_rxbuf_skb(dev, lp->pci_dev,
+ &lp->rx_skbs[i].skb_dma);
+ if (!lp->rx_skbs[i].skb) {
+ while (--i >= 0) {
+ free_rxbuf_skb(lp->pci_dev,
+ lp->rx_skbs[i].skb,
+ lp->rx_skbs[i].skb_dma);
+ lp->rx_skbs[i].skb = NULL;
+ }
+ pci_free_consistent(lp->pci_dev,
+ PAGE_SIZE * FD_PAGE_NUM,
+ lp->fd_buf,
+ lp->fd_buf_dma);
+ lp->fd_buf = NULL;
return -ENOMEM;
}
-#ifdef __mips__
- dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM);
#endif
}
-#ifdef __mips__
- dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+ printk(KERN_DEBUG "%s: FD buf %p DataBuf",
+ dev->name, lp->fd_buf);
+#ifdef TC35815_USE_PACKEDBUFFER
+ printk(" DataBuf");
+ for (i = 0; i < RX_BUF_NUM; i++)
+ printk(" %p", lp->data_buf[i]);
#endif
+ printk("\n");
} else {
- memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM);
-#ifdef __mips__
- dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
-#endif
+ for (i = 0; i < FD_PAGE_NUM; i++) {
+ clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE));
+ }
}
-#ifdef __mips__
- fd_addr = (unsigned long)vtonocache(lp->fd_buf);
-#else
fd_addr = (unsigned long)lp->fd_buf;
-#endif
/* Free Descriptors (for Receive) */
lp->rfd_base = (struct RxFD *)fd_addr;
@@ -675,34 +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)
-{
- struct tc35815_local *lp = dev->priv;
- struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
- unsigned long flags;
-
- spin_lock_irqsave(&lp->lock, flags);
- printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
- dev->name, tc_readl(&tr->Tx_Stat));
- /* Try to restart the adaptor. */
- tc35815_chip_reset(dev);
- tc35815_clear_queues(dev);
- tc35815_chip_init(dev);
- lp->tbusy=0;
- spin_unlock_irqrestore(&lp->lock, flags);
- dev->trans_start = jiffies;
- netif_wake_queue(dev);
-}
-
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
- struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
-
- if (netif_queue_stopped(dev)) {
- /*
- * If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
- dev->name, tc_readl(&tr->Tx_Stat));
- /* Try to restart the adaptor. */
- tc35815_chip_reset(dev);
- tc35815_clear_queues(dev);
- tc35815_chip_init(dev);
- lp->tbusy=0;
- dev->trans_start = jiffies;
- netif_wake_queue(dev);
- }
+ struct TxFD *txfd;
+ unsigned long flags;
- /*
- * Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, lp->tbusy), but set_bit() works as well.
+ /* If some error occurs while trying to transmit this
+ * packet, you should return '1' from this function.
+ * In such a case you _may not_ do anything to the
+ * SKB, it is still owned by the network queueing
+ * layer when an error is returned. This means you
+ * may not modify any SKB fields, you may not free
+ * the SKB, etc.
*/
- if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
- dev_kfree_skb_any(skb);
- } else {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
- struct TxFD *txfd = &lp->tfd_base[lp->tfd_start];
- unsigned long flags;
- lp->stats.tx_bytes += skb->len;
+ /* This is the most common case for modern hardware.
+ * The spinlock protects this code from the TX complete
+ * hardware interrupt handler. Queue flow control is
+ * thus managed under this lock as well.
+ */
+ spin_lock_irqsave(&lp->lock, flags);
-#ifdef __mips__
- dma_cache_wback_inv((unsigned long)buf, length);
+ /* failsafe... (handle txdone now if half of FDs are used) */
+ if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM >
+ TX_FD_NUM / 2)
+ tc35815_txdone(dev);
+
+ if (netif_msg_pktdata(lp))
+ print_eth(skb->data);
+#ifdef DEBUG
+ if (lp->tx_skbs[lp->tfd_start].skb) {
+ printk("%s: tx_skbs conflict.\n", dev->name);
+ panic_queues(dev);
+ }
+#else
+ BUG_ON(lp->tx_skbs[lp->tfd_start].skb);
#endif
-
- spin_lock_irqsave(&lp->lock, flags);
-
- /* failsafe... */
- if (lp->tfd_start != lp->tfd_end)
- tc35815_txdone(dev);
-
-
- txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf));
-
- txfd->bd.BDCtl = cpu_to_le32(length);
- txfd->fd.FDSystem = cpu_to_le32((__u32)skb);
- txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
-
- if (lp->tfd_start == lp->tfd_end) {
- /* Start DMA Transmitter. */
- txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+ lp->tx_skbs[lp->tfd_start].skb = skb;
+ lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+ /*add to ring */
+ txfd = &lp->tfd_base[lp->tfd_start];
+ txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
+ txfd->bd.BDCtl = cpu_to_le32(skb->len);
+ txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
+ txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+
+ if (lp->tfd_start == lp->tfd_end) {
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ /* Start DMA Transmitter. */
+ txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
#ifdef GATHER_TXINT
- txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+ txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
#endif
- if (tc35815_debug > 2) {
- printk("%s: starting TxFD.\n", dev->name);
- dump_txfd(txfd);
- if (tc35815_debug > 3)
- print_eth(buf);
- }
- tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
- } else {
- txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
- if (tc35815_debug > 2) {
- printk("%s: queueing TxFD.\n", dev->name);
- dump_txfd(txfd);
- if (tc35815_debug > 3)
- print_eth(buf);
- }
+ if (netif_msg_tx_queued(lp)) {
+ printk("%s: starting TxFD.\n", dev->name);
+ dump_txfd(txfd);
}
- lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
+ tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
+ } else {
+ txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
+ if (netif_msg_tx_queued(lp)) {
+ printk("%s: queueing TxFD.\n", dev->name);
+ dump_txfd(txfd);
+ }
+ }
+ lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
- dev->trans_start = jiffies;
+ dev->trans_start = jiffies;
- if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) {
- /* we can send another packet */
- lp->tbusy = 0;
- netif_start_queue(dev);
- } else {
- netif_stop_queue(dev);
- if (tc35815_debug > 1)
- printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
- }
- spin_unlock_irqrestore(&lp->lock, flags);
+ /* If we just used up the very last entry in the
+ * TX ring on this device, tell the queueing
+ * layer to send no more.
+ */
+ if (tc35815_tx_full(dev)) {
+ if (netif_msg_tx_queued(lp))
+ printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
+ netif_stop_queue(dev);
}
+ /* When the TX completion hw interrupt arrives, this
+ * is when the transmit statistics are updated.
+ */
+
+ spin_unlock_irqrestore(&lp->lock, flags);
return 0;
}
#define FATAL_ERROR_INT \
(Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
-static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
+static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
{
static int count;
printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
dev->name, status);
-
if (status & Int_IntPCI)
printk(" IntPCI");
if (status & Int_DmParErr)
@@ -1033,110 +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;
+}
- tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
+static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct tc35815_local *lp = dev->priv;
+ int rc;
+#if 1 /* use our negotiation method... */
+ /* Verify the settings we care about. */
+ if (cmd->autoneg != AUTONEG_ENABLE &&
+ cmd->autoneg != AUTONEG_DISABLE)
+ return -EINVAL;
+ if (cmd->autoneg == AUTONEG_DISABLE &&
+ ((cmd->speed != SPEED_100 &&
+ cmd->speed != SPEED_10) ||
+ (cmd->duplex != DUPLEX_HALF &&
+ cmd->duplex != DUPLEX_FULL)))
+ return -EINVAL;
+
+ /* Ok, do it to it. */
+ spin_lock_irq(&lp->lock);
+ del_timer(&lp->timer);
+ tc35815_start_auto_negotiation(dev, cmd);
+ spin_unlock_irq(&lp->lock);
+ rc = 0;
+#else
+ spin_lock_irq(&lp->lock);
+ rc = mii_ethtool_sset(&lp->mii, cmd);
+ spin_unlock_irq(&lp->lock);
+#endif
+ return rc;
+}
+
+static int tc35815_nway_reset(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ int rc;
+ spin_lock_irq(&lp->lock);
+ rc = mii_nway_restart(&lp->mii);
+ spin_unlock_irq(&lp->lock);
+ return rc;
+}
+
+static u32 tc35815_get_link(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ int rc;
+ spin_lock_irq(&lp->lock);
+ rc = mii_link_ok(&lp->mii);
+ spin_unlock_irq(&lp->lock);
+ return rc;
+}
+
+static u32 tc35815_get_msglevel(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ return lp->msg_enable;
+}
+
+static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
+{
+ struct tc35815_local *lp = dev->priv;
+ lp->msg_enable = datum;
+}
+
+static int tc35815_get_stats_count(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ return sizeof(lp->lstats) / sizeof(int);
+}
+
+static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
+{
+ struct tc35815_local *lp = dev->priv;
+ data[0] = lp->lstats.max_tx_qlen;
+ data[1] = lp->lstats.tx_ints;
+ data[2] = lp->lstats.rx_ints;
+ data[3] = lp->lstats.tx_underrun;
+}
+
+static struct {
+ const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+ { "max_tx_qlen" },
+ { "tx_ints" },
+ { "rx_ints" },
+ { "tx_underrun" },
+};
+
+static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+static const struct ethtool_ops tc35815_ethtool_ops = {
+ .get_drvinfo = tc35815_get_drvinfo,
+ .get_settings = tc35815_get_settings,
+ .set_settings = tc35815_set_settings,
+ .nway_reset = tc35815_nway_reset,
+ .get_link = tc35815_get_link,
+ .get_msglevel = tc35815_get_msglevel,
+ .set_msglevel = tc35815_set_msglevel,
+ .get_strings = tc35815_get_strings,
+ .get_stats_count = tc35815_get_stats_count,
+ .get_ethtool_stats = tc35815_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
+};
+
+static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct tc35815_local *lp = dev->priv;
+ int rc;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ spin_lock_irq(&lp->lock);
+ rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+ spin_unlock_irq(&lp->lock);
+
+ return rc;
+}
+
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ u32 data;
+ tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA);
while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
;
data = tc_readl(&tr->MD_Data);
- spin_unlock_irqrestore(&lp->lock, flags);
- return data;
+ return data & 0xffff;
+}
+
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+ int val)
+{
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ tc_writel(val, &tr->MD_Data);
+ tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA);
+ while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+ ;
}
-static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg)
+/* Auto negotiation. The scheme is very simple. We have a timer routine
+ * that keeps watching the auto negotiation process as it progresses.
+ * The DP83840 is first told to start doing it's thing, we set up the time
+ * and place the timer state machine in it's initial state.
+ *
+ * Here the timer peeks at the DP83840 status registers at each click to see
+ * if the auto negotiation has completed, we assume here that the DP83840 PHY
+ * will time out at some point and just tell us what (didn't) happen. For
+ * complete coverage we only allow so many of the ticks at this level to run,
+ * when this has expired we print a warning message and try another strategy.
+ * This "other" strategy is to force the interface into various speed/duplex
+ * configurations and we stop when we see a link-up condition before the
+ * maximum number of "peek" ticks have occurred.
+ *
+ * Once a valid link status has been detected we configure the BigMAC and
+ * the rest of the Happy Meal to speak the most efficient protocol we could
+ * get a clean link for. The priority for link configurations, highest first
+ * is:
+ * 100 Base-T Full Duplex
+ * 100 Base-T Half Duplex
+ * 10 Base-T Full Duplex
+ * 10 Base-T Half Duplex
+ *
+ * We start a new timer now, after a successful auto negotiation status has
+ * been detected. This timer just waits for the link-up bit to get set in
+ * the BMCR of the DP83840. When this occurs we print a kernel log message
+ * describing the link type in use and the fact that it is up.
+ *
+ * If a fatal error of some sort is signalled and detected in the interrupt
+ * service routine, and the chip is reset, or the link is ifconfig'd down
+ * and then back up, this entire process repeats itself all over again.
+ */
+/* Note: Above comments are come from sunhme driver. */
+
+static int tc35815_try_next_permutation(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
- unsigned long flags;
+ int pid = lp->phy_addr;
+ unsigned short bmcr;
- spin_lock_irqsave(&lp->lock, flags);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
- tc_writel(d, &tr->MD_Data);
- tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA);
- while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
- ;
- spin_unlock_irqrestore(&lp->lock, flags);
+ /* Downgrade from full to half duplex. Only possible via ethtool. */
+ if (bmcr & BMCR_FULLDPLX) {
+ bmcr &= ~BMCR_FULLDPLX;
+ printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+ return 0;
+ }
+
+ /* Downgrade from 100 to 10. */
+ if (bmcr & BMCR_SPEED100) {
+ bmcr &= ~BMCR_SPEED100;
+ printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+ return 0;
+ }
+
+ /* We've tried everything. */
+ return -1;
}
-static void tc35815_phy_chip_init(struct net_device *dev)
+static void
+tc35815_display_link_mode(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
- struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
- static int first = 1;
- unsigned short ctl;
-
- if (first) {
- unsigned short id0, id1;
- int count;
- first = 0;
-
- /* first data written to the PHY will be an ID number */
- tc_phy_write(dev, 0, tr, 0, MII_CONTROL); /* ID:0 */
-#if 0
- tc_phy_write(dev, MIICNTL_RESET, tr, 0, MII_CONTROL);
- printk(KERN_INFO "%s: Resetting PHY...", dev->name);
- while (tc_phy_read(dev, tr, 0, MII_CONTROL) & MIICNTL_RESET)
- ;
- printk("\n");
- tc_phy_write(dev, MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0,
- MII_CONTROL);
-#endif
- id0 = tc_phy_read(dev, tr, 0, MII_PHY_ID0);
- id1 = tc_phy_read(dev, tr, 0, MII_PHY_ID1);
- printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name,
- id0, id1);
- if (lp->option & TC35815_OPT_10M) {
- lp->linkspeed = 10;
- lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
- } else if (lp->option & TC35815_OPT_100M) {
- lp->linkspeed = 100;
- lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+ int pid = lp->phy_addr;
+ unsigned short lpa, bmcr;
+ char *speed = "", *duplex = "";
+
+ lpa = tc_mdio_read(dev, pid, MII_LPA);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+ speed = "100Mb/s";
+ else
+ speed = "10Mb/s";
+ if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+ duplex = "Full Duplex";
+ else
+ duplex = "Half Duplex";
+
+ if (netif_msg_link(lp))
+ printk(KERN_INFO "%s: Link is up at %s, %s.\n",
+ dev->name, speed, duplex);
+ printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+ dev->name,
+ bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+}
+
+static void tc35815_display_forced_link_mode(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short bmcr;
+ char *speed = "", *duplex = "";
+
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (bmcr & BMCR_SPEED100)
+ speed = "100Mb/s";
+ else
+ speed = "10Mb/s";
+ if (bmcr & BMCR_FULLDPLX)
+ duplex = "Full Duplex.\n";
+ else
+ duplex = "Half Duplex.\n";
+
+ if (netif_msg_link(lp))
+ printk(KERN_INFO "%s: Link has been forced up at %s, %s",
+ dev->name, speed, duplex);
+}
+
+static void tc35815_set_link_modes(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ int pid = lp->phy_addr;
+ unsigned short bmcr, lpa;
+ int speed;
+
+ if (lp->timer_state == arbwait) {
+ lpa = tc_mdio_read(dev, pid, MII_LPA);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+ dev->name,
+ bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+ if (!(lpa & (LPA_10HALF | LPA_10FULL |
+ LPA_100HALF | LPA_100FULL))) {
+ /* fall back to 10HALF */
+ printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n",
+ dev->name, lpa);
+ lpa = LPA_10HALF;
+ }
+ if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+ lp->fullduplex = 1;
+ else
+ lp->fullduplex = 0;
+ if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+ speed = 100;
+ else
+ speed = 10;
+ } else {
+ /* Forcing a link mode. */
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (bmcr & BMCR_FULLDPLX)
+ lp->fullduplex = 1;
+ else
+ lp->fullduplex = 0;
+ if (bmcr & BMCR_SPEED100)
+ speed = 100;
+ else
+ speed = 10;
+ }
+
+ tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl);
+ if (lp->fullduplex) {
+ tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+ } else {
+ tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl);
+ }
+ tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl);
+
+ /* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */
+
+#ifndef NO_CHECK_CARRIER
+ /* TX4939 does not have EnLCarr */
+ if (lp->boardtype != TC35815_TX4939) {
+#ifdef WORKAROUND_LOSTCAR
+ /* WORKAROUND: enable LostCrS only if half duplex operation */
+ if (!lp->fullduplex && lp->boardtype != TC35815_TX4939)
+ tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl);
+#endif
+ }
+#endif
+ lp->mii.full_duplex = lp->fullduplex;
+}
+
+static void tc35815_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short bmsr, bmcr, lpa;
+ int restart_timer = 0;
+
+ spin_lock_irq(&lp->lock);
+
+ lp->timer_ticks++;
+ switch (lp->timer_state) {
+ case arbwait:
+ /*
+ * Only allow for 5 ticks, thats 10 seconds and much too
+ * long to wait for arbitration to complete.
+ */
+ /* TC35815 need more times... */
+ if (lp->timer_ticks >= 10) {
+ /* Enter force mode. */
+ if (!options.doforce) {
+ printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+ " cable probblem?\n", dev->name);
+ /* Try to restart the adaptor. */
+ tc35815_restart(dev);
+ goto out;
+ }
+ printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+ " trying force link mode\n", dev->name);
+ printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name,
+ tc_mdio_read(dev, pid, MII_BMCR),
+ tc_mdio_read(dev, pid, MII_BMSR));
+ bmcr = BMCR_SPEED100;
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+ /*
+ * OK, seems we need do disable the transceiver
+ * for the first tick to make sure we get an
+ * accurate link state at the second tick.
+ */
+
+ lp->timer_state = ltrywait;
+ lp->timer_ticks = 0;
+ restart_timer = 1;
} else {
- /* auto negotiation */
- unsigned long neg_result;
- tc_phy_write(dev, MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL);
- printk(KERN_INFO "%s: Auto Negotiation...", dev->name);
- count = 0;
- while (!(tc_phy_read(dev, tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) {
- if (count++ > 5000) {
- printk(" failed. Assume 10Mbps\n");
- lp->linkspeed = 10;
- lp->fullduplex = 0;
- goto done;
+ /* Anything interesting happen? */
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ if (bmsr & BMSR_ANEGCOMPLETE) {
+ /* Just what we've been waiting for... */
+ tc35815_set_link_modes(dev);
+
+ /*
+ * Success, at least so far, advance our state
+ * engine.
+ */
+ lp->timer_state = lupwait;
+ restart_timer = 1;
+ } else {
+ restart_timer = 1;
+ }
+ }
+ break;
+
+ case lupwait:
+ /*
+ * Auto negotiation was successful and we are awaiting a
+ * link up status. I have decided to let this timer run
+ * forever until some sort of error is signalled, reporting
+ * a message to the user at 10 second intervals.
+ */
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ if (bmsr & BMSR_LSTATUS) {
+ /*
+ * Wheee, it's up, display the link mode in use and put
+ * the timer to sleep.
+ */
+ tc35815_display_link_mode(dev);
+ netif_carrier_on(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+ /* delayed promiscuous enabling */
+ if (dev->flags & IFF_PROMISC)
+ tc35815_set_multicast_list(dev);
+#endif
+#if 1
+ lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+ lp->timer_state = lcheck;
+ restart_timer = 1;
+#else
+ lp->timer_state = asleep;
+ restart_timer = 0;
+#endif
+ } else {
+ if (lp->timer_ticks >= 10) {
+ printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
+ "not completely up.\n", dev->name);
+ lp->timer_ticks = 0;
+ restart_timer = 1;
+ } else {
+ restart_timer = 1;
+ }
+ }
+ break;
+
+ case ltrywait:
+ /*
+ * Making the timeout here too long can make it take
+ * annoyingly long to attempt all of the link mode
+ * permutations, but then again this is essentially
+ * error recovery code for the most part.
+ */
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (lp->timer_ticks == 1) {
+ /*
+ * Re-enable transceiver, we'll re-enable the
+ * transceiver next tick, then check link state
+ * on the following tick.
+ */
+ restart_timer = 1;
+ break;
+ }
+ if (lp->timer_ticks == 2) {
+ restart_timer = 1;
+ break;
+ }
+ if (bmsr & BMSR_LSTATUS) {
+ /* Force mode selection success. */
+ tc35815_display_forced_link_mode(dev);
+ netif_carrier_on(dev);
+ tc35815_set_link_modes(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+ /* delayed promiscuous enabling */
+ if (dev->flags & IFF_PROMISC)
+ tc35815_set_multicast_list(dev);
+#endif
+#if 1
+ lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+ lp->timer_state = lcheck;
+ restart_timer = 1;
+#else
+ lp->timer_state = asleep;
+ restart_timer = 0;
+#endif
+ } else {
+ if (lp->timer_ticks >= 4) { /* 6 seconds or so... */
+ int ret;
+
+ ret = tc35815_try_next_permutation(dev);
+ if (ret == -1) {
+ /*
+ * Aieee, tried them all, reset the
+ * chip and try all over again.
+ */
+ printk(KERN_NOTICE "%s: Link down, "
+ "cable problem?\n",
+ dev->name);
+
+ /* Try to restart the adaptor. */
+ tc35815_restart(dev);
+ goto out;
}
- if (count % 512 == 0)
- printk(".");
- mdelay(1);
+ lp->timer_ticks = 0;
+ restart_timer = 1;
+ } else {
+ restart_timer = 1;
+ }
+ }
+ break;
+
+ case lcheck:
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ lpa = tc_mdio_read(dev, pid, MII_LPA);
+ if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) {
+ printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name,
+ bmcr);
+ } else if ((lp->saved_lpa ^ lpa) &
+ (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) {
+ printk(KERN_NOTICE "%s: link status changed"
+ " (BMCR %x LPA %x->%x)\n", dev->name,
+ bmcr, lp->saved_lpa, lpa);
+ } else {
+ /* go on */
+ restart_timer = 1;
+ break;
+ }
+ /* Try to restart the adaptor. */
+ tc35815_restart(dev);
+ goto out;
+
+ case asleep:
+ default:
+ /* Can't happens.... */
+ printk(KERN_ERR "%s: Aieee, link timer is asleep but we got "
+ "one anyways!\n", dev->name);
+ restart_timer = 0;
+ lp->timer_ticks = 0;
+ lp->timer_state = asleep; /* foo on you */
+ break;
+ }
+
+ if (restart_timer) {
+ lp->timer.expires = jiffies + msecs_to_jiffies(1200);
+ add_timer(&lp->timer);
+ }
+out:
+ spin_unlock_irq(&lp->lock);
+}
+
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+ struct ethtool_cmd *ep)
+{
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short bmsr, bmcr, advertize;
+ int timeout;
+
+ netif_carrier_off(dev);
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ advertize = tc_mdio_read(dev, pid, MII_ADVERTISE);
+
+ if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+ if (options.speed || options.duplex) {
+ /* Advertise only specified configuration. */
+ advertize &= ~(ADVERTISE_10HALF |
+ ADVERTISE_10FULL |
+ ADVERTISE_100HALF |
+ ADVERTISE_100FULL);
+ if (options.speed != 10) {
+ if (options.duplex != 1)
+ advertize |= ADVERTISE_100FULL;
+ if (options.duplex != 2)
+ advertize |= ADVERTISE_100HALF;
+ }
+ if (options.speed != 100) {
+ if (options.duplex != 1)
+ advertize |= ADVERTISE_10FULL;
+ if (options.duplex != 2)
+ advertize |= ADVERTISE_10HALF;
}
- printk(" done.\n");
- neg_result = tc_phy_read(dev, tr, 0, MII_ANLPAR);
- if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX))
- lp->linkspeed = 100;
+ if (options.speed == 100)
+ bmcr |= BMCR_SPEED100;
+ else if (options.speed == 10)
+ bmcr &= ~BMCR_SPEED100;
+ if (options.duplex == 2)
+ bmcr |= BMCR_FULLDPLX;
+ else if (options.duplex == 1)
+ bmcr &= ~BMCR_FULLDPLX;
+ } else {
+ /* Advertise everything we can support. */
+ if (bmsr & BMSR_10HALF)
+ advertize |= ADVERTISE_10HALF;
else
- lp->linkspeed = 10;
- if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX))
- lp->fullduplex = 1;
+ advertize &= ~ADVERTISE_10HALF;
+ if (bmsr & BMSR_10FULL)
+ advertize |= ADVERTISE_10FULL;
else
- lp->fullduplex = 0;
- done:
- ;
+ advertize &= ~ADVERTISE_10FULL;
+ if (bmsr & BMSR_100HALF)
+ advertize |= ADVERTISE_100HALF;
+ else
+ advertize &= ~ADVERTISE_100HALF;
+ if (bmsr & BMSR_100FULL)
+ advertize |= ADVERTISE_100FULL;
+ else
+ advertize &= ~ADVERTISE_100FULL;
+ }
+
+ tc_mdio_write(dev, pid, MII_ADVERTISE, advertize);
+
+ /* Enable Auto-Negotiation, this is usually on already... */
+ bmcr |= BMCR_ANENABLE;
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+ /* Restart it to make sure it is going. */
+ bmcr |= BMCR_ANRESTART;
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+ printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr);
+
+ /* BMCR_ANRESTART self clears when the process has begun. */
+ timeout = 64; /* More than enough. */
+ while (--timeout) {
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (!(bmcr & BMCR_ANRESTART))
+ break; /* got it. */
+ udelay(10);
}
+ if (!timeout) {
+ printk(KERN_ERR "%s: TC35815 would not start auto "
+ "negotiation BMCR=0x%04x\n",
+ dev->name, bmcr);
+ printk(KERN_NOTICE "%s: Performing force link "
+ "detection.\n", dev->name);
+ goto force_link;
+ } else {
+ printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name);
+ lp->timer_state = arbwait;
+ }
+ } else {
+force_link:
+ /* Force the link up, trying first a particular mode.
+ * Either we are here at the request of ethtool or
+ * because the Happy Meal would not start to autoneg.
+ */
+
+ /* Disable auto-negotiation in BMCR, enable the duplex and
+ * speed setting, init the timer state machine, and fire it off.
+ */
+ if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+ bmcr = BMCR_SPEED100;
+ } else {
+ if (ep->speed == SPEED_100)
+ bmcr = BMCR_SPEED100;
+ else
+ bmcr = 0;
+ if (ep->duplex == DUPLEX_FULL)
+ bmcr |= BMCR_FULLDPLX;
+ }
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+ /* OK, seems we need do disable the transceiver for the first
+ * tick to make sure we get an accurate link state at the
+ * second tick.
+ */
+ lp->timer_state = ltrywait;
}
- ctl = 0;
- if (lp->linkspeed == 100)
- ctl |= MIICNTL_SPEED;
- if (lp->fullduplex)
- ctl |= MIICNTL_FDX;
- tc_phy_write(dev, ctl, tr, 0, MII_CONTROL);
+ del_timer(&lp->timer);
+ lp->timer_ticks = 0;
+ lp->timer.expires = jiffies + msecs_to_jiffies(1200);
+ add_timer(&lp->timer);
+}
- if (lp->fullduplex) {
- tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+static void tc35815_find_phy(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short id0;
+
+ /* find MII phy */
+ for (pid = 31; pid >= 0; pid--) {
+ id0 = tc_mdio_read(dev, pid, MII_BMSR);
+ if (id0 != 0xffff && id0 != 0x0000 &&
+ (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */
+ ) {
+ lp->phy_addr = pid;
+ break;
+ }
}
+ if (pid < 0) {
+ printk(KERN_ERR "%s: No MII Phy found.\n",
+ dev->name);
+ lp->phy_addr = pid = 0;
+ }
+
+ lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1);
+ lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2);
+ if (netif_msg_hw(lp))
+ printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name,
+ pid, lp->mii_id[0], lp->mii_id[1]);
}
-static void tc35815_chip_reset(struct net_device *dev)
+static void tc35815_phy_chip_init(struct net_device *dev)
{
- struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short bmcr;
+ struct ethtool_cmd ecmd, *ep;
+
+ /* dis-isolate if needed. */
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (bmcr & BMCR_ISOLATE) {
+ int count = 32;
+ printk(KERN_DEBUG "%s: unisolating...", dev->name);
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE);
+ while (--count) {
+ if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE))
+ break;
+ udelay(20);
+ }
+ printk(" %s.\n", count ? "done" : "failed");
+ }
+
+ if (options.speed && options.duplex) {
+ ecmd.autoneg = AUTONEG_DISABLE;
+ ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100;
+ ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL;
+ ep = &ecmd;
+ } else {
+ ep = NULL;
+ }
+ tc35815_start_auto_negotiation(dev, ep);
+}
+static void tc35815_chip_reset(struct net_device *dev)
+{
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ int i;
/* reset the controller */
tc_writel(MAC_Reset, &tr->MAC_Ctl);
- while (tc_readl(&tr->MAC_Ctl) & MAC_Reset)
- ;
-
+ udelay(4); /* 3200ns */
+ i = 0;
+ while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
+ if (i++ > 100) {
+ printk(KERN_ERR "%s: MAC reset failed.\n", dev->name);
+ break;
+ }
+ mdelay(1);
+ }
tc_writel(0, &tr->MAC_Ctl);
/* initialize registers to default value */
@@ -1650,90 +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");
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index b3a64ca98634..4ed67ff0e81e 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -55,9 +55,6 @@
TODO
- Implement pci_driver::suspend() and pci_driver::resume()
- power management methods.
-
Check on 64 bit boxes.
Check and fix on big endian boxes.
@@ -125,6 +122,11 @@
#define DM9801_NOISE_FLOOR 8
#define DM9802_NOISE_FLOOR 5
+#define DMFE_WOL_LINKCHANGE 0x20000000
+#define DMFE_WOL_SAMPLEPACKET 0x10000000
+#define DMFE_WOL_MAGICPACKET 0x08000000
+
+
#define DMFE_10MHF 0
#define DMFE_100MHF 1
#define DMFE_10MFD 4
@@ -251,6 +253,7 @@ struct dmfe_board_info {
u8 wait_reset; /* Hardware failed, need to reset */
u8 dm910x_chk_mode; /* Operating mode check */
u8 first_in_callback; /* Flag to record state */
+ u8 wol_mode; /* user WOL settings */
struct timer_list timer;
/* System defined statistic counter */
@@ -431,6 +434,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
db->chip_id = ent->driver_data;
db->ioaddr = pci_resource_start(pdev, 0);
db->chip_revision = dev_rev;
+ db->wol_mode = 0;
db->pdev = pdev;
@@ -1065,7 +1069,11 @@ static void dmfe_set_filter_mode(struct DEVICE * dev)
spin_unlock_irqrestore(&db->lock, flags);
}
-static void netdev_get_drvinfo(struct net_device *dev,
+/*
+ * Ethtool interace
+ */
+
+static void dmfe_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct dmfe_board_info *np = netdev_priv(dev);
@@ -1079,9 +1087,35 @@ static void netdev_get_drvinfo(struct net_device *dev,
dev->base_addr, dev->irq);
}
+static int dmfe_ethtool_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct dmfe_board_info *db = netdev_priv(dev);
+
+ if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST |
+ WAKE_ARP | WAKE_MAGICSECURE))
+ return -EOPNOTSUPP;
+
+ db->wol_mode = wolinfo->wolopts;
+ return 0;
+}
+
+static void dmfe_ethtool_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct dmfe_board_info *db = netdev_priv(dev);
+
+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
+ wolinfo->wolopts = db->wol_mode;
+ return;
+}
+
+
static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
+ .get_drvinfo = dmfe_ethtool_get_drvinfo,
.get_link = ethtool_op_get_link,
+ .set_wol = dmfe_ethtool_set_wol,
+ .get_wol = dmfe_ethtool_get_wol,
};
/*
@@ -2050,11 +2084,85 @@ static struct pci_device_id dmfe_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
+#ifdef CONFIG_PM
+static int dmfe_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pci_dev);
+ struct dmfe_board_info *db = netdev_priv(dev);
+ u32 tmp;
+
+ /* Disable upper layer interface */
+ netif_device_detach(dev);
+
+ /* Disable Tx/Rx */
+ db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);
+ update_cr6(db->cr6_data, dev->base_addr);
+
+ /* Disable Interrupt */
+ outl(0, dev->base_addr + DCR7);
+ outl(inl (dev->base_addr + DCR5), dev->base_addr + DCR5);
+
+ /* Fre RX buffers */
+ dmfe_free_rxbuffer(db);
+
+ /* Enable WOL */
+ pci_read_config_dword(pci_dev, 0x40, &tmp);
+ tmp &= ~(DMFE_WOL_LINKCHANGE|DMFE_WOL_MAGICPACKET);
+
+ if (db->wol_mode & WAKE_PHY)
+ tmp |= DMFE_WOL_LINKCHANGE;
+ if (db->wol_mode & WAKE_MAGIC)
+ tmp |= DMFE_WOL_MAGICPACKET;
+
+ pci_write_config_dword(pci_dev, 0x40, tmp);
+
+ pci_enable_wake(pci_dev, PCI_D3hot, 1);
+ pci_enable_wake(pci_dev, PCI_D3cold, 1);
+
+ /* Power down device*/
+ pci_set_power_state(pci_dev, pci_choose_state (pci_dev,state));
+ pci_save_state(pci_dev);
+
+ return 0;
+}
+
+static int dmfe_resume(struct pci_dev *pci_dev)
+{
+ struct net_device *dev = pci_get_drvdata(pci_dev);
+ u32 tmp;
+
+ pci_restore_state(pci_dev);
+ pci_set_power_state(pci_dev, PCI_D0);
+
+ /* Re-initilize DM910X board */
+ dmfe_init_dm910x(dev);
+
+ /* Disable WOL */
+ pci_read_config_dword(pci_dev, 0x40, &tmp);
+
+ tmp &= ~(DMFE_WOL_LINKCHANGE | DMFE_WOL_MAGICPACKET);
+ pci_write_config_dword(pci_dev, 0x40, tmp);
+
+ pci_enable_wake(pci_dev, PCI_D3hot, 0);
+ pci_enable_wake(pci_dev, PCI_D3cold, 0);
+
+ /* Restart upper layer interface */
+ netif_device_attach(dev);
+
+ return 0;
+}
+#else
+#define dmfe_suspend NULL
+#define dmfe_resume NULL
+#endif
+
static struct pci_driver dmfe_driver = {
.name = "dmfe",
.id_table = dmfe_pci_tbl,
.probe = dmfe_init_one,
.remove = __devexit_p(dmfe_remove_one),
+ .suspend = dmfe_suspend,
+ .resume = dmfe_resume
};
MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index e86df07769a1..9b08afbd1f65 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -673,7 +673,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
if (tp->link_change)
(tp->link_change)(dev, csr5);
}
- if (csr5 & SytemError) {
+ if (csr5 & SystemError) {
int error = (csr5 >> 23) & 7;
/* oops, we hit a PCI error. The code produced corresponds
* to the reason:
@@ -743,7 +743,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
TxFIFOUnderflow |
TxJabber |
TPLnkFail |
- SytemError )) != 0);
+ SystemError )) != 0);
#else
} while ((csr5 & (NormalIntr|AbnormalIntr)) != 0);
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
index 20bd52b86993..b56256636543 100644
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/tulip/media.c
@@ -44,8 +44,10 @@ static const unsigned char comet_miireg2offset[32] = {
/* MII transceiver control section.
Read and write the MII registers using software-generated serial
- MDIO protocol. See the MII specifications or DP83840A data sheet
- for details. */
+ MDIO protocol.
+ See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions")
+ or DP83840A data sheet for more details.
+ */
int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
{
@@ -261,24 +263,56 @@ void tulip_select_media(struct net_device *dev, int startup)
u16 *reset_sequence = &((u16*)(p+3))[init_length];
int reset_length = p[2 + init_length*2];
misc_info = reset_sequence + reset_length;
- if (startup)
+ if (startup) {
+ int timeout = 10; /* max 1 ms */
for (i = 0; i < reset_length; i++)
iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+
+ /* flush posted writes */
+ ioread32(ioaddr + CSR15);
+
+ /* Sect 3.10.3 in DP83840A.pdf (p39) */
+ udelay(500);
+
+ /* Section 4.2 in DP83840A.pdf (p43) */
+ /* and IEEE 802.3 "22.2.4.1.1 Reset" */
+ while (timeout-- &&
+ (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
+ udelay(100);
+ }
for (i = 0; i < init_length; i++)
iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+
+ ioread32(ioaddr + CSR15); /* flush posted writes */
} else {
u8 *init_sequence = p + 2;
u8 *reset_sequence = p + 3 + init_length;
int reset_length = p[2 + init_length];
misc_info = (u16*)(reset_sequence + reset_length);
if (startup) {
+ int timeout = 10; /* max 1 ms */
iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
for (i = 0; i < reset_length; i++)
iowrite32(reset_sequence[i], ioaddr + CSR12);
+
+ /* flush posted writes */
+ ioread32(ioaddr + CSR12);
+
+ /* Sect 3.10.3 in DP83840A.pdf (p39) */
+ udelay(500);
+
+ /* Section 4.2 in DP83840A.pdf (p43) */
+ /* and IEEE 802.3 "22.2.4.1.1 Reset" */
+ while (timeout-- &&
+ (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
+ udelay(100);
}
for (i = 0; i < init_length; i++)
iowrite32(init_sequence[i], ioaddr + CSR12);
+
+ ioread32(ioaddr + CSR12); /* flush posted writes */
}
+
tmp_info = get_u16(&misc_info[1]);
if (tmp_info)
tp->advertising[phy_num] = tmp_info | 1;
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 25f25da76917..c840d2e67b23 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -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));
}
}
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index e9bf526ec534..041af63f2811 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -17,11 +17,11 @@
#define DRV_NAME "tulip"
#ifdef CONFIG_TULIP_NAPI
-#define DRV_VERSION "1.1.14-NAPI" /* Keep at least for test */
+#define DRV_VERSION "1.1.15-NAPI" /* Keep at least for test */
#else
-#define DRV_VERSION "1.1.14"
+#define DRV_VERSION "1.1.15"
#endif
-#define DRV_RELDATE "May 11, 2002"
+#define DRV_RELDATE "Feb 27, 2007"
#include <linux/module.h>
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 5b71ac78bca2..fa440706fb4a 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1147,7 +1147,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
}
/* Abnormal error summary/uncommon events handlers. */
- if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SytemError |
+ if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SystemError |
TimerInt | TxDied))
netdev_error(dev, intr_status);
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 639e1e6913bf..16b9acdabbe8 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -29,6 +29,7 @@
#include <linux/fsl_devices.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/phy.h>
#include <linux/workqueue.h>
#include <asm/of_platform.h>
@@ -41,12 +42,13 @@
#include <asm/ucc_fast.h>
#include "ucc_geth.h"
-#include "ucc_geth_phy.h"
+#include "ucc_geth_mii.h"
#undef DEBUG
-#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:Sept 11, 2006"
+#define DRV_DESC "QE UCC Gigabit Ethernet Controller"
#define DRV_NAME "ucc_geth"
+#define DRV_VERSION "1.1"
#define ugeth_printk(level, format, arg...) \
printk(level format "\n", ## arg)
@@ -73,22 +75,13 @@ static struct ucc_geth_info ugeth_primary_info = {
.bd_mem_part = MEM_PART_SYSTEM,
.rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES,
.max_rx_buf_length = 1536,
-/* FIXME: should be changed in run time for 1G and 100M */
-#ifdef CONFIG_UGETH_HAS_GIGA
- .urfs = UCC_GETH_URFS_GIGA_INIT,
- .urfet = UCC_GETH_URFET_GIGA_INIT,
- .urfset = UCC_GETH_URFSET_GIGA_INIT,
- .utfs = UCC_GETH_UTFS_GIGA_INIT,
- .utfet = UCC_GETH_UTFET_GIGA_INIT,
- .utftt = UCC_GETH_UTFTT_GIGA_INIT,
-#else
+ /* adjusted at startup if max-speed 1000 */
.urfs = UCC_GETH_URFS_INIT,
.urfet = UCC_GETH_URFET_INIT,
.urfset = UCC_GETH_URFSET_INIT,
.utfs = UCC_GETH_UTFS_INIT,
.utfet = UCC_GETH_UTFET_INIT,
.utftt = UCC_GETH_UTFTT_INIT,
-#endif
.ufpt = 256,
.mode = UCC_FAST_PROTOCOL_MODE_ETHERNET,
.ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL,
@@ -217,70 +210,6 @@ static struct list_head *dequeue(struct list_head *lh)
}
}
-static int get_interface_details(enum enet_interface enet_interface,
- enum enet_speed *speed,
- int *r10m,
- int *rmm,
- int *rpm,
- int *tbi, int *limited_to_full_duplex)
-{
- /* Analyze enet_interface according to Interface Mode
- Configuration table */
- switch (enet_interface) {
- case ENET_10_MII:
- *speed = ENET_SPEED_10BT;
- break;
- case ENET_10_RMII:
- *speed = ENET_SPEED_10BT;
- *r10m = 1;
- *rmm = 1;
- break;
- case ENET_10_RGMII:
- *speed = ENET_SPEED_10BT;
- *rpm = 1;
- *r10m = 1;
- *limited_to_full_duplex = 1;
- break;
- case ENET_100_MII:
- *speed = ENET_SPEED_100BT;
- break;
- case ENET_100_RMII:
- *speed = ENET_SPEED_100BT;
- *rmm = 1;
- break;
- case ENET_100_RGMII:
- *speed = ENET_SPEED_100BT;
- *rpm = 1;
- *limited_to_full_duplex = 1;
- break;
- case ENET_1000_GMII:
- *speed = ENET_SPEED_1000BT;
- *limited_to_full_duplex = 1;
- break;
- case ENET_1000_RGMII:
- *speed = ENET_SPEED_1000BT;
- *rpm = 1;
- *limited_to_full_duplex = 1;
- break;
- case ENET_1000_TBI:
- *speed = ENET_SPEED_1000BT;
- *tbi = 1;
- *limited_to_full_duplex = 1;
- break;
- case ENET_1000_RTBI:
- *speed = ENET_SPEED_1000BT;
- *rpm = 1;
- *tbi = 1;
- *limited_to_full_duplex = 1;
- break;
- default:
- return -EINVAL;
- break;
- }
-
- return 0;
-}
-
static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd)
{
struct sk_buff *skb = NULL;
@@ -758,24 +687,6 @@ static void dump_regs(struct ucc_geth_private *ugeth)
ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x",
(u32) & ugeth->ug_regs->hafdup,
in_be32(&ugeth->ug_regs->hafdup));
- ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimcfg,
- in_be32(&ugeth->ug_regs->miimng.miimcfg));
- ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimcom,
- in_be32(&ugeth->ug_regs->miimng.miimcom));
- ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimadd,
- in_be32(&ugeth->ug_regs->miimng.miimadd));
- ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimcon,
- in_be32(&ugeth->ug_regs->miimng.miimcon));
- ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimstat,
- in_be32(&ugeth->ug_regs->miimng.miimstat));
- ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimind,
- in_be32(&ugeth->ug_regs->miimng.miimind));
ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x",
(u32) & ugeth->ug_regs->ifctl,
in_be32(&ugeth->ug_regs->ifctl));
@@ -1425,27 +1336,6 @@ static int init_mac_station_addr_regs(u8 address_byte_0,
return 0;
}
-static int init_mac_duplex_mode(int full_duplex,
- int limited_to_full_duplex,
- volatile u32 *maccfg2_register)
-{
- u32 value = 0;
-
- /* some interfaces must work in full duplex mode */
- if ((full_duplex == 0) && (limited_to_full_duplex == 1))
- return -EINVAL;
-
- value = in_be32(maccfg2_register);
-
- if (full_duplex)
- value |= MACCFG2_FDX;
- else
- value &= ~MACCFG2_FDX;
-
- out_be32(maccfg2_register, value);
- return 0;
-}
-
static int init_check_frame_length_mode(int length_check,
volatile u32 *maccfg2_register)
{
@@ -1477,40 +1367,6 @@ static int init_preamble_length(u8 preamble_length,
return 0;
}
-static int init_mii_management_configuration(int reset_mgmt,
- int preamble_supress,
- volatile u32 *miimcfg_register,
- volatile u32 *miimind_register)
-{
- unsigned int timeout = PHY_INIT_TIMEOUT;
- u32 value = 0;
-
- value = in_be32(miimcfg_register);
- if (reset_mgmt) {
- value |= MIIMCFG_RESET_MANAGEMENT;
- out_be32(miimcfg_register, value);
- }
-
- value = 0;
-
- if (preamble_supress)
- value |= MIIMCFG_NO_PREAMBLE;
-
- value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT;
- out_be32(miimcfg_register, value);
-
- /* Wait until the bus is free */
- while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--)
- cpu_relax();
-
- if (timeout <= 0) {
- ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
static int init_rx_parameters(int reject_broadcast,
int receive_short_frames,
int promiscuous, volatile u32 *upsmr_register)
@@ -1570,10 +1426,8 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
struct ucc_geth_info *ug_info;
struct ucc_geth *ug_regs;
struct ucc_fast *uf_regs;
- enum enet_speed speed;
- int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm =
- 0, limited_to_full_duplex = 0;
- u32 upsmr, maccfg2, utbipar, tbiBaseAddress;
+ int ret_val;
+ u32 upsmr, maccfg2, tbiBaseAddress;
u16 value;
ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -1582,24 +1436,13 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
ug_regs = ugeth->ug_regs;
uf_regs = ugeth->uccf->uf_regs;
- /* Analyze enet_interface according to Interface Mode Configuration
- table */
- ret_val =
- get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm,
- &rpm, &tbi, &limited_to_full_duplex);
- if (ret_val != 0) {
- ugeth_err
- ("%s: half duplex not supported in requested configuration.",
- __FUNCTION__);
- return ret_val;
- }
-
/* Set MACCFG2 */
maccfg2 = in_be32(&ug_regs->maccfg2);
maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
- if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT))
+ if ((ugeth->max_speed == SPEED_10) ||
+ (ugeth->max_speed == SPEED_100))
maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
- else if (speed == ENET_SPEED_1000BT)
+ else if (ugeth->max_speed == SPEED_1000)
maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
maccfg2 |= ug_info->padAndCrc;
out_be32(&ug_regs->maccfg2, maccfg2);
@@ -1607,54 +1450,39 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
/* Set UPSMR */
upsmr = in_be32(&uf_regs->upsmr);
upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM);
- if (rpm)
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
upsmr |= UPSMR_RPM;
- if (r10m)
- upsmr |= UPSMR_R10M;
- if (tbi)
+ switch (ugeth->max_speed) {
+ case SPEED_10:
+ upsmr |= UPSMR_R10M;
+ /* FALLTHROUGH */
+ case SPEED_100:
+ if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI)
+ upsmr |= UPSMR_RMM;
+ }
+ }
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
upsmr |= UPSMR_TBIM;
- if (rmm)
- upsmr |= UPSMR_RMM;
+ }
out_be32(&uf_regs->upsmr, upsmr);
- /* Set UTBIPAR */
- utbipar = in_be32(&ug_regs->utbipar);
- utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK;
- if (tbi)
- utbipar |=
- (ug_info->phy_address +
- ugeth->ug_info->uf_info.
- ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
- else
- utbipar |=
- (0x10 +
- ugeth->ug_info->uf_info.
- ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
- out_be32(&ug_regs->utbipar, utbipar);
-
/* Disable autonegotiation in tbi mode, because by default it
comes up in autonegotiation mode. */
/* Note that this depends on proper setting in utbipar register. */
- if (tbi) {
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
tbiBaseAddress = in_be32(&ug_regs->utbipar);
tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK;
tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT;
- value =
- ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress,
- ENET_TBI_MII_CR);
+ value = ugeth->phydev->bus->read(ugeth->phydev->bus,
+ (u8) tbiBaseAddress, ENET_TBI_MII_CR);
value &= ~0x1000; /* Turn off autonegotiation */
- ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress,
- ENET_TBI_MII_CR, value);
- }
-
- ret_val = init_mac_duplex_mode(1,
- limited_to_full_duplex,
- &ug_regs->maccfg2);
- if (ret_val != 0) {
- ugeth_err
- ("%s: half duplex not supported in requested configuration.",
- __FUNCTION__);
- return ret_val;
+ ugeth->phydev->bus->write(ugeth->phydev->bus,
+ (u8) tbiBaseAddress, ENET_TBI_MII_CR, value);
}
init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2);
@@ -1676,76 +1504,88 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
* function converts those variables into the appropriate
* register values, and can bring down the device if needed.
*/
+
static void adjust_link(struct net_device *dev)
{
struct ucc_geth_private *ugeth = netdev_priv(dev);
struct ucc_geth *ug_regs;
- u32 tempval;
- struct ugeth_mii_info *mii_info = ugeth->mii_info;
+ struct ucc_fast *uf_regs;
+ struct phy_device *phydev = ugeth->phydev;
+ unsigned long flags;
+ int new_state = 0;
ug_regs = ugeth->ug_regs;
+ uf_regs = ugeth->uccf->uf_regs;
- if (mii_info->link) {
+ spin_lock_irqsave(&ugeth->lock, flags);
+
+ if (phydev->link) {
+ u32 tempval = in_be32(&ug_regs->maccfg2);
+ u32 upsmr = in_be32(&uf_regs->upsmr);
/* Now we make sure that we can be in full duplex mode.
* If not, we operate in half-duplex mode. */
- if (mii_info->duplex != ugeth->oldduplex) {
- if (!(mii_info->duplex)) {
- tempval = in_be32(&ug_regs->maccfg2);
+ if (phydev->duplex != ugeth->oldduplex) {
+ new_state = 1;
+ if (!(phydev->duplex))
tempval &= ~(MACCFG2_FDX);
- out_be32(&ug_regs->maccfg2, tempval);
-
- ugeth_info("%s: Half Duplex", dev->name);
- } else {
- tempval = in_be32(&ug_regs->maccfg2);
+ else
tempval |= MACCFG2_FDX;
- out_be32(&ug_regs->maccfg2, tempval);
-
- ugeth_info("%s: Full Duplex", dev->name);
- }
-
- ugeth->oldduplex = mii_info->duplex;
+ ugeth->oldduplex = phydev->duplex;
}
- if (mii_info->speed != ugeth->oldspeed) {
- switch (mii_info->speed) {
- case 1000:
- ugeth->ug_info->enet_interface = ENET_1000_RGMII;
+ if (phydev->speed != ugeth->oldspeed) {
+ new_state = 1;
+ switch (phydev->speed) {
+ case SPEED_1000:
+ tempval = ((tempval &
+ ~(MACCFG2_INTERFACE_MODE_MASK)) |
+ MACCFG2_INTERFACE_MODE_BYTE);
break;
- case 100:
- ugeth->ug_info->enet_interface = ENET_100_RGMII;
- break;
- case 10:
- ugeth->ug_info->enet_interface = ENET_10_RGMII;
+ case SPEED_100:
+ case SPEED_10:
+ tempval = ((tempval &
+ ~(MACCFG2_INTERFACE_MODE_MASK)) |
+ MACCFG2_INTERFACE_MODE_NIBBLE);
+ /* if reduced mode, re-set UPSMR.R10M */
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
+ if (phydev->speed == SPEED_10)
+ upsmr |= UPSMR_R10M;
+ else
+ upsmr &= ~(UPSMR_R10M);
+ }
break;
default:
- ugeth_warn
- ("%s: Ack! Speed (%d) is not 10/100/1000!",
- dev->name, mii_info->speed);
+ if (netif_msg_link(ugeth))
+ ugeth_warn(
+ "%s: Ack! Speed (%d) is not 10/100/1000!",
+ dev->name, phydev->speed);
break;
}
- adjust_enet_interface(ugeth);
-
- ugeth_info("%s: Speed %dBT", dev->name,
- mii_info->speed);
-
- ugeth->oldspeed = mii_info->speed;
+ ugeth->oldspeed = phydev->speed;
}
+ out_be32(&ug_regs->maccfg2, tempval);
+ out_be32(&uf_regs->upsmr, upsmr);
+
if (!ugeth->oldlink) {
- ugeth_info("%s: Link is up", dev->name);
+ new_state = 1;
ugeth->oldlink = 1;
- netif_carrier_on(dev);
netif_schedule(dev);
}
- } else {
- if (ugeth->oldlink) {
- ugeth_info("%s: Link is down", dev->name);
+ } else if (ugeth->oldlink) {
+ new_state = 1;
ugeth->oldlink = 0;
ugeth->oldspeed = 0;
ugeth->oldduplex = -1;
- netif_carrier_off(dev);
- }
}
+
+ if (new_state && netif_msg_link(ugeth))
+ phy_print_status(phydev);
+
+ spin_unlock_irqrestore(&ugeth->lock, flags);
}
/* Configure the PHY for dev.
@@ -1753,102 +1593,40 @@ static void adjust_link(struct net_device *dev)
*/
static int init_phy(struct net_device *dev)
{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
- struct phy_info *curphy;
- struct ucc_mii_mng *mii_regs;
- struct ugeth_mii_info *mii_info;
- int err;
+ struct ucc_geth_private *priv = netdev_priv(dev);
+ struct phy_device *phydev;
+ char phy_id[BUS_ID_SIZE];
- mii_regs = &ugeth->ug_regs->miimng;
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
- ugeth->oldlink = 0;
- ugeth->oldspeed = 0;
- ugeth->oldduplex = -1;
+ snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus,
+ priv->ug_info->phy_address);
- mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL);
+ phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface);
- if (NULL == mii_info) {
- ugeth_err("%s: Could not allocate mii_info", dev->name);
- return -ENOMEM;
+ if (IS_ERR(phydev)) {
+ printk("%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
}
- mii_info->mii_regs = mii_regs;
- mii_info->speed = SPEED_1000;
- mii_info->duplex = DUPLEX_FULL;
- mii_info->pause = 0;
- mii_info->link = 0;
-
- mii_info->advertising = (ADVERTISED_10baseT_Half |
+ phydev->supported &= (ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full |
- ADVERTISED_1000baseT_Full);
- mii_info->autoneg = 1;
+ ADVERTISED_100baseT_Full);
- mii_info->mii_id = ugeth->ug_info->phy_address;
+ if (priv->max_speed == SPEED_1000)
+ phydev->supported |= ADVERTISED_1000baseT_Full;
- mii_info->dev = dev;
+ phydev->advertising = phydev->supported;
- mii_info->mdio_read = &read_phy_reg;
- mii_info->mdio_write = &write_phy_reg;
-
- spin_lock_init(&mii_info->mdio_lock);
-
- ugeth->mii_info = mii_info;
-
- spin_lock_irq(&ugeth->lock);
-
- /* Set this UCC to be the master of the MII managment */
- ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
-
- if (init_mii_management_configuration(1,
- ugeth->ug_info->
- miiPreambleSupress,
- &mii_regs->miimcfg,
- &mii_regs->miimind)) {
- ugeth_err("%s: The MII Bus is stuck!", dev->name);
- err = -1;
- goto bus_fail;
- }
-
- spin_unlock_irq(&ugeth->lock);
-
- /* get info for this PHY */
- curphy = get_phy_info(ugeth->mii_info);
-
- if (curphy == NULL) {
- ugeth_err("%s: No PHY found", dev->name);
- err = -1;
- goto no_phy;
- }
-
- mii_info->phyinfo = curphy;
-
- /* Run the commands which initialize the PHY */
- if (curphy->init) {
- err = curphy->init(ugeth->mii_info);
- if (err)
- goto phy_init_fail;
- }
+ priv->phydev = phydev;
return 0;
-
- phy_init_fail:
- no_phy:
- bus_fail:
- kfree(mii_info);
-
- return err;
}
-#ifdef CONFIG_UGETH_TX_ON_DEMOND
-static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth)
-{
- struct ucc_fastransmit_on_demand(ugeth->uccf);
- return 0;
-}
-#endif
static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
{
@@ -2356,6 +2134,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
}
for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
bd = ugeth->p_tx_bd_ring[i];
+ if (!bd)
+ continue;
for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
if (ugeth->tx_skbuff[i][j]) {
dma_unmap_single(NULL,
@@ -2487,6 +2267,7 @@ static void ucc_geth_set_multi(struct net_device *dev)
static void ucc_geth_stop(struct ucc_geth_private *ugeth)
{
struct ucc_geth *ug_regs = ugeth->ug_regs;
+ struct phy_device *phydev = ugeth->phydev;
u32 tempval;
ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -2495,8 +2276,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
/* Tell the kernel the link is down */
- ugeth->mii_info->link = 0;
- adjust_link(ugeth->dev);
+ phy_stop(phydev);
/* Mask all interrupts */
out_be32(ugeth->uccf->p_ucce, 0x00000000);
@@ -2509,50 +2289,24 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
out_be32(&ug_regs->maccfg1, tempval);
- if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
- /* Clear any pending interrupts */
- mii_clear_phy_interrupt(ugeth->mii_info);
-
- /* Disable PHY Interrupts */
- mii_configure_phy_interrupt(ugeth->mii_info,
- MII_INTERRUPT_DISABLED);
- }
-
free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
- if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
- free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev);
- } else {
- del_timer_sync(&ugeth->phy_info_timer);
- }
-
ucc_geth_memclean(ugeth);
}
-static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+static int ucc_struct_init(struct ucc_geth_private *ugeth)
{
- struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
- struct ucc_geth_init_pram *p_init_enet_pram;
- struct ucc_fast_private *uccf;
struct ucc_geth_info *ug_info;
struct ucc_fast_info *uf_info;
- struct ucc_fast *uf_regs;
- struct ucc_geth *ug_regs;
- int ret_val = -EINVAL;
- u32 remoder = UCC_GETH_REMODER_INIT;
- u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
- u32 ifstat, i, j, size, l2qt, l3qt, length;
- u16 temoder = UCC_GETH_TEMODER_INIT;
- u16 test;
- u8 function_code = 0;
- u8 *bd, *endOfRing;
- u8 numThreadsRxNumerical, numThreadsTxNumerical;
-
- ugeth_vdbg("%s: IN", __FUNCTION__);
+ int i;
ug_info = ugeth->ug_info;
uf_info = &ug_info->uf_info;
+ /* Create CQs for hash tables */
+ INIT_LIST_HEAD(&ugeth->group_hash_q);
+ INIT_LIST_HEAD(&ugeth->ind_hash_q);
+
if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) ||
(uf_info->bd_mem_part == MEM_PART_MURAM))) {
ugeth_err("%s: Bad memory partition value.", __FUNCTION__);
@@ -2647,12 +2401,42 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
for (i = 0; i < ug_info->numQueuesTx; i++)
uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i);
/* Initialize the general fast UCC block. */
- if (ucc_fast_init(uf_info, &uccf)) {
+ if (ucc_fast_init(uf_info, &ugeth->uccf)) {
ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
- ugeth->uccf = uccf;
+
+ ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth));
+
+ return 0;
+}
+
+static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+{
+ struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+ struct ucc_geth_init_pram *p_init_enet_pram;
+ struct ucc_fast_private *uccf;
+ struct ucc_geth_info *ug_info;
+ struct ucc_fast_info *uf_info;
+ struct ucc_fast *uf_regs;
+ struct ucc_geth *ug_regs;
+ int ret_val = -EINVAL;
+ u32 remoder = UCC_GETH_REMODER_INIT;
+ u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
+ u32 ifstat, i, j, size, l2qt, l3qt, length;
+ u16 temoder = UCC_GETH_TEMODER_INIT;
+ u16 test;
+ u8 function_code = 0;
+ u8 *bd, *endOfRing;
+ u8 numThreadsRxNumerical, numThreadsTxNumerical;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+ uccf = ugeth->uccf;
+ ug_info = ugeth->ug_info;
+ uf_info = &ug_info->uf_info;
+ uf_regs = uccf->uf_regs;
+ ug_regs = ugeth->ug_regs;
switch (ug_info->numThreadsRx) {
case UCC_GETH_NUM_OF_THREADS_1:
@@ -2711,10 +2495,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
|| (ug_info->vlanOperationNonTagged !=
UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP);
- uf_regs = uccf->uf_regs;
- ug_regs = (struct ucc_geth *) (uccf->uf_regs);
- ugeth->ug_regs = ug_regs;
-
init_default_reg_vals(&uf_regs->upsmr,
&ug_regs->maccfg1, &ug_regs->maccfg2);
@@ -3177,8 +2957,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Size varies with number of Rx queues */
ugeth->rx_irq_coalescing_tbl_offset =
qe_muram_alloc(ug_info->numQueuesRx *
- sizeof(struct ucc_geth_rx_interrupt_coalescing_entry),
- UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
+ sizeof(struct ucc_geth_rx_interrupt_coalescing_entry)
+ + 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for"
@@ -3359,13 +3139,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
for (j = 0; j < NUM_OF_PADDRS; j++)
ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j);
- /* Create CQs for hash tables */
- if (ug_info->maxGroupAddrInHash > 0) {
- INIT_LIST_HEAD(&ugeth->group_hash_q);
- }
- if (ug_info->maxIndAddrInHash > 0) {
- INIT_LIST_HEAD(&ugeth->ind_hash_q);
- }
p_82xx_addr_filt =
(struct ucc_geth_82xx_address_filtering_pram *) ugeth->
p_rx_glbl_pram->addressfiltering;
@@ -3562,6 +3335,9 @@ static void ucc_geth_timeout(struct net_device *dev)
static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ucc_geth_private *ugeth = netdev_priv(dev);
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+ struct ucc_fast_private *uccf;
+#endif
u8 *bd; /* BD pointer */
u32 bd_status;
u8 txQ = 0;
@@ -3620,6 +3396,10 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]);
}
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+ uccf = ugeth->uccf;
+ out_be16(uccf->p_utodr, UCC_FAST_TOD);
+#endif
spin_unlock_irq(&ugeth->lock);
return 0;
@@ -3635,7 +3415,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
ugeth_vdbg("%s: IN", __FUNCTION__);
- spin_lock(&ugeth->lock);
/* collect received buffers */
bd = ugeth->rxBd[rxQ];
@@ -3683,7 +3462,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
skb = get_new_skb(ugeth, bd);
if (!skb) {
ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
- spin_unlock(&ugeth->lock);
ugeth->stats.rx_dropped++;
break;
}
@@ -3704,7 +3482,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
}
ugeth->rxBd[rxQ] = bd;
- spin_unlock(&ugeth->lock);
return howmany;
}
@@ -3756,23 +3533,38 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
static int ucc_geth_poll(struct net_device *dev, int *budget)
{
struct ucc_geth_private *ugeth = netdev_priv(dev);
+ struct ucc_geth_info *ug_info;
+ struct ucc_fast_private *uccf;
int howmany;
- int rx_work_limit = *budget;
- u8 rxQ = 0;
+ u8 i;
+ int rx_work_limit;
+ register u32 uccm;
+
+ ug_info = ugeth->ug_info;
+ rx_work_limit = *budget;
if (rx_work_limit > dev->quota)
rx_work_limit = dev->quota;
- howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit);
+ howmany = 0;
+
+ for (i = 0; i < ug_info->numQueuesRx; i++) {
+ howmany += ucc_geth_rx(ugeth, i, rx_work_limit);
+ }
dev->quota -= howmany;
rx_work_limit -= howmany;
*budget -= howmany;
- if (rx_work_limit >= 0)
+ if (rx_work_limit > 0) {
netif_rx_complete(dev);
+ uccf = ugeth->uccf;
+ uccm = in_be32(uccf->p_uccm);
+ uccm |= UCCE_RX_EVENTS;
+ out_be32(uccf->p_uccm, uccm);
+ }
- return (rx_work_limit < 0) ? 1 : 0;
+ return (rx_work_limit > 0) ? 0 : 1;
}
#endif /* CONFIG_UGETH_NAPI */
@@ -3782,10 +3574,13 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
struct ucc_geth_private *ugeth = netdev_priv(dev);
struct ucc_fast_private *uccf;
struct ucc_geth_info *ug_info;
- register u32 ucce = 0;
- register u32 bit_mask = UCCE_RXBF_SINGLE_MASK;
- register u32 tx_mask = UCCE_TXBF_SINGLE_MASK;
- register u8 i;
+ register u32 ucce;
+ register u32 uccm;
+#ifndef CONFIG_UGETH_NAPI
+ register u32 rx_mask;
+#endif
+ register u32 tx_mask;
+ u8 i;
ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -3795,174 +3590,57 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
uccf = ugeth->uccf;
ug_info = ugeth->ug_info;
- do {
- ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm));
-
- /* clear event bits for next time */
- /* Side effect here is to mask ucce variable
- for future processing below. */
- out_be32(uccf->p_ucce, ucce); /* Clear with ones,
- but only bits in UCCM */
-
- /* We ignore Tx interrupts because Tx confirmation is
- done inside Tx routine */
+ /* read and clear events */
+ ucce = (u32) in_be32(uccf->p_ucce);
+ uccm = (u32) in_be32(uccf->p_uccm);
+ ucce &= uccm;
+ out_be32(uccf->p_ucce, ucce);
+ /* check for receive events that require processing */
+ if (ucce & UCCE_RX_EVENTS) {
+#ifdef CONFIG_UGETH_NAPI
+ if (netif_rx_schedule_prep(dev)) {
+ uccm &= ~UCCE_RX_EVENTS;
+ out_be32(uccf->p_uccm, uccm);
+ __netif_rx_schedule(dev);
+ }
+#else
+ rx_mask = UCCE_RXBF_SINGLE_MASK;
for (i = 0; i < ug_info->numQueuesRx; i++) {
- if (ucce & bit_mask)
- ucc_geth_rx(ugeth, i,
- (int)ugeth->ug_info->
- bdRingLenRx[i]);
- ucce &= ~bit_mask;
- bit_mask <<= 1;
+ if (ucce & rx_mask)
+ ucc_geth_rx(ugeth, i, (int)ugeth->ug_info->bdRingLenRx[i]);
+ ucce &= ~rx_mask;
+ rx_mask <<= 1;
}
+#endif /* CONFIG_UGETH_NAPI */
+ }
+ /* Tx event processing */
+ if (ucce & UCCE_TX_EVENTS) {
+ spin_lock(&ugeth->lock);
+ tx_mask = UCCE_TXBF_SINGLE_MASK;
for (i = 0; i < ug_info->numQueuesTx; i++) {
if (ucce & tx_mask)
ucc_geth_tx(dev, i);
ucce &= ~tx_mask;
tx_mask <<= 1;
}
+ spin_unlock(&ugeth->lock);
+ }
- /* Exceptions */
+ /* Errors and other events */
+ if (ucce & UCCE_OTHER) {
if (ucce & UCCE_BSY) {
- ugeth_vdbg("Got BUSY irq!!!!");
ugeth->stats.rx_errors++;
- ucce &= ~UCCE_BSY;
}
- if (ucce & UCCE_OTHER) {
- ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!",
- ucce);
- ugeth->stats.rx_errors++;
- ucce &= ~ucce;
+ if (ucce & UCCE_TXE) {
+ ugeth->stats.tx_errors++;
}
}
- while (ucce);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t phy_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct ucc_geth_private *ugeth = netdev_priv(dev);
-
- ugeth_vdbg("%s: IN", __FUNCTION__);
-
- /* Clear the interrupt */
- mii_clear_phy_interrupt(ugeth->mii_info);
-
- /* Disable PHY interrupts */
- mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED);
-
- /* Schedule the phy change */
- schedule_work(&ugeth->tq);
return IRQ_HANDLED;
}
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
-static void ugeth_phy_change(struct work_struct *work)
-{
- struct ucc_geth_private *ugeth =
- container_of(work, struct ucc_geth_private, tq);
- struct net_device *dev = ugeth->dev;
- struct ucc_geth *ug_regs;
- int result = 0;
-
- ugeth_vdbg("%s: IN", __FUNCTION__);
-
- ug_regs = ugeth->ug_regs;
-
- /* Delay to give the PHY a chance to change the
- * register state */
- msleep(1);
-
- /* Update the link, speed, duplex */
- result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info);
-
- /* Adjust the known status as long as the link
- * isn't still coming up */
- if ((0 == result) || (ugeth->mii_info->link == 0))
- adjust_link(dev);
-
- /* Reenable interrupts, if needed */
- if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR)
- mii_configure_phy_interrupt(ugeth->mii_info,
- MII_INTERRUPT_ENABLED);
-}
-
-/* Called every so often on systems that don't interrupt
- * the core for PHY changes */
-static void ugeth_phy_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct ucc_geth_private *ugeth = netdev_priv(dev);
-
- schedule_work(&ugeth->tq);
-
- mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
-/* Keep trying aneg for some time
- * If, after GFAR_AN_TIMEOUT seconds, it has not
- * finished, we switch to forced.
- * Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to
- * using ugeth_phy_timer to check status */
-static void ugeth_phy_startup_timer(unsigned long data)
-{
- struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
- struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev);
- static int secondary = UGETH_AN_TIMEOUT;
- int result;
-
- /* Configure the Auto-negotiation */
- result = mii_info->phyinfo->config_aneg(mii_info);
-
- /* If autonegotiation failed to start, and
- * we haven't timed out, reset the timer, and return */
- if (result && secondary--) {
- mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
- return;
- } else if (result) {
- /* Couldn't start autonegotiation.
- * Try switching to forced */
- mii_info->autoneg = 0;
- result = mii_info->phyinfo->config_aneg(mii_info);
-
- /* Forcing failed! Give up */
- if (result) {
- ugeth_err("%s: Forcing failed!", mii_info->dev->name);
- return;
- }
- }
-
- /* Kill the timer so it can be restarted */
- del_timer_sync(&ugeth->phy_info_timer);
-
- /* Grab the PHY interrupt, if necessary/possible */
- if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
- if (request_irq(ugeth->ug_info->phy_interrupt,
- phy_interrupt, IRQF_SHARED,
- "phy_interrupt", mii_info->dev) < 0) {
- ugeth_err("%s: Can't get IRQ %d (PHY)",
- mii_info->dev->name,
- ugeth->ug_info->phy_interrupt);
- } else {
- mii_configure_phy_interrupt(ugeth->mii_info,
- MII_INTERRUPT_ENABLED);
- return;
- }
- }
-
- /* Start the timer again, this time in order to
- * handle a change in status */
- init_timer(&ugeth->phy_info_timer);
- ugeth->phy_info_timer.function = &ugeth_phy_timer;
- ugeth->phy_info_timer.data = (unsigned long)mii_info->dev;
- mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
/* Called when something needs to use the ethernet device */
/* Returns 0 for success. */
static int ucc_geth_open(struct net_device *dev)
@@ -3979,6 +3657,12 @@ static int ucc_geth_open(struct net_device *dev)
return -EINVAL;
}
+ err = ucc_struct_init(ugeth);
+ if (err) {
+ ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
+ return err;
+ }
+
err = ucc_geth_startup(ugeth);
if (err) {
ugeth_err("%s: Cannot configure net device, aborting.",
@@ -4006,10 +3690,12 @@ static int ucc_geth_open(struct net_device *dev)
err = init_phy(dev);
if (err) {
- ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name);
+ ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
return err;
}
-#ifndef CONFIG_UGETH_NAPI
+
+ phy_start(ugeth->phydev);
+
err =
request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
"UCC Geth", dev);
@@ -4019,15 +3705,6 @@ static int ucc_geth_open(struct net_device *dev)
ucc_geth_stop(ugeth);
return err;
}
-#endif /* CONFIG_UGETH_NAPI */
-
- /* Set up the PHY change work queue */
- INIT_WORK(&ugeth->tq, ugeth_phy_change);
-
- init_timer(&ugeth->phy_info_timer);
- ugeth->phy_info_timer.function = &ugeth_phy_startup_timer;
- ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info;
- mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
if (err) {
@@ -4050,11 +3727,8 @@ static int ucc_geth_close(struct net_device *dev)
ucc_geth_stop(ugeth);
- /* Shutdown the PHY */
- if (ugeth->mii_info->phyinfo->close)
- ugeth->mii_info->phyinfo->close(ugeth->mii_info);
-
- kfree(ugeth->mii_info);
+ phy_disconnect(ugeth->phydev);
+ ugeth->phydev = NULL;
netif_stop_queue(dev);
@@ -4063,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");
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index a66561253593..a29e1c3ca4b7 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -28,6 +28,8 @@
#include <asm/ucc.h>
#include <asm/ucc_fast.h>
+#include "ucc_geth_mii.h"
+
#define NUM_TX_QUEUES 8
#define NUM_RX_QUEUES 8
#define NUM_BDS_IN_PREFETCHED_BDS 4
@@ -36,15 +38,6 @@
#define ENET_INIT_PARAM_MAX_ENTRIES_RX 9
#define ENET_INIT_PARAM_MAX_ENTRIES_TX 8
-struct ucc_mii_mng {
- u32 miimcfg; /* MII management configuration reg */
- u32 miimcom; /* MII management command reg */
- u32 miimadd; /* MII management address reg */
- u32 miimcon; /* MII management control reg */
- u32 miimstat; /* MII management status reg */
- u32 miimind; /* MII management indication reg */
-} __attribute__ ((packed));
-
struct ucc_geth {
struct ucc_fast uccf;
@@ -53,7 +46,7 @@ struct ucc_geth {
u32 ipgifg; /* interframe gap reg. */
u32 hafdup; /* half-duplex reg. */
u8 res1[0x10];
- struct ucc_mii_mng miimng; /* MII management structure */
+ u8 miimng[0x18]; /* MII management structure moved to _mii.h */
u32 ifctl; /* interface control reg */
u32 ifstat; /* interface statux reg */
u32 macstnaddr1; /* mac station address part 1 reg */
@@ -212,6 +205,9 @@ struct ucc_geth {
#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\
UCCE_RXC | UCCE_TXC | UCCE_TXE)
+#define UCCE_RX_EVENTS (UCCE_RXF | UCCE_BSY)
+#define UCCE_TX_EVENTS (UCCE_TXB | UCCE_TXE)
+
/* UCC GETH UPSMR (Protocol Specific Mode Register) */
#define UPSMR_ECM 0x04000000 /* Enable CAM
Miss or
@@ -381,66 +377,6 @@ struct ucc_geth {
#define UCCS_MPD 0x01 /* Magic Packet
Detected */
-/* UCC GETH MIIMCFG (MII Management Configuration Register) */
-#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset
- management */
-#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble
- suppress */
-#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide
- << shift */
-#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* clock divide max val
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 /* divide by 2 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 /* divide by 4 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 /* divide by 6 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 /* divide by 8 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 /* divide by 10
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 /* divide by 14
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 /* divide by 16
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 /* divide by 20
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 /* divide by 28
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 /* divide by 32
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a /* divide by 48
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b /* divide by 64
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c /* divide by 80
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d /* divide by
- 112 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e /* divide by
- 160 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f /* divide by
- 224 */
-
-/* UCC GETH MIIMCOM (MII Management Command Register) */
-#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */
-#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */
-
-/* UCC GETH MIIMADD (MII Management Address Register) */
-#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address
- << shift */
-#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register
- << shift */
-
-/* UCC GETH MIIMCON (MII Management Control Register) */
-#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control
- << shift */
-#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status
- << shift */
-
-/* UCC GETH MIIMIND (MII Management Indicator Register) */
-#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */
-#define MIIMIND_SCAN 0x00000002 /* Scan in
- progress */
-#define MIIMIND_BUSY 0x00000001
-
/* UCC GETH IFSTAT (Interface Status Register) */
#define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive
transmission
@@ -931,8 +867,7 @@ struct ucc_geth_hardware_statistics {
#define UCC_GETH_SCHEDULER_ALIGNMENT 4 /* This is a guess */
#define UCC_GETH_TX_STATISTICS_ALIGNMENT 4 /* This is a guess */
#define UCC_GETH_RX_STATISTICS_ALIGNMENT 4 /* This is a guess */
-#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 4 /* This is a
- guess */
+#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 64
#define UCC_GETH_RX_BD_QUEUES_ALIGNMENT 8 /* This is a guess */
#define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT 128 /* This is a guess */
#define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4 /* This
@@ -1009,15 +944,6 @@ struct ucc_geth_hardware_statistics {
register */
#define UCC_GETH_MACCFG1_INIT 0
#define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1)
-#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT \
- (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112)
-
-/* Ethernet speed */
-enum enet_speed {
- ENET_SPEED_10BT, /* 10 Base T */
- ENET_SPEED_100BT, /* 100 Base T */
- ENET_SPEED_1000BT /* 1000 Base T */
-};
/* Ethernet Address Type. */
enum enet_addr_type {
@@ -1026,22 +952,6 @@ enum enet_addr_type {
ENET_ADDR_TYPE_BROADCAST
};
-/* TBI / MII Set Register */
-enum enet_tbi_mii_reg {
- ENET_TBI_MII_CR = 0x00, /* Control (CR ) */
- ENET_TBI_MII_SR = 0x01, /* Status (SR ) */
- ENET_TBI_MII_ANA = 0x04, /* AN advertisement (ANA ) */
- ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability
- (ANLPBPA) */
- ENET_TBI_MII_ANEX = 0x06, /* AN expansion (ANEX ) */
- ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit (ANNPT ) */
- ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page
- (ANLPANP) */
- ENET_TBI_MII_EXST = 0x0F, /* Extended status (EXST ) */
- ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */
- ENET_TBI_MII_TBICON = 0x11 /* TBI control (TBICON ) */
-};
-
/* UCC GETH 82xx Ethernet Address Recognition Location */
enum ucc_geth_enet_address_recognition_location {
UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station
@@ -1239,8 +1149,7 @@ struct ucc_geth_info {
u16 pausePeriod;
u16 extensionField;
u8 phy_address;
- u32 board_flags;
- u32 phy_interrupt;
+ u32 mdio_bus;
u8 weightfactor[NUM_TX_QUEUES];
u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];
@@ -1249,7 +1158,6 @@ struct ucc_geth_info {
u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX];
u16 bdRingLenTx[NUM_TX_QUEUES];
u16 bdRingLenRx[NUM_RX_QUEUES];
- enum enet_interface enet_interface;
enum ucc_geth_num_of_station_addresses numStationAddresses;
enum qe_fltr_largest_external_tbl_lookup_key_size
largestexternallookupkeysize;
@@ -1326,9 +1234,11 @@ struct ucc_geth_private {
/* index of the first skb which hasn't been transmitted yet. */
u16 skb_dirtytx[NUM_TX_QUEUES];
- struct work_struct tq;
- struct timer_list phy_info_timer;
struct ugeth_mii_info *mii_info;
+ struct phy_device *phydev;
+ phy_interface_t phy_interface;
+ int max_speed;
+ uint32_t msg_enable;
int oldspeed;
int oldduplex;
int oldlink;
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
new file mode 100644
index 000000000000..73b5a538e8f4
--- /dev/null
+++ b/drivers/net/ucc_geth_mii.c
@@ -0,0 +1,279 @@
+/*
+ * drivers/net/ucc_geth_mii.c
+ *
+ * Gianfar Ethernet Driver -- MIIM bus implementation
+ * Provides Bus interface for MIIM regs
+ *
+ * Author: Li Yang
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <asm/ocp.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/of_platform.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/ucc.h>
+
+#include "ucc_geth_mii.h"
+#include "ucc_geth.h"
+
+#define DEBUG
+#ifdef DEBUG
+#define vdbg(format, arg...) printk(KERN_DEBUG , format "\n" , ## arg)
+#else
+#define vdbg(format, arg...) do {} while(0)
+#endif
+
+#define DRV_DESC "QE UCC Ethernet Controller MII Bus"
+#define DRV_NAME "fsl-uec_mdio"
+
+/* Write value to the PHY for this device to the register at regnum, */
+/* waiting until the write is done before it returns. All PHY */
+/* configuration has to be done through the master UEC MIIM regs */
+int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+{
+ struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+
+ /* Setting up the MII Mangement Address Register */
+ out_be32(&regs->miimadd,
+ (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum);
+
+ /* Setting up the MII Mangement Control Register with the value */
+ out_be32(&regs->miimcon, value);
+
+ /* Wait till MII management write is complete */
+ while ((in_be32(&regs->miimind)) & MIIMIND_BUSY)
+ cpu_relax();
+
+ return 0;
+}
+
+/* Reads from register regnum in the PHY for device dev, */
+/* returning the value. Clears miimcom first. All PHY */
+/* configuration has to be done through the TSEC1 MIIM regs */
+int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+ u16 value;
+
+ /* Setting up the MII Mangement Address Register */
+ out_be32(&regs->miimadd,
+ (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum);
+
+ /* Clear miimcom, perform an MII management read cycle */
+ out_be32(&regs->miimcom, 0);
+ out_be32(&regs->miimcom, MIIMCOM_READ_CYCLE);
+
+ /* Wait till MII management write is complete */
+ while ((in_be32(&regs->miimind)) & (MIIMIND_BUSY | MIIMIND_NOT_VALID))
+ cpu_relax();
+
+ /* Read MII management status */
+ value = in_be32(&regs->miimstat);
+
+ return value;
+}
+
+/* Reset the MIIM registers, and wait for the bus to free */
+int uec_mdio_reset(struct mii_bus *bus)
+{
+ struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+ unsigned int timeout = PHY_INIT_TIMEOUT;
+
+ spin_lock_bh(&bus->mdio_lock);
+
+ /* Reset the management interface */
+ out_be32(&regs->miimcfg, MIIMCFG_RESET_MANAGEMENT);
+
+ /* Setup the MII Mgmt clock speed */
+ out_be32(&regs->miimcfg, MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112);
+
+ /* Wait until the bus is free */
+ while ((in_be32(&regs->miimind) & MIIMIND_BUSY) && timeout--)
+ cpu_relax();
+
+ spin_unlock_bh(&bus->mdio_lock);
+
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *match)
+{
+ struct device *device = &ofdev->dev;
+ struct device_node *np = ofdev->node, *tempnp = NULL;
+ struct device_node *child = NULL;
+ struct ucc_mii_mng __iomem *regs;
+ struct mii_bus *new_bus;
+ struct resource res;
+ int k, err = 0;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+ if (NULL == new_bus)
+ return -ENOMEM;
+
+ new_bus->name = "UCC Ethernet Controller MII Bus";
+ new_bus->read = &uec_mdio_read;
+ new_bus->write = &uec_mdio_write;
+ new_bus->reset = &uec_mdio_reset;
+
+ memset(&res, 0, sizeof(res));
+
+ err = of_address_to_resource(np, 0, &res);
+ if (err)
+ goto reg_map_fail;
+
+ new_bus->id = res.start;
+
+ new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL);
+
+ if (NULL == new_bus->irq) {
+ err = -ENOMEM;
+ goto reg_map_fail;
+ }
+
+ for (k = 0; k < 32; k++)
+ new_bus->irq[k] = PHY_POLL;
+
+ while ((child = of_get_next_child(np, child)) != NULL) {
+ int irq = irq_of_parse_and_map(child, 0);
+ if (irq != NO_IRQ) {
+ const u32 *id = 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
index 000000000000..98430fe0bfc6
--- /dev/null
+++ b/drivers/net/ucc_geth_mii.h
@@ -0,0 +1,100 @@
+/*
+ * drivers/net/ucc_geth_mii.h
+ *
+ * Gianfar Ethernet Driver -- MII Management Bus Implementation
+ * Driver for the MDIO bus controller in the Gianfar register space
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __UEC_MII_H
+#define __UEC_MII_H
+
+/* UCC GETH MIIMCFG (MII Management Configuration Register) */
+#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset
+ management */
+#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble
+ suppress */
+#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide
+ << shift */
+#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* max clock divide */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f
+
+/* UCC GETH MIIMCOM (MII Management Command Register) */
+#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */
+#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */
+
+/* UCC GETH MIIMADD (MII Management Address Register) */
+#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address
+ << shift */
+#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register
+ << shift */
+
+/* UCC GETH MIIMCON (MII Management Control Register) */
+#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control
+ << shift */
+#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status
+ << shift */
+
+/* UCC GETH MIIMIND (MII Management Indicator Register) */
+#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */
+#define MIIMIND_SCAN 0x00000002 /* Scan in
+ progress */
+#define MIIMIND_BUSY 0x00000001
+
+/* Initial TBI Physical Address */
+#define UTBIPAR_INIT_TBIPA 0x1f
+
+struct ucc_mii_mng {
+ u32 miimcfg; /* MII management configuration reg */
+ u32 miimcom; /* MII management command reg */
+ u32 miimadd; /* MII management address reg */
+ u32 miimcon; /* MII management control reg */
+ u32 miimstat; /* MII management status reg */
+ u32 miimind; /* MII management indication reg */
+ u8 notcare[28]; /* Space holder */
+ u32 utbipar; /* TBI phy address reg */
+} __attribute__ ((packed));
+
+/* TBI / MII Set Register */
+enum enet_tbi_mii_reg {
+ ENET_TBI_MII_CR = 0x00, /* Control */
+ ENET_TBI_MII_SR = 0x01, /* Status */
+ ENET_TBI_MII_ANA = 0x04, /* AN advertisement */
+ ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability */
+ ENET_TBI_MII_ANEX = 0x06, /* AN expansion */
+ ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit */
+ ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page */
+ ENET_TBI_MII_EXST = 0x0F, /* Extended status */
+ ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics */
+ ENET_TBI_MII_TBICON = 0x11 /* TBI control */
+};
+
+int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
+int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int __init uec_mdio_init(void);
+void __exit uec_mdio_exit(void);
+#endif /* __UEC_MII_H */
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
deleted file mode 100644
index 9373d895b9ec..000000000000
--- a/drivers/net/ucc_geth_phy.c
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Author: Shlomi Gridish <gridish@freescale.com>
- *
- * Description:
- * UCC GETH Driver -- PHY handling
- *
- * Changelog:
- * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
- * - Rearrange code and style fixes
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "ucc_geth.h"
-#include "ucc_geth_phy.h"
-
-#define ugphy_printk(level, format, arg...) \
- printk(level format "\n", ## arg)
-
-#define ugphy_dbg(format, arg...) \
- ugphy_printk(KERN_DEBUG, format , ## arg)
-#define ugphy_err(format, arg...) \
- ugphy_printk(KERN_ERR, format , ## arg)
-#define ugphy_info(format, arg...) \
- ugphy_printk(KERN_INFO, format , ## arg)
-#define ugphy_warn(format, arg...) \
- ugphy_printk(KERN_WARNING, format , ## arg)
-
-#ifdef UGETH_VERBOSE_DEBUG
-#define ugphy_vdbg ugphy_dbg
-#else
-#define ugphy_vdbg(fmt, args...) do { } while (0)
-#endif /* UGETH_VERBOSE_DEBUG */
-
-static void config_genmii_advert(struct ugeth_mii_info *mii_info);
-static void genmii_setup_forced(struct ugeth_mii_info *mii_info);
-static void genmii_restart_aneg(struct ugeth_mii_info *mii_info);
-static int gbit_config_aneg(struct ugeth_mii_info *mii_info);
-static int genmii_config_aneg(struct ugeth_mii_info *mii_info);
-static int genmii_update_link(struct ugeth_mii_info *mii_info);
-static int genmii_read_status(struct ugeth_mii_info *mii_info);
-
-static u16 ucc_geth_phy_read(struct ugeth_mii_info *mii_info, u16 regnum)
-{
- u16 retval;
- unsigned long flags;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- spin_lock_irqsave(&mii_info->mdio_lock, flags);
- retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
- spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-
- return retval;
-}
-
-static void ucc_geth_phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val)
-{
- unsigned long flags;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- spin_lock_irqsave(&mii_info->mdio_lock, flags);
- mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val);
- spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-}
-
-/* Write value to the PHY for this device to the register at regnum, */
-/* waiting until the write is done before it returns. All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value)
-{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
- struct ucc_mii_mng *mii_regs;
- enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum;
- u32 tmp_reg;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- spin_lock_irq(&ugeth->lock);
-
- mii_regs = ugeth->mii_info->mii_regs;
-
- /* Set this UCC to be the master of the MII managment */
- ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
-
- /* Stop the MII management read cycle */
- out_be32(&mii_regs->miimcom, 0);
- /* Setting up the MII Mangement Address Register */
- tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
- out_be32(&mii_regs->miimadd, tmp_reg);
-
- /* Setting up the MII Mangement Control Register with the value */
- out_be32(&mii_regs->miimcon, (u32) value);
-
- /* Wait till MII management write is complete */
- while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
- cpu_relax();
-
- spin_unlock_irq(&ugeth->lock);
-
- udelay(10000);
-}
-
-/* Reads from register regnum in the PHY for device dev, */
-/* returning the value. Clears miimcom first. All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum)
-{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
- struct ucc_mii_mng *mii_regs;
- enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum;
- u32 tmp_reg;
- u16 value;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- spin_lock_irq(&ugeth->lock);
-
- mii_regs = ugeth->mii_info->mii_regs;
-
- /* Setting up the MII Mangement Address Register */
- tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
- out_be32(&mii_regs->miimadd, tmp_reg);
-
- /* Perform an MII management read cycle */
- out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE);
-
- /* Wait till MII management write is complete */
- while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
- cpu_relax();
-
- udelay(10000);
-
- /* Read MII management status */
- value = (u16) in_be32(&mii_regs->miimstat);
- out_be32(&mii_regs->miimcom, 0);
- if (value == 0xffff)
- ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x",
- mii_id, mii_reg, (u32) & (mii_regs->miimcfg));
-
- spin_unlock_irq(&ugeth->lock);
-
- return (value);
-}
-
-void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->phyinfo->ack_interrupt)
- mii_info->phyinfo->ack_interrupt(mii_info);
-}
-
-void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
- u32 interrupts)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- mii_info->interrupts = interrupts;
- if (mii_info->phyinfo->config_intr)
- mii_info->phyinfo->config_intr(mii_info);
-}
-
-/* Writes MII_ADVERTISE with the appropriate values, after
- * sanitizing advertise to make sure only supported features
- * are advertised
- */
-static void config_genmii_advert(struct ugeth_mii_info *mii_info)
-{
- u32 advertise;
- u16 adv;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Only allow advertising what this PHY supports */
- mii_info->advertising &= mii_info->phyinfo->features;
- advertise = mii_info->advertising;
-
- /* Setup standard advertisement */
- adv = ucc_geth_phy_read(mii_info, MII_ADVERTISE);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
- if (advertise & ADVERTISED_10baseT_Half)
- adv |= ADVERTISE_10HALF;
- if (advertise & ADVERTISED_10baseT_Full)
- adv |= ADVERTISE_10FULL;
- if (advertise & ADVERTISED_100baseT_Half)
- adv |= ADVERTISE_100HALF;
- if (advertise & ADVERTISED_100baseT_Full)
- adv |= ADVERTISE_100FULL;
- ucc_geth_phy_write(mii_info, MII_ADVERTISE, adv);
-}
-
-static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
-{
- u16 ctrl;
- u32 features = mii_info->phyinfo->features;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- ctrl = ucc_geth_phy_read(mii_info, MII_BMCR);
-
- ctrl &=
- ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
- ctrl |= BMCR_RESET;
-
- switch (mii_info->speed) {
- case SPEED_1000:
- if (features & (SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full)) {
- ctrl |= BMCR_SPEED1000;
- break;
- }
- mii_info->speed = SPEED_100;
- case SPEED_100:
- if (features & (SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full)) {
- ctrl |= BMCR_SPEED100;
- break;
- }
- mii_info->speed = SPEED_10;
- case SPEED_10:
- if (features & (SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full))
- break;
- default: /* Unsupported speed! */
- ugphy_err("%s: Bad speed!", mii_info->dev->name);
- break;
- }
-
- ucc_geth_phy_write(mii_info, MII_BMCR, ctrl);
-}
-
-/* Enable and Restart Autonegotiation */
-static void genmii_restart_aneg(struct ugeth_mii_info *mii_info)
-{
- u16 ctl;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- ctl = ucc_geth_phy_read(mii_info, MII_BMCR);
- ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- ucc_geth_phy_write(mii_info, MII_BMCR, ctl);
-}
-
-static int gbit_config_aneg(struct ugeth_mii_info *mii_info)
-{
- u16 adv;
- u32 advertise;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->autoneg) {
- /* Configure the ADVERTISE register */
- config_genmii_advert(mii_info);
- advertise = mii_info->advertising;
-
- adv = ucc_geth_phy_read(mii_info, MII_1000BASETCONTROL);
- adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
- MII_1000BASETCONTROL_HALFDUPLEXCAP);
- if (advertise & SUPPORTED_1000baseT_Half)
- adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
- if (advertise & SUPPORTED_1000baseT_Full)
- adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
- ucc_geth_phy_write(mii_info, MII_1000BASETCONTROL, adv);
-
- /* Start/Restart aneg */
- genmii_restart_aneg(mii_info);
- } else
- genmii_setup_forced(mii_info);
-
- return 0;
-}
-
-static int genmii_config_aneg(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->autoneg) {
- config_genmii_advert(mii_info);
- genmii_restart_aneg(mii_info);
- } else
- genmii_setup_forced(mii_info);
-
- return 0;
-}
-
-static int genmii_update_link(struct ugeth_mii_info *mii_info)
-{
- u16 status;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Do a fake read */
- ucc_geth_phy_read(mii_info, MII_BMSR);
-
- /* Read link and autonegotiation status */
- status = ucc_geth_phy_read(mii_info, MII_BMSR);
- if ((status & BMSR_LSTATUS) == 0)
- mii_info->link = 0;
- else
- mii_info->link = 1;
-
- /* If we are autonegotiating, and not done,
- * return an error */
- if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE))
- return -EAGAIN;
-
- return 0;
-}
-
-static int genmii_read_status(struct ugeth_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- if (mii_info->autoneg) {
- status = ucc_geth_phy_read(mii_info, MII_LPA);
-
- if (status & (LPA_10FULL | LPA_100FULL))
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
- if (status & (LPA_100FULL | LPA_100HALF))
- mii_info->speed = SPEED_100;
- else
- mii_info->speed = SPEED_10;
- mii_info->pause = 0;
- }
- /* On non-aneg, we assume what we put in BMCR is the speed,
- * though magic-aneg shouldn't prevent this case from occurring
- */
-
- return 0;
-}
-
-static int marvell_init(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- ucc_geth_phy_write(mii_info, 0x14, 0x0cd2);
- ucc_geth_phy_write(mii_info, 0x1b,
- (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b);
- ucc_geth_phy_write(mii_info, MII_BMCR,
- ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
- msleep(4000);
-
- return 0;
-}
-
-static int marvell_config_aneg(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* The Marvell PHY has an errata which requires
- * that certain registers get written in order
- * to restart autonegotiation */
- ucc_geth_phy_write(mii_info, MII_BMCR, BMCR_RESET);
-
- ucc_geth_phy_write(mii_info, 0x1d, 0x1f);
- ucc_geth_phy_write(mii_info, 0x1e, 0x200c);
- ucc_geth_phy_write(mii_info, 0x1d, 0x5);
- ucc_geth_phy_write(mii_info, 0x1e, 0);
- ucc_geth_phy_write(mii_info, 0x1e, 0x100);
-
- gbit_config_aneg(mii_info);
-
- return 0;
-}
-
-static int marvell_read_status(struct ugeth_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- int speed;
- status = ucc_geth_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
-
- /* Get the duplexity */
- if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
-
- /* Get the speed */
- speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
- switch (speed) {
- case MII_M1011_PHY_SPEC_STATUS_1000:
- mii_info->speed = SPEED_1000;
- break;
- case MII_M1011_PHY_SPEC_STATUS_100:
- mii_info->speed = SPEED_100;
- break;
- default:
- mii_info->speed = SPEED_10;
- break;
- }
- mii_info->pause = 0;
- }
-
- return 0;
-}
-
-static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Clear the interrupts by reading the reg */
- ucc_geth_phy_read(mii_info, MII_M1011_IEVENT);
-
- return 0;
-}
-
-static int marvell_config_intr(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
- ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
- else
- ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
-
- return 0;
-}
-
-static int cis820x_init(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- ucc_geth_phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
- MII_CIS8201_AUXCONSTAT_INIT);
- ucc_geth_phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT);
-
- return 0;
-}
-
-static int cis820x_read_status(struct ugeth_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- int speed;
-
- status = ucc_geth_phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
- if (status & MII_CIS8201_AUXCONSTAT_DUPLEX)
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
-
- speed = status & MII_CIS8201_AUXCONSTAT_SPEED;
-
- switch (speed) {
- case MII_CIS8201_AUXCONSTAT_GBIT:
- mii_info->speed = SPEED_1000;
- break;
- case MII_CIS8201_AUXCONSTAT_100:
- mii_info->speed = SPEED_100;
- break;
- default:
- mii_info->speed = SPEED_10;
- break;
- }
- }
-
- return 0;
-}
-
-static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- ucc_geth_phy_read(mii_info, MII_CIS8201_ISTAT);
-
- return 0;
-}
-
-static int cis820x_config_intr(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
- ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK);
- else
- ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, 0);
-
- return 0;
-}
-
-#define DM9161_DELAY 10
-
-static int dm9161_read_status(struct ugeth_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- status = ucc_geth_phy_read(mii_info, MII_DM9161_SCSR);
- if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
- mii_info->speed = SPEED_100;
- else
- mii_info->speed = SPEED_10;
-
- if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
- }
-
- return 0;
-}
-
-static int dm9161_config_aneg(struct ugeth_mii_info *mii_info)
-{
- struct dm9161_private *priv = mii_info->priv;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (0 == priv->resetdone)
- return -EAGAIN;
-
- return 0;
-}
-
-static void dm9161_timer(unsigned long data)
-{
- struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
- struct dm9161_private *priv = mii_info->priv;
- u16 status = ucc_geth_phy_read(mii_info, MII_BMSR);
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (status & BMSR_ANEGCOMPLETE) {
- priv->resetdone = 1;
- } else
- mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-}
-
-static int dm9161_init(struct ugeth_mii_info *mii_info)
-{
- struct dm9161_private *priv;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Allocate the private data structure */
- priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL);
-
- if (NULL == priv)
- return -ENOMEM;
-
- mii_info->priv = priv;
-
- /* Reset is not done yet */
- priv->resetdone = 0;
-
- ucc_geth_phy_write(mii_info, MII_BMCR,
- ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
-
- ucc_geth_phy_write(mii_info, MII_BMCR,
- ucc_geth_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE);
-
- config_genmii_advert(mii_info);
- /* Start/Restart aneg */
- genmii_config_aneg(mii_info);
-
- /* Start a timer for DM9161_DELAY seconds to wait
- * for the PHY to be ready */
- init_timer(&priv->timer);
- priv->timer.function = &dm9161_timer;
- priv->timer.data = (unsigned long)mii_info;
- mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-
- return 0;
-}
-
-static void dm9161_close(struct ugeth_mii_info *mii_info)
-{
- struct dm9161_private *priv = mii_info->priv;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- del_timer_sync(&priv->timer);
- kfree(priv);
-}
-
-static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Clear the interrupts by reading the reg */
- ucc_geth_phy_read(mii_info, MII_DM9161_INTR);
-
-
- return 0;
-}
-
-static int dm9161_config_intr(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
- ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
- else
- ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
-
- return 0;
-}
-
-/* Cicada 820x */
-static struct phy_info phy_info_cis820x = {
- .phy_id = 0x000fc440,
- .name = "Cicada Cis8204",
- .phy_id_mask = 0x000fffc0,
- .features = MII_GBIT_FEATURES,
- .init = &cis820x_init,
- .config_aneg = &gbit_config_aneg,
- .read_status = &cis820x_read_status,
- .ack_interrupt = &cis820x_ack_interrupt,
- .config_intr = &cis820x_config_intr,
-};
-
-static struct phy_info phy_info_dm9161 = {
- .phy_id = 0x0181b880,
- .phy_id_mask = 0x0ffffff0,
- .name = "Davicom DM9161E",
- .init = dm9161_init,
- .config_aneg = dm9161_config_aneg,
- .read_status = dm9161_read_status,
- .close = dm9161_close,
-};
-
-static struct phy_info phy_info_dm9161a = {
- .phy_id = 0x0181b8a0,
- .phy_id_mask = 0x0ffffff0,
- .name = "Davicom DM9161A",
- .features = MII_BASIC_FEATURES,
- .init = dm9161_init,
- .config_aneg = dm9161_config_aneg,
- .read_status = dm9161_read_status,
- .ack_interrupt = dm9161_ack_interrupt,
- .config_intr = dm9161_config_intr,
- .close = dm9161_close,
-};
-
-static struct phy_info phy_info_marvell = {
- .phy_id = 0x01410c00,
- .phy_id_mask = 0xffffff00,
- .name = "Marvell 88E11x1",
- .features = MII_GBIT_FEATURES,
- .init = &marvell_init,
- .config_aneg = &marvell_config_aneg,
- .read_status = &marvell_read_status,
- .ack_interrupt = &marvell_ack_interrupt,
- .config_intr = &marvell_config_intr,
-};
-
-static struct phy_info phy_info_genmii = {
- .phy_id = 0x00000000,
- .phy_id_mask = 0x00000000,
- .name = "Generic MII",
- .features = MII_BASIC_FEATURES,
- .config_aneg = genmii_config_aneg,
- .read_status = genmii_read_status,
-};
-
-static struct phy_info *phy_info[] = {
- &phy_info_cis820x,
- &phy_info_marvell,
- &phy_info_dm9161,
- &phy_info_dm9161a,
- &phy_info_genmii,
- NULL
-};
-
-/* Use the PHY ID registers to determine what type of PHY is attached
- * to device dev. return a struct phy_info structure describing that PHY
- */
-struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info)
-{
- u16 phy_reg;
- u32 phy_ID;
- int i;
- struct phy_info *theInfo = NULL;
- struct net_device *dev = mii_info->dev;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Grab the bits from PHYIR1, and put them in the upper half */
- phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID1);
- phy_ID = (phy_reg & 0xffff) << 16;
-
- /* Grab the bits from PHYIR2, and put them in the lower half */
- phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID2);
- phy_ID |= (phy_reg & 0xffff);
-
- /* loop through all the known PHY types, and find one that */
- /* matches the ID we read from the PHY. */
- for (i = 0; phy_info[i]; i++)
- if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){
- theInfo = phy_info[i];
- break;
- }
-
- /* This shouldn't happen, as we have generic PHY support */
- if (theInfo == NULL) {
- ugphy_info("%s: PHY id %x is not supported!", dev->name,
- phy_ID);
- return NULL;
- } else {
- ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name,
- phy_ID);
- }
-
- return theInfo;
-}
diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h
deleted file mode 100644
index f5740783670f..000000000000
--- a/drivers/net/ucc_geth_phy.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Author: Shlomi Gridish <gridish@freescale.com>
- *
- * Description:
- * UCC GETH Driver -- PHY handling
- *
- * Changelog:
- * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
- * - Rearrange code and style fixes
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-#ifndef __UCC_GETH_PHY_H__
-#define __UCC_GETH_PHY_H__
-
-#define MII_end ((u32)-2)
-#define MII_read ((u32)-1)
-
-#define MIIMIND_BUSY 0x00000001
-#define MIIMIND_NOTVALID 0x00000004
-
-#define UGETH_AN_TIMEOUT 2000
-
-/* 1000BT control (Marvell & BCM54xx at least) */
-#define MII_1000BASETCONTROL 0x09
-#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200
-#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100
-
-/* Cicada Extended Control Register 1 */
-#define MII_CIS8201_EXT_CON1 0x17
-#define MII_CIS8201_EXTCON1_INIT 0x0000
-
-/* Cicada Interrupt Mask Register */
-#define MII_CIS8201_IMASK 0x19
-#define MII_CIS8201_IMASK_IEN 0x8000
-#define MII_CIS8201_IMASK_SPEED 0x4000
-#define MII_CIS8201_IMASK_LINK 0x2000
-#define MII_CIS8201_IMASK_DUPLEX 0x1000
-#define MII_CIS8201_IMASK_MASK 0xf000
-
-/* Cicada Interrupt Status Register */
-#define MII_CIS8201_ISTAT 0x1a
-#define MII_CIS8201_ISTAT_STATUS 0x8000
-#define MII_CIS8201_ISTAT_SPEED 0x4000
-#define MII_CIS8201_ISTAT_LINK 0x2000
-#define MII_CIS8201_ISTAT_DUPLEX 0x1000
-
-/* Cicada Auxiliary Control/Status Register */
-#define MII_CIS8201_AUX_CONSTAT 0x1c
-#define MII_CIS8201_AUXCONSTAT_INIT 0x0004
-#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020
-#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018
-#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010
-#define MII_CIS8201_AUXCONSTAT_100 0x0008
-
-/* 88E1011 PHY Status Register */
-#define MII_M1011_PHY_SPEC_STATUS 0x11
-#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000
-#define MII_M1011_PHY_SPEC_STATUS_100 0x4000
-#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000
-#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000
-#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800
-#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400
-
-#define MII_M1011_IEVENT 0x13
-#define MII_M1011_IEVENT_CLEAR 0x0000
-
-#define MII_M1011_IMASK 0x12
-#define MII_M1011_IMASK_INIT 0x6400
-#define MII_M1011_IMASK_CLEAR 0x0000
-
-#define MII_DM9161_SCR 0x10
-#define MII_DM9161_SCR_INIT 0x0610
-
-/* DM9161 Specified Configuration and Status Register */
-#define MII_DM9161_SCSR 0x11
-#define MII_DM9161_SCSR_100F 0x8000
-#define MII_DM9161_SCSR_100H 0x4000
-#define MII_DM9161_SCSR_10F 0x2000
-#define MII_DM9161_SCSR_10H 0x1000
-
-/* DM9161 Interrupt Register */
-#define MII_DM9161_INTR 0x15
-#define MII_DM9161_INTR_PEND 0x8000
-#define MII_DM9161_INTR_DPLX_MASK 0x0800
-#define MII_DM9161_INTR_SPD_MASK 0x0400
-#define MII_DM9161_INTR_LINK_MASK 0x0200
-#define MII_DM9161_INTR_MASK 0x0100
-#define MII_DM9161_INTR_DPLX_CHANGE 0x0010
-#define MII_DM9161_INTR_SPD_CHANGE 0x0008
-#define MII_DM9161_INTR_LINK_CHANGE 0x0004
-#define MII_DM9161_INTR_INIT 0x0000
-#define MII_DM9161_INTR_STOP \
-(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
- | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
-
-/* DM9161 10BT Configuration/Status */
-#define MII_DM9161_10BTCSR 0x12
-#define MII_DM9161_10BTCSR_INIT 0x7800
-
-#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
- SUPPORTED_10baseT_Full | \
- SUPPORTED_100baseT_Half | \
- SUPPORTED_100baseT_Full | \
- SUPPORTED_Autoneg | \
- SUPPORTED_TP | \
- SUPPORTED_MII)
-
-#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
- SUPPORTED_1000baseT_Half | \
- SUPPORTED_1000baseT_Full)
-
-#define MII_READ_COMMAND 0x00000001
-
-#define MII_INTERRUPT_DISABLED 0x0
-#define MII_INTERRUPT_ENABLED 0x1
-/* Taken from mii_if_info and sungem_phy.h */
-struct ugeth_mii_info {
- /* Information about the PHY type */
- /* And management functions */
- struct phy_info *phyinfo;
-
- struct ucc_mii_mng *mii_regs;
-
- /* forced speed & duplex (no autoneg)
- * partner speed & duplex & pause (autoneg)
- */
- int speed;
- int duplex;
- int pause;
-
- /* The most recently read link state */
- int link;
-
- /* Enabled Interrupts */
- u32 interrupts;
-
- u32 advertising;
- int autoneg;
- int mii_id;
-
- /* private data pointer */
- /* For use by PHYs to maintain extra state */
- void *priv;
-
- /* Provided by host chip */
- struct net_device *dev;
-
- /* A lock to ensure that only one thing can read/write
- * the MDIO bus at a time */
- spinlock_t mdio_lock;
-
- /* Provided by ethernet driver */
- int (*mdio_read) (struct net_device * dev, int mii_id, int reg);
- void (*mdio_write) (struct net_device * dev, int mii_id, int reg,
- int val);
-};
-
-/* struct phy_info: a structure which defines attributes for a PHY
- *
- * id will contain a number which represents the PHY. During
- * startup, the driver will poll the PHY to find out what its
- * UID--as defined by registers 2 and 3--is. The 32-bit result
- * gotten from the PHY will be ANDed with phy_id_mask to
- * discard any bits which may change based on revision numbers
- * unimportant to functionality
- *
- * There are 6 commands which take a ugeth_mii_info structure.
- * Each PHY must declare config_aneg, and read_status.
- */
-struct phy_info {
- u32 phy_id;
- char *name;
- unsigned int phy_id_mask;
- u32 features;
-
- /* Called to initialize the PHY */
- int (*init) (struct ugeth_mii_info * mii_info);
-
- /* Called to suspend the PHY for power */
- int (*suspend) (struct ugeth_mii_info * mii_info);
-
- /* Reconfigures autonegotiation (or disables it) */
- int (*config_aneg) (struct ugeth_mii_info * mii_info);
-
- /* Determines the negotiated speed and duplex */
- int (*read_status) (struct ugeth_mii_info * mii_info);
-
- /* Clears any pending interrupts */
- int (*ack_interrupt) (struct ugeth_mii_info * mii_info);
-
- /* Enables or disables interrupts */
- int (*config_intr) (struct ugeth_mii_info * mii_info);
-
- /* Clears up any memory if needed */
- void (*close) (struct ugeth_mii_info * mii_info);
-};
-
-struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info);
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value);
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum);
-void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info);
-void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
- u32 interrupts);
-
-struct dm9161_private {
- struct timer_list timer;
- int resetdone;
-};
-
-#endif /* __UCC_GETH_PHY_H__ */
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 00e0aaadabcc..9ec6cf2e510e 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -37,16 +37,16 @@
struct hdlc_header {
u8 address;
u8 control;
- u16 protocol;
+ __be16 protocol;
}__attribute__ ((packed));
struct cisco_packet {
- u32 type; /* code */
- u32 par1;
- u32 par2;
- u16 rel; /* reliability */
- u32 time;
+ __be32 type; /* code */
+ __be32 par1;
+ __be32 par2;
+ __be16 rel; /* reliability */
+ __be32 time;
}__attribute__ ((packed));
#define CISCO_PACKET_LEN 18
#define CISCO_BIG_PACKET_LEN 20
@@ -97,7 +97,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
static void cisco_keepalive_send(struct net_device *dev, u32 type,
- u32 par1, u32 par2)
+ __be32 par1, __be32 par2)
{
struct sk_buff *skb;
struct cisco_packet *data;
@@ -115,9 +115,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
data = (struct cisco_packet*)(skb->data + 4);
data->type = htonl(type);
- data->par1 = htonl(par1);
- data->par2 = htonl(par2);
- data->rel = 0xFFFF;
+ data->par1 = par1;
+ data->par2 = par2;
+ data->rel = __constant_htons(0xFFFF);
/* we will need do_div here if 1000 % HZ != 0 */
data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
@@ -193,7 +193,7 @@ static int cisco_rx(struct sk_buff *skb)
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
in_dev = dev->ip_ptr;
addr = 0;
- mask = ~0; /* is the mask correct? */
+ mask = __constant_htonl(~0); /* is the mask correct? */
if (in_dev != NULL) {
struct in_ifaddr **ifap = &in_dev->ifa_list;
@@ -245,7 +245,7 @@ static int cisco_rx(struct sk_buff *skb)
} /* switch(protocol) */
printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name,
- data->protocol);
+ ntohs(data->protocol));
dev_kfree_skb_any(skb);
return NET_RX_DROP;
@@ -270,8 +270,9 @@ static void cisco_timer(unsigned long arg)
netif_dormant_on(dev);
}
- cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq,
- state(hdlc)->rxseq);
+ cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
+ htonl(++state(hdlc)->txseq),
+ htonl(state(hdlc)->rxseq));
state(hdlc)->request_sent = 1;
state(hdlc)->timer.expires = jiffies +
state(hdlc)->settings.interval * HZ;
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index aeb2789adf26..15b6e07a4382 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -288,31 +288,31 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
struct sk_buff *skb = *skb_p;
switch (skb->protocol) {
- case __constant_ntohs(NLPID_CCITT_ANSI_LMI):
+ case __constant_htons(NLPID_CCITT_ANSI_LMI):
head_len = 4;
skb_push(skb, head_len);
skb->data[3] = NLPID_CCITT_ANSI_LMI;
break;
- case __constant_ntohs(NLPID_CISCO_LMI):
+ case __constant_htons(NLPID_CISCO_LMI):
head_len = 4;
skb_push(skb, head_len);
skb->data[3] = NLPID_CISCO_LMI;
break;
- case __constant_ntohs(ETH_P_IP):
+ case __constant_htons(ETH_P_IP):
head_len = 4;
skb_push(skb, head_len);
skb->data[3] = NLPID_IP;
break;
- case __constant_ntohs(ETH_P_IPV6):
+ case __constant_htons(ETH_P_IPV6):
head_len = 4;
skb_push(skb, head_len);
skb->data[3] = NLPID_IPV6;
break;
- case __constant_ntohs(ETH_P_802_3):
+ case __constant_htons(ETH_P_802_3):
head_len = 10;
if (skb_headroom(skb) < head_len) {
struct sk_buff *skb2 = skb_realloc_headroom(skb,
@@ -340,7 +340,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
skb->data[5] = FR_PAD;
skb->data[6] = FR_PAD;
skb->data[7] = FR_PAD;
- *(u16*)(skb->data + 8) = skb->protocol;
+ *(__be16*)(skb->data + 8) = skb->protocol;
}
dlci_to_q922(skb->data, dlci);
@@ -974,8 +974,8 @@ static int fr_rx(struct sk_buff *skb)
} else if (skb->len > 10 && data[3] == FR_PAD &&
data[4] == NLPID_SNAP && data[5] == FR_PAD) {
- u16 oui = ntohs(*(u16*)(data + 6));
- u16 pid = ntohs(*(u16*)(data + 8));
+ u16 oui = ntohs(*(__be16*)(data + 6));
+ u16 pid = ntohs(*(__be16*)(data + 8));
skb_pull(skb, 10);
switch ((((u32)oui) << 16) | pid) {
@@ -1127,7 +1127,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
memcpy(dev->dev_addr, "\x00\x01", 2);
get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
} else {
- *(u16*)dev->dev_addr = htons(dlci);
+ *(__be16*)dev->dev_addr = htons(dlci);
dlci_to_q922(dev->broadcast, dlci);
}
dev->hard_start_xmit = pvc_xmit;
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 4426841b2be6..c4b3dc291a5a 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -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)
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index c613af17a159..d2124602263b 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -43,3 +43,4 @@ obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
obj-$(CONFIG_USB_ZD1201) += zd1201.o
+obj-$(CONFIG_LIBERTAS_USB) += libertas/
diff --git a/drivers/net/wireless/README b/drivers/net/wireless/README
deleted file mode 100644
index 0c274bf6d45e..000000000000
--- a/drivers/net/wireless/README
+++ /dev/null
@@ -1,25 +0,0 @@
- README
- ------
-
- This directory is mostly for Wireless LAN drivers, in their
-various incarnations (ISA, PCI, Pcmcia...).
- This separate directory is needed because a lot of driver work
-on different bus (typically PCI + Pcmcia) and share 95% of the
-code. This allow the code and the config options to be in one single
-place instead of scattered all over the driver tree, which is never
-100% satisfactory.
-
- Note : if you want more info on the topic of Wireless LANs,
-you are kindly invited to have a look at the Wireless Howto :
- http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
- Some Wireless LAN drivers, like orinoco_cs, require the use of
-Wireless Tools to be configured :
- http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html
-
- Special notes for distribution maintainers :
- 1) wvlan_cs will be discontinued soon in favor of orinoco_cs
- 2) Please add Wireless Tools support in your scripts
-
- Have fun...
-
- Jean
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 7fe0a61091a6..f21bbafcb728 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -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);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 95ff175d8f33..f8483c179e4c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -277,11 +277,14 @@
#define BCM43xx_SBTMSTATELOW_REJECT 0x02
#define BCM43xx_SBTMSTATELOW_CLOCK 0x10000
#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000
+#define BCM43xx_SBTMSTATELOW_G_MODE_ENABLE 0x20000000
/* sbtmstatehigh state flags */
#define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001
#define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004
#define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020
+#define BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000
+#define BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL 0x00020000
#define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000
#define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000
#define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
index c947025d655f..d2df6a0100a1 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
@@ -32,7 +32,7 @@
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <linux/utsname.h>
static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -40,7 +40,7 @@ static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *
struct bcm43xx_private *bcm = bcm43xx_priv(dev);
strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
- strncpy(info->version, UTS_RELEASE, sizeof(info->version));
+ strncpy(info->version, utsname()->release, sizeof(info->version));
strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index a38e7eec0e62..5e96bca6730a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1407,7 +1407,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
& ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
} else {
if (connect_phy)
- flags |= 0x20000000;
+ flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
bcm43xx_phy_connect(bcm, connect_phy);
bcm43xx_core_enable(bcm, flags);
bcm43xx_write16(bcm, 0x03E6, 0x0000);
@@ -3604,7 +3604,7 @@ int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
u32 sbtmstatelow;
sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow |= 0x20000000;
+ sbtmstatelow |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
}
err = wireless_core_up(bcm, 1);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index 72529a440f15..b37f1e348700 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -168,16 +168,16 @@ int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect)
flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
if (connect) {
- if (!(flags & 0x00010000))
+ if (!(flags & BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL))
return -ENODEV;
flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- flags |= (0x800 << 18);
+ flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
} else {
- if (!(flags & 0x00020000))
+ if (!(flags & BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL))
return -ENODEV;
flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- flags &= ~(0x800 << 18);
+ flags &= ~BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
}
out:
@@ -300,16 +300,20 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm)
if (phy->rev > 2) {
bcm43xx_phy_write(bcm, 0x0422, 0x287A);
- bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000);
+ bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420)
+ & 0x0FFF) | 0x3000);
}
- bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874);
+ bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080)
+ | 0x7874);
bcm43xx_phy_write(bcm, 0x048E, 0x1C00);
if (phy->rev == 1) {
- bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600);
+ bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB)
+ & 0xF0FF) | 0x0600);
bcm43xx_phy_write(bcm, 0x048B, 0x005E);
- bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E);
+ bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C)
+ & 0xFF00) | 0x001E);
bcm43xx_phy_write(bcm, 0x048D, 0x0002);
}
@@ -335,7 +339,8 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
if (phy->rev == 1) {
bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
- (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340);
+ (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+ & 0xFC3F) | 0x0340);
bcm43xx_phy_write(bcm, 0x042C, 0x005A);
bcm43xx_phy_write(bcm, 0x0427, 0x001A);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
index 1f321ef42be8..73118364b552 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
@@ -48,6 +48,10 @@ void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm);
local_irq_restore(flags); \
} while (0)
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+ (((phy)->rev > 1) || ((phy)->connected))
+
u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset);
void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index 4025dd0089d2..6a109f4a1b71 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1343,11 +1343,110 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
return ret;
}
+#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd)
+{
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+ u16 loop_or = 0;
+ u16 adj_loopback_gain = phy->loopback_gain[0];
+ u8 loop;
+ u16 extern_lna_control;
+
+ if (!phy->connected)
+ return 0;
+ if (!has_loopback_gain(phy)) {
+ if (phy->rev < 7 || !(bcm->sprom.boardflags
+ & BCM43xx_BFL_EXTLNA)) {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0FB2;
+ case LPD(0, 0, 1):
+ return 0x00B2;
+ case LPD(1, 0, 1):
+ return 0x30B2;
+ case LPD(1, 0, 0):
+ return 0x30B3;
+ default:
+ assert(0);
+ }
+ } else {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8FB2;
+ case LPD(0, 0, 1):
+ return 0x80B2;
+ case LPD(1, 0, 1):
+ return 0x20B2;
+ case LPD(1, 0, 0):
+ return 0x20B3;
+ default:
+ assert(0);
+ }
+ }
+ } else {
+ if (radio->revision == 8)
+ adj_loopback_gain += 0x003E;
+ else
+ adj_loopback_gain += 0x0026;
+ if (adj_loopback_gain >= 0x46) {
+ adj_loopback_gain -= 0x46;
+ extern_lna_control = 0x3000;
+ } else if (adj_loopback_gain >= 0x3A) {
+ adj_loopback_gain -= 0x3A;
+ extern_lna_control = 0x2000;
+ } else if (adj_loopback_gain >= 0x2E) {
+ adj_loopback_gain -= 0x2E;
+ extern_lna_control = 0x1000;
+ } else {
+ adj_loopback_gain -= 0x10;
+ extern_lna_control = 0x0000;
+ }
+ for (loop = 0; loop < 16; loop++) {
+ u16 tmp = adj_loopback_gain - 6 * loop;
+ if (tmp < 6)
+ break;
+ }
+
+ loop_or = (loop << 8) | extern_lna_control;
+ if (phy->rev >= 7 && bcm->sprom.boardflags
+ & BCM43xx_BFL_EXTLNA) {
+ if (extern_lna_control)
+ loop_or |= 0x8000;
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8F92;
+ case LPD(0, 0, 1):
+ return (0x8092 | loop_or);
+ case LPD(1, 0, 1):
+ return (0x2092 | loop_or);
+ case LPD(1, 0, 0):
+ return (0x2093 | loop_or);
+ default:
+ assert(0);
+ }
+ } else {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0F92;
+ case LPD(0, 0, 1):
+ case LPD(1, 0, 1):
+ return (0x0092 | loop_or);
+ case LPD(1, 0, 0):
+ return (0x0093 | loop_or);
+ default:
+ assert(0);
+ }
+ }
+ }
+ return 0;
+}
+
u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- u16 backup[19] = { 0 };
+ u16 backup[21] = { 0 };
u16 ret;
u16 i, j;
u32 tmp1 = 0, tmp2 = 0;
@@ -1373,19 +1472,36 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
backup[9] = bcm43xx_phy_read(bcm, 0x0802);
bcm43xx_phy_write(bcm, 0x0814,
- (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
+ (bcm43xx_phy_read(bcm, 0x0814)
+ | 0x0003));
bcm43xx_phy_write(bcm, 0x0815,
- (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));
+ (bcm43xx_phy_read(bcm, 0x0815)
+ & 0xFFFC));
bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
- (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
+ (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+ & 0x7FFF));
bcm43xx_phy_write(bcm, 0x0802,
(bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
- bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
- bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
+ if (phy->rev > 1) { /* loopback gain enabled */
+ backup[19] = bcm43xx_phy_read(bcm, 0x080F);
+ backup[20] = bcm43xx_phy_read(bcm, 0x0810);
+ if (phy->rev >= 3)
+ bcm43xx_phy_write(bcm, 0x080F, 0xC020);
+ else
+ bcm43xx_phy_write(bcm, 0x080F, 0x8020);
+ bcm43xx_phy_write(bcm, 0x0810, 0x0000);
+ }
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
+ if (phy->rev < 7 || !(bcm->sprom.boardflags
+ & BCM43xx_BFL_EXTLNA))
+ bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
+ else
+ bcm43xx_phy_write(bcm, 0x0811, 0x09B3);
}
- bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
- (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
}
+ bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+ (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
backup[10] = bcm43xx_phy_read(bcm, 0x0035);
bcm43xx_phy_write(bcm, 0x0035,
(bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
@@ -1397,10 +1513,12 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_write16(bcm, 0x03E6, 0x0122);
} else {
if (phy->analog >= 2)
- bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003)
- & 0xFFBF) | 0x0040);
+ bcm43xx_phy_write(bcm, 0x0003,
+ (bcm43xx_phy_read(bcm, 0x0003)
+ & 0xFFBF) | 0x0040);
bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
- (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
+ (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+ | 0x2000));
}
ret = bcm43xx_radio_calibrationvalue(bcm);
@@ -1408,16 +1526,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
if (phy->type == BCM43xx_PHYTYPE_B)
bcm43xx_radio_write16(bcm, 0x0078, 0x0026);
+ if (phy->connected)
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
bcm43xx_phy_write(bcm, 0x002B, 0x1403);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(0, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
bcm43xx_radio_write16(bcm, 0x0051,
(bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
- bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
- bcm43xx_radio_write16(bcm, 0x0043,
- (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009);
+ if (radio->revision == 8)
+ bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
+ else {
+ bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+ bcm43xx_radio_write16(bcm, 0x0043,
+ (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0)
+ | 0x0009);
+ }
bcm43xx_phy_write(bcm, 0x0058, 0x0000);
for (i = 0; i < 16; i++) {
@@ -1425,21 +1552,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0059, 0xC810);
bcm43xx_phy_write(bcm, 0x0058, 0x000D);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
udelay(10);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
udelay(10);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(1, 0, 0)));
bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
- udelay(10);
+ udelay(20);
tmp1 += bcm43xx_phy_read(bcm, 0x002D);
bcm43xx_phy_write(bcm, 0x0058, 0x0000);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
}
@@ -1457,21 +1588,29 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0059, 0xC810);
bcm43xx_phy_write(bcm, 0x0058, 0x000D);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm,
+ LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
udelay(10);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm,
+ LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
udelay(10);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm,
+ LPD(1, 0, 0)));
bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
udelay(10);
tmp2 += bcm43xx_phy_read(bcm, 0x002D);
bcm43xx_phy_write(bcm, 0x0058, 0x0000);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm,
+ LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
}
tmp2++;
@@ -1497,15 +1636,20 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0030, backup[2]);
bcm43xx_write16(bcm, 0x03EC, backup[3]);
} else {
- bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
- (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
if (phy->connected) {
+ bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+ (bcm43xx_read16(bcm,
+ BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
bcm43xx_phy_write(bcm, 0x0811, backup[4]);
bcm43xx_phy_write(bcm, 0x0812, backup[5]);
bcm43xx_phy_write(bcm, 0x0814, backup[6]);
bcm43xx_phy_write(bcm, 0x0815, backup[7]);
bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
bcm43xx_phy_write(bcm, 0x0802, backup[9]);
+ if (phy->rev > 1) {
+ bcm43xx_phy_write(bcm, 0x080F, backup[19]);
+ bcm43xx_phy_write(bcm, 0x0810, backup[20]);
+ }
}
}
if (i >= 15)
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 4ca8a27b8c55..5b3abd54d0e5 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -1,8 +1,8 @@
/*
* Intersil Prism2 driver with Host AP (software access point) support
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This file is to be included into hostap.c when S/W AP functionality is
* compiled.
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index 01624005d808..b31e6a05f23c 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -368,9 +368,9 @@ enum {
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
#define PRISM2_HOSTAPD_RID_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+offsetof(struct prism2_hostapd_param, u.rid.data)
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+offsetof(struct prism2_hostapd_param, u.generic_elem.data)
/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
*/
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 8d8f4b9b8b07..ee1532b62e42 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -22,7 +22,7 @@
#include "hostap_wlan.h"
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
static dev_info_t dev_info = "hostap_cs";
MODULE_AUTHOR("Jouni Malinen");
@@ -838,6 +838,8 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF",
+ 0x2d858104),
PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
0x74c5e40d),
PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
@@ -848,6 +850,11 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
"Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P",
"Eval-RevA",
0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e),
+ /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */
+ PCMCIA_DEVICE_PROD_ID1234(
+ "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10",
+ "A3",
+ 0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52),
PCMCIA_DEVICE_PROD_ID123(
"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
0xe6ec52ce, 0x08649af2, 0x4b74baa0),
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index fb01fb95a9f0..959887b70ca7 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -3,8 +3,8 @@
* Intersil Prism2/2.5/3.
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 1f9edd91565d..4743426cf6ad 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -3,8 +3,8 @@
* Intersil Prism2/2.5/3 - hostap.o module, common routines
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index c4f6020baa9e..db4899ed4bb1 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -20,7 +20,7 @@
#include "hostap_wlan.h"
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
static char *dev_info = "hostap_pci";
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index e235e0647897..f0fd5ecdb24d 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -23,7 +23,7 @@
#include "hostap_wlan.h"
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
static char *dev_info = "hostap_plx";
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 9137a4dd02eb..d51daf87450f 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -28,8 +28,8 @@
Portions of this file are based on the Host AP project,
Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <jkmaline@cc.hut.fi>
- Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ <j@w1.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 4839a45098cb..7cb2052a55a5 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1847,6 +1847,52 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr,
static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO,
show_net_stats, store_net_stats);
+static ssize_t show_channels(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
+ int len = 0, i;
+
+ len = sprintf(&buf[len],
+ "Displaying %d channels in 2.4Ghz band "
+ "(802.11bg):\n", geo->bg_channels);
+
+ for (i = 0; i < geo->bg_channels; i++) {
+ len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n",
+ geo->bg[i].channel,
+ geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ?
+ " (radar spectrum)" : "",
+ ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) ||
+ (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT))
+ ? "" : ", IBSS",
+ geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+ "passive only" : "active/passive",
+ geo->bg[i].flags & IEEE80211_CH_B_ONLY ?
+ "B" : "B/G");
+ }
+
+ len += sprintf(&buf[len],
+ "Displaying %d channels in 5.2Ghz band "
+ "(802.11a):\n", geo->a_channels);
+ for (i = 0; i < geo->a_channels; i++) {
+ len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n",
+ geo->a[i].channel,
+ geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ?
+ " (radar spectrum)" : "",
+ ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) ||
+ (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT))
+ ? "" : ", IBSS",
+ geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+ "passive only" : "active/passive");
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
static void notify_wx_assoc_event(struct ipw_priv *priv)
{
union iwreq_data wrqu;
@@ -11383,6 +11429,7 @@ static struct attribute *ipw_sysfs_entries[] = {
&dev_attr_led.attr,
&dev_attr_speed_scan.attr,
&dev_attr_net_stats.attr,
+ &dev_attr_channels.attr,
#ifdef CONFIG_IPW2200_PROMISCUOUS
&dev_attr_rtap_iface.attr,
&dev_attr_rtap_filter.attr,
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
new file mode 100644
index 000000000000..e0ecc4d483bb
--- /dev/null
+++ b/drivers/net/wireless/libertas/11d.c
@@ -0,0 +1,754 @@
+/**
+ * This file contains functions for 802.11D.
+ */
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/wireless.h>
+
+#include "host.h"
+#include "decl.h"
+#include "11d.h"
+#include "dev.h"
+#include "wext.h"
+
+#define TX_PWR_DEFAULT 10
+
+static struct region_code_mapping region_code_mapping[] = {
+ {"US ", 0x10}, /* US FCC */
+ {"CA ", 0x10}, /* IC Canada */
+ {"SG ", 0x10}, /* Singapore */
+ {"EU ", 0x30}, /* ETSI */
+ {"AU ", 0x30}, /* Australia */
+ {"KR ", 0x30}, /* Republic Of Korea */
+ {"ES ", 0x31}, /* Spain */
+ {"FR ", 0x32}, /* France */
+ {"JP ", 0x40}, /* Japan */
+};
+
+/* Following 2 structure defines the supported channels */
+static struct chan_freq_power channel_freq_power_UN_BG[] = {
+ {1, 2412, TX_PWR_DEFAULT},
+ {2, 2417, TX_PWR_DEFAULT},
+ {3, 2422, TX_PWR_DEFAULT},
+ {4, 2427, TX_PWR_DEFAULT},
+ {5, 2432, TX_PWR_DEFAULT},
+ {6, 2437, TX_PWR_DEFAULT},
+ {7, 2442, TX_PWR_DEFAULT},
+ {8, 2447, TX_PWR_DEFAULT},
+ {9, 2452, TX_PWR_DEFAULT},
+ {10, 2457, TX_PWR_DEFAULT},
+ {11, 2462, TX_PWR_DEFAULT},
+ {12, 2467, TX_PWR_DEFAULT},
+ {13, 2472, TX_PWR_DEFAULT},
+ {14, 2484, TX_PWR_DEFAULT}
+};
+
+static u8 wlan_region_2_code(u8 * region)
+{
+ u8 i;
+ u8 size = sizeof(region_code_mapping)/
+ sizeof(struct region_code_mapping);
+
+ for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
+ region[i] = toupper(region[i]);
+
+ for (i = 0; i < size; i++) {
+ if (!memcmp(region, region_code_mapping[i].region,
+ COUNTRY_CODE_LEN))
+ return (region_code_mapping[i].code);
+ }
+
+ /* default is US */
+ return (region_code_mapping[0].code);
+}
+
+static u8 *wlan_code_2_region(u8 code)
+{
+ u8 i;
+ u8 size = sizeof(region_code_mapping)
+ / sizeof(struct region_code_mapping);
+ for (i = 0; i < size; i++) {
+ if (region_code_mapping[i].code == code)
+ return (region_code_mapping[i].region);
+ }
+ /* default is US */
+ return (region_code_mapping[0].region);
+}
+
+/**
+ * @brief This function finds the nrchan-th chan after the firstchan
+ * @param band band
+ * @param firstchan first channel number
+ * @param nrchan number of channels
+ * @return the nrchan-th chan number
+*/
+static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
+/*find the nrchan-th chan after the firstchan*/
+{
+ u8 i;
+ struct chan_freq_power *cfp;
+ u8 cfp_no;
+
+ cfp = channel_freq_power_UN_BG;
+ cfp_no = sizeof(channel_freq_power_UN_BG) /
+ sizeof(struct chan_freq_power);
+
+ for (i = 0; i < cfp_no; i++) {
+ if ((cfp + i)->channel == firstchan) {
+ lbs_pr_debug(1, "firstchan found\n");
+ break;
+ }
+ }
+
+ if (i < cfp_no) {
+ /*if beyond the boundary */
+ if (i + nrchan < cfp_no) {
+ *chan = (cfp + i + nrchan)->channel;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * @brief This function Checks if chan txpwr is learned from AP/IBSS
+ * @param chan chan number
+ * @param parsed_region_chan pointer to parsed_region_chan_11d
+ * @return TRUE; FALSE
+*/
+static u8 wlan_channel_known_11d(u8 chan,
+ struct parsed_region_chan_11d * parsed_region_chan)
+{
+ struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
+ u8 nr_chan = parsed_region_chan->nr_chan;
+ u8 i = 0;
+
+ lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr,
+ sizeof(struct chan_power_11d) * nr_chan);
+
+ for (i = 0; i < nr_chan; i++) {
+ if (chan == chanpwr[i].chan) {
+ lbs_pr_debug(1, "11D: Found Chan:%d\n", chan);
+ return 1;
+ }
+ }
+
+ lbs_pr_debug(1, "11D: Not Find Chan:%d\n", chan);
+ return 0;
+}
+
+u32 libertas_chan_2_freq(u8 chan, u8 band)
+{
+ struct chan_freq_power *cf;
+ u16 cnt;
+ u16 i;
+ u32 freq = 0;
+
+ cf = channel_freq_power_UN_BG;
+ cnt =
+ sizeof(channel_freq_power_UN_BG) /
+ sizeof(struct chan_freq_power);
+
+ for (i = 0; i < cnt; i++) {
+ if (chan == cf[i].channel)
+ freq = cf[i].freq;
+ }
+
+ return freq;
+}
+
+static int generate_domain_info_11d(struct parsed_region_chan_11d
+ *parsed_region_chan,
+ struct wlan_802_11d_domain_reg * domaininfo)
+{
+ u8 nr_subband = 0;
+
+ u8 nr_chan = parsed_region_chan->nr_chan;
+ u8 nr_parsedchan = 0;
+
+ u8 firstchan = 0, nextchan = 0, maxpwr = 0;
+
+ u8 i, flag = 0;
+
+ memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
+ COUNTRY_CODE_LEN);
+
+ lbs_pr_debug(1, "11D:nrchan=%d\n", nr_chan);
+ lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan,
+ sizeof(struct parsed_region_chan_11d));
+
+ for (i = 0; i < nr_chan; i++) {
+ if (!flag) {
+ flag = 1;
+ nextchan = firstchan =
+ parsed_region_chan->chanpwr[i].chan;
+ maxpwr = parsed_region_chan->chanpwr[i].pwr;
+ nr_parsedchan = 1;
+ continue;
+ }
+
+ if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
+ parsed_region_chan->chanpwr[i].pwr == maxpwr) {
+ nextchan++;
+ nr_parsedchan++;
+ } else {
+ domaininfo->subband[nr_subband].firstchan = firstchan;
+ domaininfo->subband[nr_subband].nrchan =
+ nr_parsedchan;
+ domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
+ nr_subband++;
+ nextchan = firstchan =
+ parsed_region_chan->chanpwr[i].chan;
+ maxpwr = parsed_region_chan->chanpwr[i].pwr;
+ }
+ }
+
+ if (flag) {
+ domaininfo->subband[nr_subband].firstchan = firstchan;
+ domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
+ domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
+ nr_subband++;
+ }
+ domaininfo->nr_subband = nr_subband;
+
+ lbs_pr_debug(1, "nr_subband=%x\n", domaininfo->nr_subband);
+ lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo,
+ COUNTRY_CODE_LEN + 1 +
+ sizeof(struct ieeetypes_subbandset) * nr_subband);
+ return 0;
+}
+
+/**
+ * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
+ * @param region_chan pointer to struct region_channel
+ * @param *parsed_region_chan pointer to parsed_region_chan_11d
+ * @return N/A
+*/
+static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan,
+ struct parsed_region_chan_11d *
+ parsed_region_chan)
+{
+ u8 i;
+ struct chan_freq_power *cfp;
+
+ if (region_chan == NULL) {
+ lbs_pr_debug(1, "11D: region_chan is NULL\n");
+ return;
+ }
+
+ cfp = region_chan->CFP;
+ if (cfp == NULL) {
+ lbs_pr_debug(1, "11D: cfp equal NULL \n");
+ return;
+ }
+
+ parsed_region_chan->band = region_chan->band;
+ parsed_region_chan->region = region_chan->region;
+ memcpy(parsed_region_chan->countrycode,
+ wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
+
+ lbs_pr_debug(1, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
+ parsed_region_chan->band);
+
+ for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
+ parsed_region_chan->chanpwr[i].chan = cfp->channel;
+ parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
+ lbs_pr_debug(1, "11D: Chan[%d] Pwr[%d]\n",
+ parsed_region_chan->chanpwr[i].chan,
+ parsed_region_chan->chanpwr[i].pwr);
+ }
+ parsed_region_chan->nr_chan = region_chan->nrcfp;
+
+ lbs_pr_debug(1, "11D: nrchan[%d]\n", parsed_region_chan->nr_chan);
+
+ return;
+}
+
+/**
+ * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
+ * @param region region ID
+ * @param band band
+ * @param chan chan
+ * @return TRUE;FALSE
+*/
+static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
+{
+ struct chan_freq_power *cfp;
+ int cfp_no;
+ u8 idx;
+
+ ENTER();
+
+ cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
+ if (cfp == NULL)
+ return 0;
+
+ for (idx = 0; idx < cfp_no; idx++) {
+ if (chan == (cfp + idx)->channel) {
+ /* If Mrvl Chip Supported? */
+ if ((cfp + idx)->unsupported) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ }
+
+ /*chan is not in the region table */
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function checks if chan txpwr is learned from AP/IBSS
+ * @param chan chan number
+ * @param parsed_region_chan pointer to parsed_region_chan_11d
+ * @return 0
+*/
+static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
+ countryinfo,
+ u8 band,
+ struct parsed_region_chan_11d *
+ parsed_region_chan)
+{
+ u8 nr_subband, nrchan;
+ u8 lastchan, firstchan;
+ u8 region;
+ u8 curchan = 0;
+
+ u8 idx = 0; /*chan index in parsed_region_chan */
+
+ u8 j, i;
+
+ ENTER();
+
+ /*validation Rules:
+ 1. valid region Code
+ 2. First Chan increment
+ 3. channel range no overlap
+ 4. channel is valid?
+ 5. channel is supported by region?
+ 6. Others
+ */
+
+ lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30);
+
+ if ((*(countryinfo->countrycode)) == 0
+ || (countryinfo->len <= COUNTRY_CODE_LEN)) {
+ /* No region Info or Wrong region info: treat as No 11D info */
+ LEAVE();
+ return 0;
+ }
+
+ /*Step1: check region_code */
+ parsed_region_chan->region = region =
+ wlan_region_2_code(countryinfo->countrycode);
+
+ lbs_pr_debug(1, "regioncode=%x\n", (u8) parsed_region_chan->region);
+ lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
+ COUNTRY_CODE_LEN);
+
+ parsed_region_chan->band = band;
+
+ memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
+ COUNTRY_CODE_LEN);
+
+ nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
+ sizeof(struct ieeetypes_subbandset);
+
+ for (j = 0, lastchan = 0; j < nr_subband; j++) {
+
+ if (countryinfo->subband[j].firstchan <= lastchan) {
+ /*Step2&3. Check First Chan Num increment and no overlap */
+ lbs_pr_debug(1, "11D: Chan[%d>%d] Overlap\n",
+ countryinfo->subband[j].firstchan, lastchan);
+ continue;
+ }
+
+ firstchan = countryinfo->subband[j].firstchan;
+ nrchan = countryinfo->subband[j].nrchan;
+
+ for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
+ /*step4: channel is supported? */
+
+ if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
+ /* Chan is not found in UN table */
+ lbs_pr_debug(1, "chan is not supported: %d \n", i);
+ break;
+ }
+
+ lastchan = curchan;
+
+ if (wlan_region_chan_supported_11d
+ (region, band, curchan)) {
+ /*step5: Check if curchan is supported by mrvl in region */
+ parsed_region_chan->chanpwr[idx].chan = curchan;
+ parsed_region_chan->chanpwr[idx].pwr =
+ countryinfo->subband[j].maxtxpwr;
+ idx++;
+ } else {
+ /*not supported and ignore the chan */
+ lbs_pr_debug(1,
+ "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n",
+ i, curchan, region, band);
+ }
+ }
+
+ /*Step6: Add other checking if any */
+
+ }
+
+ parsed_region_chan->nr_chan = idx;
+
+ lbs_pr_debug(1, "nrchan=%x\n", parsed_region_chan->nr_chan);
+ lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan,
+ 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function calculates the scan type for channels
+ * @param chan chan number
+ * @param parsed_region_chan pointer to parsed_region_chan_11d
+ * @return PASSIVE if chan is unknown; ACTIVE if chan is known
+*/
+u8 libertas_get_scan_type_11d(u8 chan,
+ struct parsed_region_chan_11d * parsed_region_chan)
+{
+ u8 scan_type = cmd_scan_type_passive;
+
+ ENTER();
+
+ if (wlan_channel_known_11d(chan, parsed_region_chan)) {
+ lbs_pr_debug(1, "11D: Found and do Active Scan\n");
+ scan_type = cmd_scan_type_active;
+ } else {
+ lbs_pr_debug(1, "11D: Not Find and do Passive Scan\n");
+ }
+
+ LEAVE();
+ return scan_type;
+
+}
+
+void libertas_init_11d(wlan_private * priv)
+{
+ priv->adapter->enable11d = 0;
+ memset(&(priv->adapter->parsed_region_chan), 0,
+ sizeof(struct parsed_region_chan_11d));
+ return;
+}
+
+static int wlan_enable_11d(wlan_private * priv, u8 flag)
+{
+ int ret;
+
+ priv->adapter->enable11d = flag;
+
+ /* send cmd to FW to enable/disable 11D function in FW */
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_snmp_mib,
+ cmd_act_set,
+ cmd_option_waitforrsp,
+ OID_802_11D_ENABLE,
+ &priv->adapter->enable11d);
+ if (ret)
+ lbs_pr_debug(1, "11D: Fail to enable 11D \n");
+
+ return 0;
+}
+
+/**
+ * @brief This function sets DOMAIN INFO to FW
+ * @param priv pointer to wlan_private
+ * @return 0; -1
+*/
+static int set_domain_info_11d(wlan_private * priv)
+{
+ int ret;
+
+ if (!priv->adapter->enable11d) {
+ lbs_pr_debug(1, "11D: dnld domain Info with 11d disabled\n");
+ return 0;
+ }
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+ if (ret)
+ lbs_pr_debug(1, "11D: Fail to dnld domain Info\n");
+
+ return ret;
+}
+
+/**
+ * @brief This function setups scan channels
+ * @param priv pointer to wlan_private
+ * @param band band
+ * @return 0
+*/
+int libertas_set_universaltable(wlan_private * priv, u8 band)
+{
+ wlan_adapter *adapter = priv->adapter;
+ u16 size = sizeof(struct chan_freq_power);
+ u16 i = 0;
+
+ memset(adapter->universal_channel, 0,
+ sizeof(adapter->universal_channel));
+
+ adapter->universal_channel[i].nrcfp =
+ sizeof(channel_freq_power_UN_BG) / size;
+ lbs_pr_debug(1, "11D: BG-band nrcfp=%d\n",
+ adapter->universal_channel[i].nrcfp);
+
+ adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
+ adapter->universal_channel[i].valid = 1;
+ adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+ adapter->universal_channel[i].band = band;
+ i++;
+
+ return 0;
+}
+
+/**
+ * @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ * @param priv pointer to wlan_private
+ * @param cmd pointer to cmd buffer
+ * @param cmdno cmd ID
+ * @param cmdOption cmd action
+ * @return 0
+*/
+int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+ struct cmd_ds_command *cmd, u16 cmdno,
+ u16 cmdoption)
+{
+ struct cmd_ds_802_11d_domain_info *pdomaininfo =
+ &cmd->params.domaininfo;
+ struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
+ wlan_adapter *adapter = priv->adapter;
+ u8 nr_subband = adapter->domainreg.nr_subband;
+
+ ENTER();
+
+ lbs_pr_debug(1, "nr_subband=%x\n", nr_subband);
+
+ cmd->command = cpu_to_le16(cmdno);
+ pdomaininfo->action = cpu_to_le16(cmdoption);
+ if (cmdoption == cmd_act_get) {
+ cmd->size =
+ cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+ lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
+ (int)(cmd->size));
+ LEAVE();
+ return 0;
+ }
+
+ domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
+ memcpy(domain->countrycode, adapter->domainreg.countrycode,
+ sizeof(domain->countrycode));
+
+ domain->header.len =
+ cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
+ sizeof(domain->countrycode));
+
+ if (nr_subband) {
+ memcpy(domain->subband, adapter->domainreg.subband,
+ nr_subband * sizeof(struct ieeetypes_subbandset));
+
+ cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+ domain->header.len +
+ sizeof(struct mrvlietypesheader) +
+ S_DS_GEN);
+ } else {
+ cmd->size =
+ cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+ }
+
+ lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->size));
+
+ LEAVE();
+
+ return 0;
+}
+
+/**
+ * @brief This function implements private cmd: enable/disable 11D
+ * @param priv pointer to wlan_private
+ * @param wrq pointer to user data
+ * @return 0 or -1
+ */
+int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
+{
+ int data = 0;
+ int *val;
+
+ ENTER();
+ data = SUBCMD_DATA(wrq);
+
+ lbs_pr_debug(1, "enable 11D: %s\n",
+ (data == 1) ? "enable" : "Disable");
+
+ wlan_enable_11d(priv, data);
+ val = (int *)wrq->u.name;
+ *val = priv->adapter->enable11d;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function parses countryinfo from AP and download country info to FW
+ * @param priv pointer to wlan_private
+ * @param resp pointer to command response buffer
+ * @return 0; -1
+ */
+int libertas_ret_802_11d_domain_info(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11d_domain_info
+ *domaininfo = &resp->params.domaininforesp;
+ struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
+ u16 action = le16_to_cpu(domaininfo->action);
+ s16 ret = 0;
+ u8 nr_subband = 0;
+
+ ENTER();
+
+ lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
+ (int)le16_to_cpu(resp->size));
+
+ nr_subband = (domain->header.len - 3) / sizeof(struct ieeetypes_subbandset);
+ /* countrycode 3 bytes */
+
+ lbs_pr_debug(1, "11D Domain Info Resp: nr_subband=%d\n", nr_subband);
+
+ if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
+ lbs_pr_debug(1, "Invalid Numrer of Subband returned!!\n");
+ return -1;
+ }
+
+ switch (action) {
+ case cmd_act_set: /*Proc Set action */
+ break;
+
+ case cmd_act_get:
+ break;
+ default:
+ lbs_pr_debug(1, "Invalid action:%d\n", domaininfo->action);
+ ret = -1;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function parses countryinfo from AP and download country info to FW
+ * @param priv pointer to wlan_private
+ * @return 0; -1
+ */
+int libertas_parse_dnld_countryinfo_11d(wlan_private * priv)
+{
+ int ret;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+ if (priv->adapter->enable11d) {
+ memset(&adapter->parsed_region_chan, 0,
+ sizeof(struct parsed_region_chan_11d));
+ ret = parse_domain_info_11d(&adapter->pattemptedbssdesc->
+ countryinfo, 0,
+ &adapter->parsed_region_chan);
+
+ if (ret == -1) {
+ lbs_pr_debug(1, "11D: Err Parse domain_info from AP..\n");
+ LEAVE();
+ return ret;
+ }
+
+ memset(&adapter->domainreg, 0,
+ sizeof(struct wlan_802_11d_domain_reg));
+ generate_domain_info_11d(&adapter->parsed_region_chan,
+ &adapter->domainreg);
+
+ ret = set_domain_info_11d(priv);
+
+ if (ret) {
+ lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
+ LEAVE();
+ return ret;
+ }
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function generates 11D info from user specified regioncode and download to FW
+ * @param priv pointer to wlan_private
+ * @return 0; -1
+ */
+int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
+{
+ int ret;
+ wlan_adapter *adapter = priv->adapter;
+ struct region_channel *region_chan;
+ u8 j;
+
+ ENTER();
+ lbs_pr_debug(1, "11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
+
+ if (priv->adapter->enable11d) {
+ /* update parsed_region_chan_11; dnld domaininf to FW */
+
+ for (j = 0; j < sizeof(adapter->region_channel) /
+ sizeof(adapter->region_channel[0]); j++) {
+ region_chan = &adapter->region_channel[j];
+
+ lbs_pr_debug(1, "11D:[%d] region_chan->band[%d]\n", j,
+ region_chan->band);
+
+ if (!region_chan || !region_chan->valid
+ || !region_chan->CFP)
+ continue;
+ if (region_chan->band != adapter->curbssparams.band)
+ continue;
+ break;
+ }
+
+ if (j >= sizeof(adapter->region_channel) /
+ sizeof(adapter->region_channel[0])) {
+ lbs_pr_debug(1, "11D:region_chan not found. band[%d]\n",
+ adapter->curbssparams.band);
+ LEAVE();
+ return -1;
+ }
+
+ memset(&adapter->parsed_region_chan, 0,
+ sizeof(struct parsed_region_chan_11d));
+ wlan_generate_parsed_region_chan_11d(region_chan,
+ &adapter->
+ parsed_region_chan);
+
+ memset(&adapter->domainreg, 0,
+ sizeof(struct wlan_802_11d_domain_reg));
+ generate_domain_info_11d(&adapter->parsed_region_chan,
+ &adapter->domainreg);
+
+ ret = set_domain_info_11d(priv);
+
+ if (ret) {
+ lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
+ LEAVE();
+ return ret;
+ }
+
+ }
+
+ LEAVE();
+ return 0;
+}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
new file mode 100644
index 000000000000..db2ebea9f231
--- /dev/null
+++ b/drivers/net/wireless/libertas/11d.h
@@ -0,0 +1,105 @@
+/**
+ * This header file contains data structures and
+ * function declarations of 802.11d
+ */
+#ifndef _WLAN_11D_
+#define _WLAN_11D_
+
+#include "types.h"
+#include "defs.h"
+
+#define UNIVERSAL_REGION_CODE 0xff
+
+/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
+ */
+#define MRVDRV_MAX_SUBBAND_802_11D 83
+
+#define COUNTRY_CODE_LEN 3
+#define MAX_NO_OF_CHAN 40
+
+struct cmd_ds_command;
+
+/** Data structure for Country IE*/
+struct ieeetypes_subbandset {
+ u8 firstchan;
+ u8 nrchan;
+ u8 maxtxpwr;
+} __attribute__ ((packed));
+
+struct ieeetypes_countryinfoset {
+ u8 element_id;
+ u8 len;
+ u8 countrycode[COUNTRY_CODE_LEN];
+ struct ieeetypes_subbandset subband[1];
+};
+
+struct ieeetypes_countryinfofullset {
+ u8 element_id;
+ u8 len;
+ u8 countrycode[COUNTRY_CODE_LEN];
+ struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
+} __attribute__ ((packed));
+
+struct mrvlietypes_domainparamset {
+ struct mrvlietypesheader header;
+ u8 countrycode[COUNTRY_CODE_LEN];
+ struct ieeetypes_subbandset subband[1];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11d_domain_info {
+ u16 action;
+ struct mrvlietypes_domainparamset domain;
+} __attribute__ ((packed));
+
+/** domain regulatory information */
+struct wlan_802_11d_domain_reg {
+ /** country Code*/
+ u8 countrycode[COUNTRY_CODE_LEN];
+ /** No. of subband*/
+ u8 nr_subband;
+ struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
+};
+
+struct chan_power_11d {
+ u8 chan;
+ u8 pwr;
+} __attribute__ ((packed));
+
+struct parsed_region_chan_11d {
+ u8 band;
+ u8 region;
+ s8 countrycode[COUNTRY_CODE_LEN];
+ struct chan_power_11d chanpwr[MAX_NO_OF_CHAN];
+ u8 nr_chan;
+} __attribute__ ((packed));
+
+struct region_code_mapping {
+ u8 region[COUNTRY_CODE_LEN];
+ u8 code;
+};
+
+u8 libertas_get_scan_type_11d(u8 chan,
+ struct parsed_region_chan_11d *parsed_region_chan);
+
+u32 libertas_chan_2_freq(u8 chan, u8 band);
+
+enum state_11d libertas_get_state_11d(wlan_private * priv);
+
+void libertas_init_11d(wlan_private * priv);
+
+int libertas_set_universaltable(wlan_private * priv, u8 band);
+
+int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+ struct cmd_ds_command *cmd, u16 cmdno,
+ u16 cmdOption);
+
+int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
+
+int libertas_ret_802_11d_domain_info(wlan_private * priv,
+ struct cmd_ds_command *resp);
+
+int libertas_parse_dnld_countryinfo_11d(wlan_private * priv);
+
+int libertas_create_dnld_countryinfo_11d(wlan_private * priv);
+
+#endif /* _WLAN_11D_ */
diff --git a/drivers/net/wireless/libertas/LICENSE b/drivers/net/wireless/libertas/LICENSE
new file mode 100644
index 000000000000..8862742213b9
--- /dev/null
+++ b/drivers/net/wireless/libertas/LICENSE
@@ -0,0 +1,16 @@
+ Copyright (c) 2003-2006, Marvell International Ltd.
+ All Rights Reserved
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
new file mode 100644
index 000000000000..19c935071d8e
--- /dev/null
+++ b/drivers/net/wireless/libertas/Makefile
@@ -0,0 +1,21 @@
+# EXTRA_CFLAGS += -Wpacked
+
+usb8xxx-objs := main.o fw.o wext.o \
+ rx.o tx.o cmd.o \
+ cmdresp.o scan.o \
+ join.o 11d.o \
+ ioctl.o debugfs.o \
+ ethtool.o assoc.o
+
+ifeq ($(CONFIG_LIBERTAS_USB_DEBUG), y)
+EXTRA_CFLAGS += -DDEBUG -DPROC_DEBUG
+endif
+
+
+# This is needed to support the newer boot2 bootloader (v >= 3104)
+EXTRA_CFLAGS += -DSUPPORT_BOOT_COMMAND
+usb8xxx-objs += if_bootcmd.o
+usb8xxx-objs += if_usb.o
+
+obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
+
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
new file mode 100644
index 000000000000..688da4c784b1
--- /dev/null
+++ b/drivers/net/wireless/libertas/README
@@ -0,0 +1,1044 @@
+================================================================================
+ README for USB8388
+
+ (c) Copyright © 2003-2006, Marvell International Ltd.
+ All Rights Reserved
+
+ This software file (the "File") is distributed by Marvell International
+ Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ (the "License"). You may use, redistribute and/or modify this File in
+ accordance with the terms and conditions of the License, a copy of which
+ is available along with the File in the license.txt file or by writing to
+ the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+
+ THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ this warranty disclaimer.
+================================================================================
+
+=====================
+DRIVER LOADING
+=====================
+
+ o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/
+
+ o. Load driver by using the following command:
+
+ insmod usb8388.ko [fw_name=usb8388.bin]
+
+=====================
+IWPRIV COMMAND
+=====================
+
+NAME
+ This manual describes the usage of private commands used in Marvell WLAN
+ Linux Driver. All the commands available in Wlanconfig will not be available
+ in the iwpriv.
+
+SYNOPSIS
+ iwpriv <ethX> <command> [sub-command] ...
+
+ iwpriv ethX version
+ iwpriv ethX scantype [sub-command]
+ iwpriv ethX getSNR <n>
+ iwpriv ethX getNF <n>
+ iwpriv ethX getRSSI <n>
+ iwpriv ethX setrxant <n>
+ iwpriv ethX getrxant
+ iwpriv ethX settxant <n>
+ iwpriv ethX gettxant
+ iwpriv ethX authalgs <n>
+ iwpriv ethX pre-TBTT <n>
+ iwpriv ethX 8021xauthalgs <n>
+ iwpriv ethX encryptionmode <n>
+ iwpriv ethX setregioncode <n>
+ iwpriv ethX getregioncode
+ iwpriv ethX setbcnavg <n>
+ iwpriv ethX getbcnavg
+ iwpriv ethX setdataavg <n>
+ iwpriv ethX setlisteninter <n>
+ iwpriv ethX getlisteninter
+ iwpriv ethX setmultipledtim <n>
+ iwpriv ethX getmultipledtim
+ iwpriv ethX atimwindow <n>
+ iwpriv ethX deauth
+ iwpriv ethX adhocstop
+ iwpriv ethX radioon
+ iwpriv ethX radiooff
+ iwpriv ethX reasso-on
+ iwpriv ethX reasso-off
+ iwpriv ethX scanmode [sub-command]
+ iwpriv ethX setwpaie <n>
+ iwpriv ethX wlanidle-off
+ iwpriv ethX wlanidle-on
+ iwpriv ethX getcis
+ iwpriv ethX getlog
+ iwpriv ethX getadhocstatus
+ iwpriv ethX adhocgrate <n>
+
+Version 4 Command:
+ iwpriv ethX inactvityto <n>
+ iwpriv ethX sleeppd <n>
+ iwpriv ethX enable11d <n>
+ iwpriv ethX tpccfg <n>
+ iwpriv ethX powercfg <n>
+ iwpriv ethX setafc <n>
+ iwpriv ethX getafc
+
+Version 5 Command:
+ iwpriv ethX ledgpio <n>
+ iwpriv ethX scanprobes <n>
+ iwpriv ethX lolisteninter <n>
+ iwpriv ethX rateadapt <n> <m>
+ iwpriv ethX txcontrol <n>
+ iwpriv ethX psnullinterval <n>
+ iwpriv ethX prescan <n>
+ iwpriv ethX getrxinfo
+ iwpriv ethX gettxrate
+ iwpriv ethX beaconinterval
+
+BT Commands:
+ The blinding table (BT) contains a list of mac addresses that should be
+ ignored by the firmware. It is primarily used for debugging and
+ testing networks. It can be edited and inspected with the following
+ commands:
+
+ iwpriv ethX bt_reset
+ iwpriv ethX bt_add <mac_address>
+ iwpriv ethX bt_del <mac_address>
+ iwpriv ethX bt_list <id>
+
+FWT Commands:
+ The forwarding table (FWT) is a feature used to manage mesh network
+ routing in the firmware. The FWT is essentially a routing table that
+ associates a destination mac address (da) with a next hop receiver
+ address (ra). The FWT can be inspected and edited with the following
+ iwpriv commands, which are described in greater detail below.
+ Eventually, the table will be automatically maintained by a custom
+ routing protocol.
+
+ NOTE: FWT commands replace the previous DFT commands. What were the DFT
+ commands?, you might ask. They were an earlier API to the firmware that
+ implemented a simple MAC-layer forwarding mechanism. In the unlikely
+ event that you were using these commands, you must migrate to the new
+ FWT commands which can be used to achieve the same functionality.
+
+ iwpriv ethX fwt_add [parameters]
+ iwpriv ethX fwt_del [parameters]
+ iwpriv ethX fwt_lookup [parameters]
+ iwpriv ethX fwt_list [parameters]
+ iwpriv ethX fwt_list_route [parameters]
+ iwpriv ethX fwt_list_neigh [parameters]
+ iwpriv ethX fwt_reset [parameters]
+ iwpriv ethX fwt_cleanup
+ iwpriv ethX fwt_time
+
+MESH Commands:
+
+ The MESH commands are used to configure various features of the mesh
+ routing protocol. The following commands are supported:
+
+ iwpriv ethX mesh_get_ttl
+ iwpriv ethX mesh_set_ttl ttl
+
+DESCRIPTION
+ Those commands are used to send additional commands to the Marvell WLAN
+ card via the Linux device driver.
+
+ The ethX parameter specifies the network device that is to be used to
+ perform this command on. it could be eth0, eth1 etc.
+
+version
+ This is used to get the current version of the driver and the firmware.
+
+scantype
+ This command is used to set the scan type to be used by the driver in
+ the scan command. This setting will not be used while performing a scan
+ for a specific SSID, as it is always done with scan type being active.
+
+ where the sub-commands are: -
+ active -- to set the scan type to active
+ passive -- to set the scan type to passive
+ get -- to get the scan type set in the driver
+
+getSNR
+ This command gets the average and non average value of Signal to Noise
+ Ratio of Beacon and Data.
+
+ where value is:-
+ 0 -- Beacon non-average.
+ 1 -- Beacon average.
+ 2 -- Data non-average.
+ 3 -- Data average.
+
+ If no value is given, all four values are returned in the order mentioned
+ above.
+
+ Note: This command is available only when STA is connected.
+
+getRSSI
+ This command gets the average and non average value os Receive Signal
+ Strength of Beacon and Data.
+
+ where value is:-
+ 0 -- Beacon non-average.
+ 1 -- Beacon average.
+ 2 -- Data non-average.
+ 3 -- Data average.
+
+ Note: This command is available only when STA is connected.
+
+getNF
+ This command gets the average and non average value of Noise Floor of
+ Beacon and Data.
+
+ where value is:-
+ 0 -- Beacon non-average.
+ 1 -- Beacon average.
+ 2 -- Data non-average.
+ 3 -- Data average.
+
+ Note: This command is available only when STA is connected.
+
+setrxant
+ This command is used to set the mode for Rx antenna.
+
+ The options that can be sent are:-
+ 1 -- Antenna 1.
+ 2 -- Antenna 2.
+ 0xFFFF -- Diversity.
+
+ Usage:
+ iwpriv ethX setrxant 0x01: select Antenna 1.
+
+getrxant
+ This command is used to get the mode for Rx antenna.
+
+
+settxant
+ This command is used to set the mode for Tx antenna.
+ The options that can be sent are:-
+ 1 -- Antenna 1.
+ 2 -- Antenna 2.
+ 0xFFFF -- Diversity.
+ Usage:
+ iwpriv ethX settxant 0x01: select Antenna 1.
+
+gettxant
+ This command is used to get the mode for Tx antenna.
+
+authalgs
+ This command is used by the WPA supplicant to set the authentication
+ algorithms in the station.
+
+8021xauthalgs
+ This command is used by the WPA supplicant to set the 8021.x authentication algorithm type
+ station.
+
+ where values can be:-
+ 1 -- None
+ 2 -- LEAP
+ 4 -- TLS
+ 8 -- TTLs
+ 16 -- MD5
+
+
+encryptionmode
+ This command is used by the WPA supplicant to set the encryption algorithm.
+
+ where values can be:-
+ 0 -- NONE
+ 1 -- WEP40
+ 2 -- TKIP
+ 3 -- CCMP
+ 4 -- WEP104
+
+pre-TBTT
+ This command is used to set pre-TBTT time period where value is in microseconds.
+
+setregioncode
+ This command is used to set the region code in the station.
+ where value is 'region code' for various regions like
+ USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ...
+
+ Usage:
+ iwpriv ethX setregioncode 0x10: set region code to USA (0x10).
+
+getregioncode
+ This command is used to get the region code information set in the
+ station.
+
+setbcnavg
+ Set the weighting factor for calculating RSSI.
+
+getbcnavg
+ Get weighting factor for calculating RSSI.
+
+setdataavg
+ Set the weighting factor for calculating SNR.
+
+setlisteninter
+ This command is used to set the listen interval in the
+ station.
+
+ where the value ranges between 1 - 255
+
+getlisteninter
+ This command is used to get the listen interval value set in the
+ station.
+
+setmultipledtim
+ This command is used to set the multiple dtim value in the
+ station.
+ where the value is 1,2,3,4,5,0xfffe
+ 0xfffe means the firmware will use listen interval in association
+ command for waking up
+
+getmultipledtim
+ This command is used to get the multiple dtim value set in the station.
+
+atimwindow
+ This command is used to set the atim value in the
+ station.
+
+ where the value ranges between 0 - 50
+
+deauth
+ This command is used to send the de-authentication to the AP with which
+ the station is associated. This command is valid only when
+ station is in Infrastructure mode.
+
+ Note: This command is available only when STA is connected.
+
+adhocstop
+ This command is used to stop beacon transmission from the station and
+ go into idle state in ad-hoc mode.
+
+ Note: This command is available only when STA is connected.
+
+radioon
+ This command is used to turn on the RF antenna.
+
+radiooff
+ This command is sued to turn off the RF antenna.
+
+scanmode
+ This command is used to set the station to scan for either IBSS
+ networks or BSS networks or both BSS and IBSS networks. This
+ command can be used with sub commands,
+
+ where the value for
+ bss -- Scan All the BSS networks.
+ ibss -- Scan All the IBSS networks.
+ any -- Scan both BSS and IBSS networks.
+
+
+
+setwpaie
+ This command is used by WPA supplicant to send the WPA-IE to the driver.
+
+wlanidle-off
+ This command is used to get into idle state.
+
+ Note: This command is available only when STA is connected.
+
+wlanidle-on
+ This command is used to get off the idle state.
+
+ Note: This command is available only when STA is connected.
+
+
+getlog
+ This command is used to get the 802.11 statistics available in the
+ station.
+
+ Note: This command is available only when STA is connected.
+
+getadhocstatus
+ This command is used to get the ad-hoc Network Status.
+
+ The various status codes are:
+ AdhocStarted
+ AdhocJoined
+ AdhocIdle
+ InfraMode
+ AutoUnknownMode
+
+ Note: This command is available only when STA is connected.
+
+adhocgrate
+ This command is used to enable(1) g_rate, Disable(0) g_rate
+ and request(2) the status which g_rate is disabled/enabled,
+ for Ad-hoc creator.
+
+ where value is:-
+ 0 -- Disabled
+ 1 -- Enabled
+ 2 -- Get
+
+ledgpio
+ This command is used to set/get LEDs.
+
+ iwpriv ethX ledgpio <LEDs>
+ will set the corresponding LED for the GPIO Line.
+
+ iwpriv ethX ledgpio
+ will give u which LEDs are Enabled.
+
+ Usage:
+ iwpriv eth1 ledgpio 1 0 2 1 3 4
+ will enable
+ LED 1 -> GPIO 0
+ LED 2 -> GPIO 1
+ LED 3 -> GPIO 4
+
+ iwpriv eth1 ledgpio
+ shows LED information in the format as mentioned above.
+
+ Note: LED0 is invalid
+ Note: Maximum Number of LEDs are 16.
+
+inactivityto
+ This command is used by the host to set/get the inactivity timeout value,
+ which specifies when WLAN device is put to sleep.
+
+ Usage:
+ iwpriv ethX inactivityto [<timeout>]
+
+ where the parameter are:
+ timeout: timeout value in milliseconds.
+
+ Example:
+ iwpriv eth1 inactivityto
+ "get the timeout value"
+
+ iwpriv eth1 inactivityto X
+ "set timeout value to X ms"
+
+
+sleeppd
+ This command is used to configure the sleep period of the WLAN device.
+
+ Usage:
+ iwpriv ethX sleeppd [<sleep period>]
+
+ where the parameter are:
+ Period: sleep period in milliseconds. Range 10~60.
+
+ Example:
+ iwpriv eth1 sleeppd 10
+ "set period as 10 ms"
+ iwpriv eth1 sleeppd
+ "get the sleep period configuration"
+
+enable11d
+ This command is used to control 11d
+ where value is:-
+ 1 -- Enabled
+ 0 -- Disabled
+ 2 -- Get
+
+
+
+
+tpccfg
+ Enables or disables automatic transmit power control.
+
+ The first parameter turns this feature on (1) or off (0). When turning
+ on, the user must also supply four more parameters in the following
+ order:
+ -UseSNR (Use SNR (in addition to PER) for TPC algorithm),
+ -P0 (P0 power level for TPC),
+ -P1 (P1 power level for TPC),
+ -P2 (P2 power level for TPC).
+
+ Usage:
+ iwpriv ethX tpccfg: Get current configuration
+ iwpriv ethX tpccfg 0: disable auto TPC
+ iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR;
+ P0=0x05; P1=0x0a; P2=0x0d;
+ iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR;
+ P0=0x05; P1=0x0a; P2=0x0d.
+
+powercfg
+ Enables or disables power adaptation.
+
+ The first parameter turns this feature on (1) or off (0). When turning
+ on, the user must also supply three more parameters in the following
+ order:
+ -P0 (P0 power level for Power Adaptation),
+ -P1 (P1 power level for Power Adaptation),
+ -P2 (P2 power level for Power Adaptation).
+
+ Usage:
+ iwpriv ethX powercfg: Get current configuration
+ iwpriv ethX powercfg 0: disable power adaptation
+ iwpriv ethX powercfg 1 0x0d 0x0f 0x12: enable power adaptation;
+ P0=0x0d; P1=0x0f; P2=0x12.
+
+getafc
+ This command returns automatic frequency control parameters. It returns
+ three integers:
+ -P0: automatic is on (1), or off (0),
+ -P1: current timing offset in PPM (part per million), and
+ -P2: current frequency offset in PPM.
+
+setafc
+ Set automatic frequency control options.
+
+ The first parameter turns automatic on (1) or off (0).
+ The user must supply two more parameters in either case, in the following
+ order:
+
+ When auto is on:
+
+ -P0 (automatic adjustment frequency threshold in PPM),
+ -P1 (automatic adjustment period in beacon period),
+
+ When auto is off:
+
+ -P0 (manual adjustment timing offset in PPM), and
+ -P1 (manual adjustment frequency offset in PPM).
+
+ Usage:
+ iwpriv ethX setafc 0 10 10: manual adjustment, both timing and frequcncy
+ offset are 10 PPM.
+
+ iwpriv ethX setafc 1 10 10 enable afc, automatic adjustment,
+ frequency threshold 10 PPM, for every 10 beacon periods.
+
+
+
+scanprobes
+ This command sets number of probe requests per channel.
+
+ Usage:
+ iwpriv ethX scanprobes 3 (set scan probes to 3)
+ iwpriv ethX scanprobes (get scan probes)
+
+lolisteninter
+ This command sets the value of listen interval.
+
+ Usage:
+ iwpriv ethX lolisteninter 234 (set the lolisteninter to 234)
+ iwpriv ethX lolisteninter (get the lolisteninter value)
+
+rateadapt
+ This command sets the data rates bitmap.
+ Where <n>
+ 0: Disable auto rate adapt
+ 1: Enable auto rate adapt
+
+ <m>
+ data rate bitmap
+ Bit Data rate
+ 0 1 Mbps
+ 1 2 Mbps
+ 2 5.5 Mbps
+ 3 11 Mbps
+ 4 Reserved
+ 5 6 Mbps
+ 6 9 Mbps
+ 7 12 Mbps
+ 8 18 Mbps
+ 9 24 Mbps
+ 10 36 Mbps
+ 11 48 Mbps
+ 12 54 Mbps
+ 12-15 Reserved
+
+ Usage:
+ iwpriv ethX rateadapt
+ read the currect data rate setting
+ iwpriv ethX rateadapt 1 0x07
+ enable auto data rate adapt and
+ data rates are 1Mbps, 2Mbsp and 5.5Mbps
+
+
+txcontrol
+ This command is used to set the Tx rate, ack policy, and retry limit on a per packet basis.
+
+ Where value <n> is:
+ if bit[4] == 1:
+ bit[3:0] -- 0 1 2 3 4 5 6 7 8 9 10 11 12 13-16
+ Data Rate(Mbps) -- 1 2 5.5 11 Rsv 6 9 12 18 24 36 48 54 Rsv
+
+ bit[12:8]
+ if bit[12] == 1, bit[11:8] specifies the Tx retry limit.
+
+ bit[14:13] specifies per packet ack policy:
+ bit[14:13]
+ 1 0 use immediate ack policy for this packet
+ 1 1 use no ack policy for this packet
+ 0 x use the per-packet ack policy setting
+
+ Usage:
+ iwpriv ethX txcontrol 0x7513
+ Use no-ack policy, 5 retires for Tx, 11Mbps rate
+
+
+
+psnullinterval
+ This command is used to set/request NULL package interval for Power Save
+ under infrastructure mode.
+
+ where value is:-
+ -1 -- Disabled
+ n>0 -- Set interval as n (seconds)
+
+prescan
+ This command is used to enable (1)/disable(0) auto prescan before assoicate to the ap
+
+ where value is:-
+ 0 -- Disabled
+ 1 -- Enabled
+ 2 -- Get
+
+getrxinfo
+ This command gets non average value of Signal to Noise Ratio of Data and rate index.
+
+ The following table shows RateIndex and Rate
+
+ RateIndex Data rate
+ 0 1 Mbps
+ 1 2 Mbps
+ 2 5.5 Mbps
+ 3 11 Mbps
+ 4 Reserved
+ 5 6 Mbps
+ 6 9 Mbps
+ 7 12 Mbps
+ 8 18 Mbps
+ 9 24 Mbps
+ 10 36 Mbps
+ 11 48 Mbps
+ 12 54 Mbps
+ 13-15 Reserved
+
+gettxrate
+ This command gets current Tx rate index of the first packet associated with Rate Adaptation.
+
+ The following table shows RateIndex and Rate
+
+ RateIndex Data rate
+ 0 1 Mbps
+ 1 2 Mbps
+ 2 5.5 Mbps
+ 3 11 Mbps
+ 4 Reserved
+ 5 6 Mbps
+ 6 9 Mbps
+ 7 12 Mbps
+ 8 18 Mbps
+ 9 24 Mbps
+ 10 36 Mbps
+ 11 48 Mbps
+ 12 54 Mbps
+ 13-15 Reserved
+
+bcninterval
+ This command is used to sets beacon interval in adhoc mode when an argument is given, and gets current adhoc
+ beacon interval when no argument is given. The valid beacon interval is between 20 - 1000,
+ default beacon interval is 100.
+
+ Usage:
+ iwpriv ethX bcninterval 100 (set adhoc beacon interval to 100)
+ iwpriv ethX bcninterval (get adhoc beacon interval)
+
+fwt_add
+ This command is used to insert an entry into the FWT table. The list of
+ parameters must follow the following structure:
+
+ iwpriv ethX fwt_add da ra [metric dir ssn dsn hopcount ttl expiration sleepmode snr]
+
+ The parameters between brackets are optional, but they must appear in
+ the order specified. For example, if you want to specify the metric,
+ you must also specify the dir, ssn, and dsn but you need not specify the
+ hopcount, expiration, sleepmode, or snr. Any unspecified parameters
+ will be assigned the defaults specified below.
+
+ The different parameters are:-
+ da -- DA MAC address in the form 00:11:22:33:44:55
+ ra -- RA MAC address in the form 00:11:22:33:44:55
+ metric -- route metric (cost: smaller-metric routes are
+ preferred, default is 0)
+ dir -- direction (1 for direct, 0 for reverse,
+ default is 1)
+ ssn -- Source Sequence Number (time at the RA for
+ reverse routes. Default is 0)
+ dsn -- Destination Sequence Number (time at the DA
+ for direct routes. Default is 0)
+ hopcount -- hop count (currently unused, default is 0)
+ ttl -- TTL (Only used in reverse entries)
+ expiration -- entry expiration (in ticks, where a tick is
+ 1024us, or ~ 1ms. Use 0 for an indefinite
+ entry, default is 0)
+ sleepmode -- RA's sleep mode (currently unused, default is
+ 0)
+ snr -- SNR in the link to RA (currently unused,
+ default is 0)
+
+ The command does not return anything.
+
+fwt_del
+ This command is used to remove an entry to the FWT table. The list of
+ parameters must follow the following structure:
+
+ iwpriv ethX fwt_del da ra [dir]
+
+ where the different parameters are:-
+ da -- DA MAC address (in the form "00:11:22:33:44:55")
+ ra -- RA MAC address (in the form "00:11:22:33:44:55")
+ dir -- direction (1 for direct, 0 for reverse,
+ default is 1)
+
+ The command does not return anything.
+
+fwt_lookup
+ This command is used to get the best route in the FWT table to a given
+ host. The only parameter is the MAC address of the host that is being
+ looked for.
+
+ iwpriv ethX fwt_lookup da
+
+ where:-
+ da -- DA MAC address (in the form "00:11:22:33:44:55")
+
+ The command returns an output string identical to the one returned by
+ fwt_list described below.
+
+
+fwt_list
+ This command is used to list a route from the FWT table. The only
+ parameter is the index into the table. If you want to list all the
+ routes in a table, start with index=0, and keep listing until you get a
+ "(null)" string. Note that the indicies may change as the fwt is
+ updated. It is expected that most users will not use fwt_list directly,
+ but that a utility similar to the traditional route command will be used
+ to invoke fwt_list over and over.
+
+ iwpriv ethX fwt_list index
+
+ The output is a string of the following form:
+
+ da ra metric dir ssn dsn hopcount ttl expiration sleepmode snr
+
+ where the different fields are:-
+ da -- DA MAC address (in the form "00:11:22:33:44:55")
+ ra -- RA MAC address (in the form "00:11:22:33:44:55")
+ metric -- route metric (cost: smaller-metric routes are preferred)
+ dir -- direction (1 for direct, 0 for reverse)
+ ssn -- Source Sequence Number (time at the RA for reverse routes)
+ dsn -- Destination Sequence Number (time at the DA for direct routes)
+ hopcount -- hop count (currently unused)
+ ttl -- TTL (only used in reverse entries)
+ expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+ sleepmode -- RA's sleep mode (currently unused)
+ snr -- SNR in the link to RA (currently unused)
+
+fwt_list_route
+ This command is used to list a route from the FWT table. The only
+ parameter is the route ID. If you want to list all the routes in a
+ table, start with rid=0, and keep incrementing rid until you get a
+ "(null)" string. This function is similar to fwt_list. The only
+ difference is the output format. Also note that this command is meant
+ for debugging. It is expected that users will use fwt_lookup and
+ fwt_list. One important reason for this is that the route id may change
+ as the route table is altered.
+
+ iwpriv ethX fwt_list_route rid
+
+ The output is a string of the following form:
+
+ da metric dir nid ssn dsn hopcount ttl expiration
+
+ where the different fields are:-
+ da -- DA MAC address (in the form "00:11:22:33:44:55")
+ metric -- route metric (cost: smaller-metric routes are preferred)
+ dir -- direction (1 for direct, 0 for reverse)
+ nid -- Next-hop (neighbor) host ID (nid)
+ ssn -- Source Sequence Number (time at the RA for reverse routes)
+ dsn -- Destination Sequence Number (time at the DA for direct routes)
+ hopcount -- hop count (currently unused)
+ ttl -- TTL count (only used in reverse entries)
+ expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+
+fwt_list_neigh
+ This command is used to list a neighbor from the FWT table. The only
+ parameter is the neighbor ID. If you want to list all the neighbors in a
+ table, start with nid=0, and keep incrementing nid until you get a
+ "(null)" string. Note that the nid from a fwt_list_route command can be
+ used as an input to this command. Also note that this command is meant
+ mostly for debugging. It is expected that users will use fwt_lookup.
+ One important reason for this is that the neighbor id may change as the
+ neighbor table is altered.
+
+ iwpriv ethX fwt_list_neigh nid
+
+ The output is a string of the following form:
+
+ ra sleepmode snr references
+
+ where the different fields are:-
+ ra -- RA MAC address (in the form "00:11:22:33:44:55")
+ sleepmode -- RA's sleep mode (currently unused)
+ snr -- SNR in the link to RA (currently unused)
+ references -- RA's reference counter
+
+fwt_reset
+ This command is used to reset the FWT table, getting rid of all the
+ entries. There are no input parameters.
+
+ iwpriv ethX fwt_reset
+
+ The command does not return anything.
+
+fwt_cleanup
+ This command is used to perform user-based garbage recollection. The
+ FWT table is checked, and all the entries that are expired or invalid
+ are cleaned. Note that this is exported to the driver for debugging
+ purposes, as garbage collection is also fired by the firmware when in
+ space problems. There are no input parameters.
+
+ iwpriv ethX fwt_cleanup
+
+ The command does returns the number of invalid/expired routes deleted.
+
+fwt_time
+ This command returns a card's internal time representation. It is this
+ time that is used to represent the expiration times of FWT entries. The
+ number is not consistent from card to card; it is simply a timer count.
+ The fwt_time command is used to inspect the timer so that expiration
+ times reported by fwt_list can be properly interpreted.
+
+ iwpriv ethX fwt_time
+
+mesh_get_ttl
+
+ The mesh ttl is the number of hops a mesh packet can traverse before it
+ is dropped. This parameter is used to prevent infinite loops in the
+ mesh network. The value returned by this function is the ttl assigned
+ to all mesh packets. Currently there is no way to control the ttl on a
+ per packet or per socket basis.
+
+ iwpriv ethX mesh_get_ttl
+
+mesh_set_ttl ttl
+
+ Set the ttl. The argument must be between 0 and 255.
+
+ iwpriv ethX mesh_set_ttl <ttl>
+
+=========================
+ETHTOOL
+=========================
+
+
+Use the -i option to retrieve version information from the driver.
+
+# ethtool -i eth0
+driver: libertas
+version: COMM-USB8388-318.p4
+firmware-version: 5.110.7
+bus-info:
+
+Use the -e option to read the EEPROM contents of the card.
+
+ Usage:
+ ethtool -e ethX [raw on|off] [offset N] [length N]
+
+ -e retrieves and prints an EEPROM dump for the specified ethernet
+ device. When raw is enabled, then it dumps the raw EEPROM data
+ to stdout. The length and offset parameters allow dumping cer-
+ tain portions of the EEPROM. Default is to dump the entire EEP-
+ ROM.
+
+# ethtool -e eth0 offset 0 length 16
+Offset Values
+------ ------
+0x0000 38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00
+
+========================
+DEBUGFS COMMANDS
+========================
+
+those commands are used via debugfs interface
+
+===========
+rdmac
+rdbbp
+rdrf
+ These commands are used to read the MAC, BBP and RF registers from the
+ card. These commands take one parameter that specifies the offset
+ location that is to be read. This parameter must be specified in
+ hexadecimal (its possible to preceed preceding the number with a "0x").
+
+ Path: /debugfs/libertas_wireless/ethX/registers/
+
+ Usage:
+ echo "0xa123" > rdmac ; cat rdmac
+ echo "0xa123" > rdbbp ; cat rdbbp
+ echo "0xa123" > rdrf ; cat rdrf
+wrmac
+wrbbp
+wrrf
+ These commands are used to write the MAC, BBP and RF registers in the
+ card. These commands take two parameters that specify the offset
+ location and the value that is to be written. This parameters must
+ be specified in hexadecimal (its possible to preceed the number
+ with a "0x").
+
+ Usage:
+ echo "0xa123 0xaa" > wrmac
+ echo "0xa123 0xaa" > wrbbp
+ echo "0xa123 0xaa" > wrrf
+
+sleepparams
+ This command is used to set the sleepclock configurations
+
+ Path: /debugfs/libertas_wireless/ethX/
+
+ Usage:
+ cat sleepparams: reads the current sleepclock configuration
+
+ echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration.
+
+ where:
+ p1 is Sleep clock error in ppm (0-65535)
+ p2 is Wakeup offset in usec (0-65535)
+ p3 is Clock stabilization time in usec (0-65535)
+ p4 is Control periodic calibration (0-2)
+ p5 is Control the use of external sleep clock (0-2)
+ p6 is reserved for debug (0-65535)
+
+subscribed_events
+
+ The subscribed_events directory contains the interface for the
+ subscribed events API.
+
+ Path: /debugfs/libertas_wireless/ethX/subscribed_events/
+
+ Each event is represented by a filename. Each filename consists of the
+ following three fields:
+ Value Frequency Subscribed
+
+ To read the current values for a given event, do:
+ cat event
+ To set the current values, do:
+ echo "60 2 1" > event
+
+ Frequency field specifies the reporting frequency for this event.
+ If it is set to 0, then the event is reported only once, and then
+ automatically unsubscribed. If it is set to 1, then the event is
+ reported every time it occurs. If it is set to N, then the event is
+ reported every Nth time it occurs.
+
+ beacon_missed
+ Value field specifies the number of consecutive missing beacons which
+ triggers the LINK_LOSS event. This event is generated only once after
+ which the firmware resets its state. At initialization, the LINK_LOSS
+ event is subscribed by default. The default value of MissedBeacons is
+ 60.
+
+ failure_count
+ Value field specifies the consecutive failure count threshold which
+ triggers the generation of the MAX_FAIL event. Once this event is
+ generated, the consecutive failure count is reset to 0.
+ At initialization, the MAX_FAIL event is NOT subscribed by
+ default.
+
+ high_rssi
+ This event is generated when the average received RSSI in beacons goes
+ above a threshold, specified by Value.
+
+ low_rssi
+ This event is generated when the average received RSSI in beacons goes
+ below a threshold, specified by Value.
+
+ high_snr
+ This event is generated when the average received SNR in beacons goes
+ above a threshold, specified by Value.
+
+ low_snr
+ This event is generated when the average received SNR in beacons goes
+ below a threshold, specified by Value.
+
+extscan
+ This command is used to do a specific scan.
+
+ Path: /debugfs/libertas_wireless/ethX/
+
+ Usage: echo "SSID" > extscan
+
+ Example:
+ echo "LINKSYS-AP" > extscan
+
+ To see the results of use getscantable command.
+
+getscantable
+
+ Display the current contents of the driver scan table (ie. get the
+ scan results).
+
+ Path: /debugfs/libertas_wireless/ethX/
+
+ Usage:
+ cat getscantable
+
+setuserscan
+ Initiate a customized scan and retrieve the results
+
+
+ Path: /debugfs/libertas_wireless/ethX/
+
+ Usage:
+ echo "[ARGS]" > setuserscan
+
+ where [ARGS]:
+
+ chan=[chan#][band][mode] where band is [a,b,g] and mode is
+ blank for active or 'p' for passive
+ bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan
+ ssid="[SSID]" specify a SSID filter for the scan
+ keep=[0 or 1] keep the previous scan results (1), discard (0)
+ dur=[scan time] time to scan for each channel in milliseconds
+ probes=[#] number of probe requests to send on each chan
+ type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any)
+
+ Any combination of the above arguments can be supplied on the command line.
+ If the chan token is absent, a full channel scan will be completed by
+ the driver. If the dur or probes tokens are absent, the driver default
+ setting will be used. The bssid and ssid fields, if blank,
+ will produce an unfiltered scan. The type field will default to 3 (Any)
+ and the keep field will default to 0 (Discard).
+
+ Examples:
+ 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band:
+ echo "chan=1g,6g,11g" > setuserscan
+
+ 2) Perform a passive scan on channel 11 for 20 ms:
+ echo "chan=11gp dur=20" > setuserscan
+
+ 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
+ channel 36 in the 'a' band:
+
+ echo "chan=1g,6g,11g,36ap" > setuserscan
+
+ 4) Perform an active scan on channel 6 and 36 for a specific SSID:
+ echo "chan=6g,36a ssid="TestAP"" > setuserscan
+
+ 5) Scan all available channels (B/G, A bands) for a specific BSSID, keep
+ the current scan table intact, update existing or append new scan data:
+ echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
+
+ 6) Scan channel 6, for all infrastructure networks, sending two probe
+ requests. Keep the previous scan table intact. Update any duplicate
+ BSSID/SSID matches with the new scan data:
+ echo "chan=6g type=1 probes=2 keep=1" > setuserscan
+
+ All entries in the scan table (not just the new scan data when keep=1)
+ will be displayed upon completion by use of the getscantable ioctl.
+
+==============================================================================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
new file mode 100644
index 000000000000..b55c7f57aca8
--- /dev/null
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -0,0 +1,588 @@
+/* Copyright (C) 2006, Red Hat, Inc. */
+
+#include <linux/bitops.h>
+#include <net/ieee80211.h>
+
+#include "assoc.h"
+#include "join.h"
+#include "decl.h"
+#include "hostcmd.h"
+#include "host.h"
+
+
+static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static int assoc_helper_essid(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ int i;
+
+ ENTER();
+
+ lbs_pr_debug(1, "New SSID requested: %s\n", assoc_req->ssid.ssid);
+ if (assoc_req->mode == wlan802_11infrastructure) {
+ if (adapter->prescan) {
+ libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
+ }
+
+ i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
+ NULL, wlan802_11infrastructure);
+ if (i >= 0) {
+ lbs_pr_debug(1,
+ "SSID found in scan list ... associating...\n");
+
+ ret = wlan_associate(priv, &adapter->scantable[i]);
+ if (ret == 0) {
+ memcpy(&assoc_req->bssid,
+ &adapter->scantable[i].macaddress,
+ ETH_ALEN);
+ }
+ } else {
+ lbs_pr_debug(1, "SSID '%s' not found; cannot associate\n",
+ assoc_req->ssid.ssid);
+ }
+ } else if (assoc_req->mode == wlan802_11ibss) {
+ /* Scan for the network, do not save previous results. Stale
+ * scan data will cause us to join a non-existant adhoc network
+ */
+ libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
+
+ /* Search for the requested SSID in the scan table */
+ i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
+ wlan802_11ibss);
+ if (i >= 0) {
+ lbs_pr_debug(1, "SSID found at %d in List, so join\n", ret);
+ libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+ } else {
+ /* else send START command */
+ lbs_pr_debug(1, "SSID not found in list, so creating adhoc"
+ " with SSID '%s'\n", assoc_req->ssid.ssid);
+ libertas_start_adhoc_network(priv, &assoc_req->ssid);
+ }
+ memcpy(&assoc_req->bssid, &adapter->current_addr, ETH_ALEN);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+
+static int assoc_helper_bssid(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i, ret = 0;
+
+ ENTER();
+
+ lbs_pr_debug(1, "ASSOC: WAP: BSSID = " MAC_FMT "\n",
+ MAC_ARG(assoc_req->bssid));
+
+ /* Search for index position in list for requested MAC */
+ i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
+ assoc_req->mode);
+ if (i < 0) {
+ lbs_pr_debug(1, "ASSOC: WAP: BSSID " MAC_FMT " not found, "
+ "cannot associate.\n", MAC_ARG(assoc_req->bssid));
+ goto out;
+ }
+
+ if (assoc_req->mode == wlan802_11infrastructure) {
+ ret = wlan_associate(priv, &adapter->scantable[i]);
+ lbs_pr_debug(1, "ASSOC: return from wlan_associate(bssd) was %d\n", ret);
+ } else if (assoc_req->mode == wlan802_11ibss) {
+ libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+ }
+ memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid,
+ sizeof(struct WLAN_802_11_SSID));
+
+out:
+ LEAVE();
+ return ret;
+}
+
+
+static int assoc_helper_associate(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ int ret = 0, done = 0;
+
+ /* If we're given and 'any' BSSID, try associating based on SSID */
+
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+ if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN)
+ && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) {
+ ret = assoc_helper_bssid(priv, assoc_req);
+ done = 1;
+ if (ret) {
+ lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
+ }
+ }
+ }
+
+ if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+ ret = assoc_helper_essid(priv, assoc_req);
+ if (ret) {
+ lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
+ }
+ }
+
+ return ret;
+}
+
+
+static int assoc_helper_mode(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ if (assoc_req->mode == adapter->inframode) {
+ LEAVE();
+ return 0;
+ }
+
+ if (assoc_req->mode == wlan802_11infrastructure) {
+ if (adapter->psstate != PS_STATE_FULL_POWER)
+ libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+ adapter->psmode = wlan802_11powermodecam;
+ }
+
+ adapter->inframode = assoc_req->mode;
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_snmp_mib,
+ 0, cmd_option_waitforrsp,
+ OID_802_11_INFRASTRUCTURE_MODE,
+ (void *) assoc_req->mode);
+
+ LEAVE();
+ return ret;
+}
+
+
+static int assoc_helper_wep_keys(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i;
+ int ret = 0;
+
+ ENTER();
+
+ /* Set or remove WEP keys */
+ if ( assoc_req->wep_keys[0].len
+ || assoc_req->wep_keys[1].len
+ || assoc_req->wep_keys[2].len
+ || assoc_req->wep_keys[3].len) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_set_wep,
+ cmd_act_add,
+ cmd_option_waitforrsp,
+ 0, assoc_req);
+ } else {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_set_wep,
+ cmd_act_remove,
+ cmd_option_waitforrsp,
+ 0, NULL);
+ }
+
+ if (ret)
+ goto out;
+
+ /* enable/disable the MAC's WEP packet filter */
+ if (assoc_req->secinfo.WEPstatus == wlan802_11WEPenabled)
+ adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
+ else
+ adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
+ ret = libertas_set_mac_packet_filter(priv);
+ if (ret)
+ goto out;
+
+ mutex_lock(&adapter->lock);
+
+ /* Copy WEP keys into adapter wep key fields */
+ for (i = 0; i < 4; i++) {
+ memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
+ sizeof(struct WLAN_802_11_KEY));
+ }
+ adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
+
+ mutex_unlock(&adapter->lock);
+
+out:
+ LEAVE();
+ return ret;
+}
+
+static int assoc_helper_secinfo(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ memcpy(&adapter->secinfo, &assoc_req->secinfo,
+ sizeof(struct wlan_802_11_security));
+
+ ret = libertas_set_mac_packet_filter(priv);
+
+ LEAVE();
+ return ret;
+}
+
+
+static int assoc_helper_wpa_keys(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ int ret = 0;
+
+ ENTER();
+
+ /* enable/Disable RSN */
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_enable_rsn,
+ cmd_act_set,
+ cmd_option_waitforrsp,
+ 0, assoc_req);
+ if (ret)
+ goto out;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_key_material,
+ cmd_act_set,
+ cmd_option_waitforrsp,
+ 0, assoc_req);
+
+out:
+ LEAVE();
+ return ret;
+}
+
+
+static int assoc_helper_wpa_ie(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
+ memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
+ adapter->wpa_ie_len = assoc_req->wpa_ie_len;
+ } else {
+ memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
+ adapter->wpa_ie_len = 0;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+
+static int should_deauth_infrastructure(wlan_adapter *adapter,
+ struct assoc_request * assoc_req)
+{
+ if (adapter->connect_status != libertas_connected)
+ return 0;
+
+ if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+ lbs_pr_debug(1, "Deauthenticating due to new SSID in "
+ " configuration request.\n");
+ return 1;
+ }
+
+ if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+ if (adapter->secinfo.authmode !=
+ assoc_req->secinfo.authmode) {
+ lbs_pr_debug(1, "Deauthenticating due to updated security "
+ "info in configuration request.\n");
+ return 1;
+ }
+ }
+
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+ lbs_pr_debug(1, "Deauthenticating due to new BSSID in "
+ " configuration request.\n");
+ return 1;
+ }
+
+ /* FIXME: deal with 'auto' mode somehow */
+ if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+ if (assoc_req->mode != wlan802_11infrastructure)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int should_stop_adhoc(wlan_adapter *adapter,
+ struct assoc_request * assoc_req)
+{
+ if (adapter->connect_status != libertas_connected)
+ return 0;
+
+ if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
+ return 1;
+ if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
+ sizeof(struct WLAN_802_11_SSID)))
+ return 1;
+
+ /* FIXME: deal with 'auto' mode somehow */
+ if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+ if (assoc_req->mode != wlan802_11ibss)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void wlan_association_worker(struct work_struct *work)
+{
+ wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
+ wlan_adapter *adapter = priv->adapter;
+ struct assoc_request * assoc_req = NULL;
+ int ret = 0;
+ int find_any_ssid = 0;
+
+ ENTER();
+
+ mutex_lock(&adapter->lock);
+ assoc_req = adapter->assoc_req;
+ adapter->assoc_req = NULL;
+ mutex_unlock(&adapter->lock);
+
+ if (!assoc_req) {
+ LEAVE();
+ return;
+ }
+
+ lbs_pr_debug(1, "ASSOC: starting new association request: flags = 0x%lX\n",
+ assoc_req->flags);
+
+ /* If 'any' SSID was specified, find an SSID to associate with */
+ if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
+ && !assoc_req->ssid.ssidlength)
+ find_any_ssid = 1;
+
+ /* But don't use 'any' SSID if there's a valid locked BSSID to use */
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+ if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN)
+ && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN))
+ find_any_ssid = 0;
+ }
+
+ if (find_any_ssid) {
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
+
+ ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
+ assoc_req->mode, &new_mode);
+ if (ret) {
+ lbs_pr_debug(1, "Could not find best network\n");
+ ret = -ENETUNREACH;
+ goto out;
+ }
+
+ /* Ensure we switch to the mode of the AP */
+ if (assoc_req->mode == wlan802_11autounknown) {
+ set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+ assoc_req->mode = new_mode;
+ }
+ }
+
+ /*
+ * Check if the attributes being changing require deauthentication
+ * from the currently associated infrastructure access point.
+ */
+ if (adapter->inframode == wlan802_11infrastructure) {
+ if (should_deauth_infrastructure(adapter, assoc_req)) {
+ ret = libertas_send_deauthentication(priv);
+ if (ret) {
+ lbs_pr_debug(1, "Deauthentication due to new "
+ "configuration request failed: %d\n",
+ ret);
+ }
+ }
+ } else if (adapter->inframode == wlan802_11ibss) {
+ if (should_stop_adhoc(adapter, assoc_req)) {
+ ret = libertas_stop_adhoc_network(priv);
+ if (ret) {
+ lbs_pr_debug(1, "Teardown of AdHoc network due to "
+ "new configuration request failed: %d\n",
+ ret);
+ }
+
+ }
+ }
+
+ /* Send the various configuration bits to the firmware */
+ if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+ ret = assoc_helper_mode(priv, assoc_req);
+ if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
+ goto out;
+ }
+ }
+
+ if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
+ || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
+ ret = assoc_helper_wep_keys(priv, assoc_req);
+ if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
+ goto out;
+ }
+ }
+
+ if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+ ret = assoc_helper_secinfo(priv, assoc_req);
+ if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
+ goto out;
+ }
+ }
+
+ if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+ ret = assoc_helper_wpa_ie(priv, assoc_req);
+ if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
+ goto out;
+ }
+ }
+
+ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
+ || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+ ret = assoc_helper_wpa_keys(priv, assoc_req);
+ if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
+ goto out;
+ }
+ }
+
+ /* SSID/BSSID should be the _last_ config option set, because they
+ * trigger the association attempt.
+ */
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
+ || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+ int success = 1;
+
+ ret = assoc_helper_associate(priv, assoc_req);
+ if (ret) {
+ lbs_pr_debug(1, "ASSOC: association attempt unsuccessful: %d\n",
+ ret);
+ success = 0;
+ }
+
+ if (adapter->connect_status != libertas_connected) {
+ lbs_pr_debug(1, "ASSOC: assoication attempt unsuccessful, "
+ "not connected.\n");
+ success = 0;
+ }
+
+ if (success) {
+ lbs_pr_debug(1, "ASSOC: association attempt successful. "
+ "Associated to '%s' (" MAC_FMT ")\n",
+ assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid));
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_rssi,
+ 0, cmd_option_waitforrsp, 0, NULL);
+
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_get_log,
+ 0, cmd_option_waitforrsp, 0, NULL);
+ } else {
+
+ ret = -1;
+ }
+ }
+
+out:
+ if (ret) {
+ lbs_pr_debug(1, "ASSOC: reconfiguration attempt unsuccessful: %d\n",
+ ret);
+ }
+ kfree(assoc_req);
+ LEAVE();
+}
+
+
+/*
+ * Caller MUST hold any necessary locks
+ */
+struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
+{
+ struct assoc_request * assoc_req;
+
+ if (!adapter->assoc_req) {
+ adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL);
+ if (!adapter->assoc_req) {
+ lbs_pr_info("Not enough memory to allocate association"
+ " request!\n");
+ return NULL;
+ }
+ }
+
+ /* Copy current configuration attributes to the association request,
+ * but don't overwrite any that are already set.
+ */
+ assoc_req = adapter->assoc_req;
+ if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+ memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid,
+ adapter->curbssparams.ssid.ssidlength);
+ }
+
+ if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
+ assoc_req->channel = adapter->curbssparams.channel;
+
+ if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
+ assoc_req->mode = adapter->inframode;
+
+ if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+ memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
+ ETH_ALEN);
+ }
+
+ if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
+ sizeof(struct WLAN_802_11_KEY));
+ }
+ }
+
+ if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
+ assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
+
+ if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
+ memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
+ sizeof(struct WLAN_802_11_KEY));
+ }
+
+ if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+ memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
+ sizeof(struct WLAN_802_11_KEY));
+ }
+
+ if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+ memcpy(&assoc_req->secinfo, &adapter->secinfo,
+ sizeof(struct wlan_802_11_security));
+ }
+
+ if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+ memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
+ MAX_WPA_IE_LEN);
+ assoc_req->wpa_ie_len = adapter->wpa_ie_len;
+ }
+
+ return assoc_req;
+}
+
+
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
new file mode 100644
index 000000000000..2ffd82d99b34
--- /dev/null
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2006, Red Hat, Inc. */
+
+#ifndef _WLAN_ASSOC_H_
+#define _WLAN_ASSOC_H_
+
+#include "dev.h"
+
+void wlan_association_worker(struct work_struct *work);
+
+struct assoc_request * wlan_get_association_request(wlan_adapter *adapter);
+
+#define ASSOC_DELAY (HZ / 2)
+static inline void wlan_postpone_association_work(wlan_private *priv)
+{
+ if (priv->adapter->surpriseremoved)
+ return;
+ cancel_delayed_work(&priv->assoc_work);
+ queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
+}
+
+static inline void wlan_cancel_association_work(wlan_private *priv)
+{
+ cancel_delayed_work(&priv->assoc_work);
+ if (priv->adapter->assoc_req) {
+ kfree(priv->adapter->assoc_req);
+ priv->adapter->assoc_req = NULL;
+ }
+}
+
+#endif /* _WLAN_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
new file mode 100644
index 000000000000..bfdac58b5c06
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -0,0 +1,1958 @@
+/**
+ * This file contains the handling of command.
+ * It prepares command and sends it to firmware when it is ready.
+ */
+
+#include <net/iw_handler.h>
+#include "host.h"
+#include "hostcmd.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
+
+static u16 commands_allowed_in_ps[] = {
+ cmd_802_11_rssi,
+};
+
+/**
+ * @brief This function checks if the commans is allowed
+ * in PS mode not.
+ *
+ * @param command the command ID
+ * @return TRUE or FALSE
+ */
+static u8 is_command_allowed_in_ps(u16 command)
+{
+ int count = sizeof(commands_allowed_in_ps)
+ / sizeof(commands_allowed_in_ps[0]);
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (command == cpu_to_le16(commands_allowed_in_ps[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd)
+{
+ struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_get_hw_spec);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
+ memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
+ u16 action = cmd_action;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_802_11_ps_mode);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
+ S_DS_GEN);
+ psm->action = cpu_to_le16(cmd_action);
+ psm->multipledtim = 0;
+ switch (action) {
+ case cmd_subcmd_enter_ps:
+ lbs_pr_debug(1, "PS command:" "SubCode- Enter PS\n");
+ lbs_pr_debug(1, "locallisteninterval = %d\n",
+ adapter->locallisteninterval);
+
+ psm->locallisteninterval =
+ cpu_to_le16(adapter->locallisteninterval);
+ psm->nullpktinterval =
+ cpu_to_le16(adapter->nullpktinterval);
+ psm->multipledtim =
+ cpu_to_le16(priv->adapter->multipledtim);
+ break;
+
+ case cmd_subcmd_exit_ps:
+ lbs_pr_debug(1, "PS command:" "SubCode- Exit PS\n");
+ break;
+
+ case cmd_subcmd_sleep_confirmed:
+ lbs_pr_debug(1, "PS command: SubCode- sleep confirm\n");
+ break;
+
+ default:
+ break;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ u16 *timeout = pdata_buf;
+
+ cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
+ + S_DS_GEN);
+
+ cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action)
+ cmd->params.inactivity_timeout.timeout =
+ cpu_to_le16(*timeout);
+ else
+ cmd->params.inactivity_timeout.timeout = 0;
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_sleep_params(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
+
+ ENTER();
+
+ cmd->size =
+ cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
+ S_DS_GEN);
+ cmd->command = cpu_to_le16(cmd_802_11_sleep_params);
+
+ if (cmd_action == cmd_act_get) {
+ memset(&adapter->sp, 0, sizeof(struct sleep_params));
+ memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
+ sp->action = cpu_to_le16(cmd_action);
+ } else if (cmd_action == cmd_act_set) {
+ sp->action = cpu_to_le16(cmd_action);
+ sp->error = cpu_to_le16(adapter->sp.sp_error);
+ sp->offset = cpu_to_le16(adapter->sp.sp_offset);
+ sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime);
+ sp->calcontrol = (u8) adapter->sp.sp_calcontrol;
+ sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk;
+ sp->reserved = cpu_to_le16(adapter->sp.sp_reserved);
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_set_wep(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u32 cmd_act,
+ void * pdata_buf)
+{
+ struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct assoc_request * assoc_req = pdata_buf;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_802_11_set_wep);
+ cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_set_wep))
+ + S_DS_GEN);
+
+ if (cmd_act == cmd_act_add) {
+ int i;
+
+ if (!assoc_req) {
+ lbs_pr_debug(1, "Invalid association request!");
+ ret = -1;
+ goto done;
+ }
+
+ wep->action = cpu_to_le16(cmd_act_add);
+
+ /* default tx key index */
+ wep->keyindex = cpu_to_le16((u16)
+ (assoc_req->wep_tx_keyidx &
+ (u32)cmd_WEP_KEY_INDEX_MASK));
+
+ lbs_pr_debug(1, "Tx key Index: %u\n", wep->keyindex);
+
+ /* Copy key types and material to host command structure */
+ for (i = 0; i < 4; i++) {
+ struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i];
+
+ switch (pkey->len) {
+ case KEY_LEN_WEP_40:
+ wep->keytype[i] = cmd_type_wep_40_bit;
+ memmove(&wep->keymaterial[i], pkey->key,
+ pkey->len);
+ break;
+ case KEY_LEN_WEP_104:
+ wep->keytype[i] = cmd_type_wep_104_bit;
+ memmove(&wep->keymaterial[i], pkey->key,
+ pkey->len);
+ break;
+ case 0:
+ break;
+ default:
+ lbs_pr_debug(1, "Invalid WEP key %d length of %d\n",
+ i, pkey->len);
+ ret = -1;
+ goto done;
+ break;
+ }
+ }
+ } else if (cmd_act == cmd_act_remove) {
+ /* ACT_REMOVE clears _all_ WEP keys */
+ wep->action = cpu_to_le16(cmd_act_remove);
+
+ /* default tx key index */
+ wep->keyindex = cpu_to_le16((u16)
+ (adapter->wep_tx_keyidx &
+ (u32)cmd_WEP_KEY_INDEX_MASK));
+ }
+
+ ret = 0;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
+ wlan_adapter *adapter = priv->adapter;
+
+ cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) +
+ S_DS_GEN);
+ penableRSN->action = cpu_to_le16(cmd_action);
+ if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+ penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
+ } else {
+ penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
+ }
+
+ return 0;
+}
+
+
+static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
+ struct WLAN_802_11_KEY * pkey)
+{
+ pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
+
+ if (pkey->flags & KEY_INFO_WPA_ENABLED) {
+ pkeyparamset->keyinfo = cpu_to_le16(KEY_INFO_WPA_ENABLED);
+ } else {
+ pkeyparamset->keyinfo = cpu_to_le16(!KEY_INFO_WPA_ENABLED);
+ }
+
+ if (pkey->flags & KEY_INFO_WPA_UNICAST) {
+ pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
+ } else if (pkey->flags & KEY_INFO_WPA_MCAST) {
+ pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
+ }
+
+ pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkeyparamset->keylen = cpu_to_le16(pkey->len);
+ memcpy(pkeyparamset->key, pkey->key, pkey->len);
+ pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid)
+ + sizeof(pkeyparamset->keyinfo)
+ + sizeof(pkeyparamset->keylen)
+ + sizeof(pkeyparamset->key));
+}
+
+static int wlan_cmd_802_11_key_material(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action,
+ u32 cmd_oid, void *pdata_buf)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_key_material *pkeymaterial =
+ &cmd->params.keymaterial;
+ int ret = 0;
+ int index = 0;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_802_11_key_material);
+ pkeymaterial->action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == cmd_act_get) {
+ cmd->size = cpu_to_le16( S_DS_GEN
+ + sizeof (pkeymaterial->action));
+ ret = 0;
+ goto done;
+ }
+
+ memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
+
+ if (adapter->wpa_unicast_key.len) {
+ set_one_wpa_key(&pkeymaterial->keyParamSet[index],
+ &adapter->wpa_unicast_key);
+ index++;
+ }
+
+ if (adapter->wpa_mcast_key.len) {
+ set_one_wpa_key(&pkeymaterial->keyParamSet[index],
+ &adapter->wpa_mcast_key);
+ index++;
+ }
+
+ cmd->size = cpu_to_le16( S_DS_GEN
+ + sizeof (pkeymaterial->action)
+ + index * sizeof(struct MrvlIEtype_keyParamSet));
+
+ ret = 0;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+static int wlan_cmd_802_11_reset(wlan_private * priv,
+ struct cmd_ds_command *cmd, int cmd_action)
+{
+ struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
+
+ cmd->command = cpu_to_le16(cmd_802_11_reset);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
+ reset->action = cpu_to_le16(cmd_action);
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_get_log(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ cmd->command = cpu_to_le16(cmd_802_11_get_log);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_get_stat(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ cmd->command = cpu_to_le16(cmd_802_11_get_stat);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) +
+ S_DS_GEN);
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ int cmd_action,
+ int cmd_oid, void *pdata_buf)
+{
+ struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
+ wlan_adapter *adapter = priv->adapter;
+ u8 ucTemp;
+
+ ENTER();
+
+ lbs_pr_debug(1, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+
+ cmd->command = cpu_to_le16(cmd_802_11_snmp_mib);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_snmp_mib) +
+ S_DS_GEN);
+
+ switch (cmd_oid) {
+ case OID_802_11_INFRASTRUCTURE_MODE:
+ {
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode =
+ (enum WLAN_802_11_NETWORK_INFRASTRUCTURE) pdata_buf;
+ pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+ pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i);
+ pSNMPMIB->bufsize = sizeof(u8);
+ if (mode == wlan802_11infrastructure)
+ ucTemp = SNMP_MIB_VALUE_INFRA;
+ else
+ ucTemp = SNMP_MIB_VALUE_ADHOC;
+
+ memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
+
+ break;
+ }
+
+ case OID_802_11D_ENABLE:
+ {
+ u32 ulTemp;
+
+ pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i);
+
+ if (cmd_action == cmd_act_set) {
+ pSNMPMIB->querytype = cmd_act_set;
+ pSNMPMIB->bufsize = sizeof(u16);
+ ulTemp = *(u32 *)pdata_buf;
+ *((unsigned short *)(pSNMPMIB->value)) =
+ cpu_to_le16((u16) ulTemp);
+ }
+ break;
+ }
+
+ case OID_802_11_FRAGMENTATION_THRESHOLD:
+ {
+ u32 ulTemp;
+
+ pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i);
+
+ if (cmd_action == cmd_act_get) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_get);
+ } else if (cmd_action == cmd_act_set) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_set);
+ pSNMPMIB->bufsize =
+ cpu_to_le16(sizeof(u16));
+ ulTemp = *((u32 *) pdata_buf);
+ *((unsigned short *)(pSNMPMIB->value)) =
+ cpu_to_le16((u16) ulTemp);
+
+ }
+
+ break;
+ }
+
+ case OID_802_11_RTS_THRESHOLD:
+ {
+
+ u32 ulTemp;
+ pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i);
+
+ if (cmd_action == cmd_act_get) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_get);
+ } else if (cmd_action == cmd_act_set) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_set);
+ pSNMPMIB->bufsize =
+ cpu_to_le16(sizeof(u16));
+ ulTemp = *((u32 *)
+ pdata_buf);
+ *(unsigned short *)(pSNMPMIB->value) =
+ cpu_to_le16((u16) ulTemp);
+
+ }
+ break;
+ }
+ case OID_802_11_TX_RETRYCOUNT:
+ pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i);
+
+ if (cmd_action == cmd_act_get) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_get);
+ } else if (cmd_action == cmd_act_set) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_set);
+ pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
+ *((unsigned short *)(pSNMPMIB->value)) =
+ cpu_to_le16((u16) adapter->txretrycount);
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ lbs_pr_debug(1,
+ "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
+ cmd->command, cmd->size, cmd->seqnum, cmd->result);
+
+ lbs_pr_debug(1,
+ "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n",
+ pSNMPMIB->querytype, pSNMPMIB->oid, pSNMPMIB->bufsize,
+ *(u16 *) pSNMPMIB->value);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_radio_control(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ int cmd_action)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_radio_control *pradiocontrol =
+ &cmd->params.radio;
+
+ ENTER();
+
+ cmd->size =
+ cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
+ S_DS_GEN);
+ cmd->command = cpu_to_le16(cmd_802_11_radio_control);
+
+ pradiocontrol->action = cpu_to_le16(cmd_action);
+
+ switch (adapter->preamble) {
+ case cmd_type_short_preamble:
+ pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
+ break;
+
+ case cmd_type_long_preamble:
+ pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
+ break;
+
+ case cmd_type_auto_preamble:
+ default:
+ pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
+ break;
+ }
+
+ if (adapter->radioon)
+ pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
+ else
+ pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+
+ struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
+
+ ENTER();
+
+ cmd->size =
+ cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) +
+ S_DS_GEN);
+ cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power);
+ prtp->action = cmd_action;
+
+ lbs_pr_debug(1, "RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", cmd->size,
+ cmd->command, prtp->action);
+
+ switch (cmd_action) {
+ case cmd_act_tx_power_opt_get:
+ prtp->action = cpu_to_le16(cmd_act_get);
+ prtp->currentlevel = 0;
+ break;
+
+ case cmd_act_tx_power_opt_set_high:
+ prtp->action = cpu_to_le16(cmd_act_set);
+ prtp->currentlevel =
+ cpu_to_le16(cmd_act_tx_power_index_high);
+ break;
+
+ case cmd_act_tx_power_opt_set_mid:
+ prtp->action = cpu_to_le16(cmd_act_set);
+ prtp->currentlevel =
+ cpu_to_le16(cmd_act_tx_power_index_mid);
+ break;
+
+ case cmd_act_tx_power_opt_set_low:
+ prtp->action = cpu_to_le16(cmd_act_set);
+ prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
+ break;
+ }
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_rf_antenna(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant;
+
+ cmd->command = cpu_to_le16(cmd_802_11_rf_antenna);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) +
+ S_DS_GEN);
+
+ rant->action = cpu_to_le16(cmd_action);
+ if ((cmd_action == cmd_act_set_rx) ||
+ (cmd_action == cmd_act_set_tx)) {
+ rant->antennamode =
+ cpu_to_le16((u16) (*(u32 *) pdata_buf));
+ }
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_rate_adapt_rateset
+ *rateadapt = &cmd->params.rateset;
+ wlan_adapter *adapter = priv->adapter;
+
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
+ + S_DS_GEN);
+ cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset);
+
+ ENTER();
+
+ rateadapt->action = cmd_action;
+ rateadapt->enablehwauto = adapter->enablehwauto;
+ rateadapt->bitmap = adapter->ratebitmap;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_data_rate(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
+ wlan_adapter *adapter = priv->adapter;
+ u16 action = cmd_action;
+
+ ENTER();
+
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
+ S_DS_GEN);
+
+ cmd->command = cpu_to_le16(cmd_802_11_data_rate);
+
+ memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
+
+ pdatarate->action = cpu_to_le16(cmd_action);
+
+ if (action == cmd_act_set_tx_fix_rate) {
+ pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate);
+ lbs_pr_debug(1, "Setting FW for fixed rate 0x%02X\n",
+ adapter->datarate);
+ } else if (action == cmd_act_set_tx_auto) {
+ lbs_pr_debug(1, "Setting FW for AUTO rate\n");
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
+ wlan_adapter *adapter = priv->adapter;
+
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
+ S_DS_GEN);
+ cmd->command = cpu_to_le16(cmd_mac_multicast_adr);
+
+ pMCastAdr->action = cpu_to_le16(cmd_action);
+ pMCastAdr->nr_of_adrs =
+ cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
+ memcpy(pMCastAdr->maclist, adapter->multicastlist,
+ adapter->nr_of_multicastmacaddr * ETH_ALEN);
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_rf_channel(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ int option, void *pdata_buf)
+{
+ struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
+
+ cmd->command = cpu_to_le16(cmd_802_11_rf_channel);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel)
+ + S_DS_GEN);
+
+ if (option == cmd_opt_802_11_rf_channel_set) {
+ rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
+ }
+
+ rfchan->action = cpu_to_le16(option);
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_rssi(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ cmd->command = cpu_to_le16(cmd_802_11_rssi);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
+ cmd->params.rssi.N = priv->adapter->bcn_avg_factor;
+
+ /* reset Beacon SNR/NF/RSSI values */
+ adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
+ adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0;
+ adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
+ adapter->NF[TYPE_BEACON][TYPE_AVG] = 0;
+ adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
+ adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+
+ return 0;
+}
+
+static int wlan_cmd_reg_access(wlan_private * priv,
+ struct cmd_ds_command *cmdptr,
+ u8 cmd_action, void *pdata_buf)
+{
+ struct wlan_offset_value *offval;
+
+ ENTER();
+
+ offval = (struct wlan_offset_value *)pdata_buf;
+
+ switch (cmdptr->command) {
+ case cmd_mac_reg_access:
+ {
+ struct cmd_ds_mac_reg_access *macreg;
+
+ cmdptr->size =
+ cpu_to_le16(sizeof
+ (struct cmd_ds_mac_reg_access)
+ + S_DS_GEN);
+ macreg =
+ (struct cmd_ds_mac_reg_access *)&cmdptr->params.
+ macreg;
+
+ macreg->action = cpu_to_le16(cmd_action);
+ macreg->offset = cpu_to_le16((u16) offval->offset);
+ macreg->value = cpu_to_le32(offval->value);
+
+ break;
+ }
+
+ case cmd_bbp_reg_access:
+ {
+ struct cmd_ds_bbp_reg_access *bbpreg;
+
+ cmdptr->size =
+ cpu_to_le16(sizeof
+ (struct cmd_ds_bbp_reg_access)
+ + S_DS_GEN);
+ bbpreg =
+ (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
+ bbpreg;
+
+ bbpreg->action = cpu_to_le16(cmd_action);
+ bbpreg->offset = cpu_to_le16((u16) offval->offset);
+ bbpreg->value = (u8) offval->value;
+
+ break;
+ }
+
+ case cmd_rf_reg_access:
+ {
+ struct cmd_ds_rf_reg_access *rfreg;
+
+ cmdptr->size =
+ cpu_to_le16(sizeof
+ (struct cmd_ds_rf_reg_access) +
+ S_DS_GEN);
+ rfreg =
+ (struct cmd_ds_rf_reg_access *)&cmdptr->params.
+ rfreg;
+
+ rfreg->action = cpu_to_le16(cmd_action);
+ rfreg->offset = cpu_to_le16((u16) offval->offset);
+ rfreg->value = (u8) offval->value;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_mac_address(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ cmd->command = cpu_to_le16(cmd_802_11_mac_address);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ cmd->params.macadd.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == cmd_act_set) {
+ memcpy(cmd->params.macadd.macadd,
+ adapter->current_addr, ETH_ALEN);
+ lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6);
+ }
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ int cmd_action, void *pdata_buf)
+{
+ struct wlan_ioctl_regrdwr *ea = pdata_buf;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_802_11_eeprom_access);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
+ cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
+ cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
+ cmd->params.rdeeprom.value = 0;
+
+ return 0;
+}
+
+static int wlan_cmd_bt_access(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
+ lbs_pr_debug(1, "BT CMD(%d)\n", cmd_action);
+
+ cmd->command = cpu_to_le16(cmd_bt_access);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access)
+ + S_DS_GEN);
+ cmd->result = 0;
+ bt_access->action = cpu_to_le16(cmd_action);
+
+ switch (cmd_action) {
+ case cmd_act_bt_access_add:
+ memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
+ lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6);
+ break;
+ case cmd_act_bt_access_del:
+ memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
+ lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6);
+ break;
+ case cmd_act_bt_access_list:
+ bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
+ break;
+ case cmd_act_bt_access_reset:
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int wlan_cmd_fwt_access(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
+ lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
+
+ cmd->command = cpu_to_le16(cmd_fwt_access);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ if (pdata_buf)
+ memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
+ else
+ memset(fwt_access, 0, sizeof(*fwt_access));
+
+ fwt_access->action = cpu_to_le16(cmd_action);
+
+ return 0;
+}
+
+static int wlan_cmd_mesh_access(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
+ lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
+
+ cmd->command = cpu_to_le16(cmd_mesh_access);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ if (pdata_buf)
+ memcpy(mesh_access, pdata_buf, sizeof(*mesh_access));
+ else
+ memset(mesh_access, 0, sizeof(*mesh_access));
+
+ mesh_access->action = cpu_to_le16(cmd_action);
+
+ return 0;
+}
+
+void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail)
+{
+ unsigned long flags;
+ struct cmd_ds_command *cmdptr;
+
+ ENTER();
+
+ if (!cmdnode) {
+ lbs_pr_debug(1, "QUEUE_CMD: cmdnode is NULL\n");
+ goto done;
+ }
+
+ cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+ if (!cmdptr) {
+ lbs_pr_debug(1, "QUEUE_CMD: cmdptr is NULL\n");
+ goto done;
+ }
+
+ /* Exit_PS command needs to be queued in the header always. */
+ if (cmdptr->command == cmd_802_11_ps_mode) {
+ struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
+ if (psm->action == cmd_subcmd_exit_ps) {
+ if (adapter->psstate != PS_STATE_FULL_POWER)
+ addtail = 0;
+ }
+ }
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+
+ if (addtail)
+ list_add_tail((struct list_head *)cmdnode,
+ &adapter->cmdpendingq);
+ else
+ list_add((struct list_head *)cmdnode, &adapter->cmdpendingq);
+
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ lbs_pr_debug(1, "QUEUE_CMD: Inserted node=0x%x, cmd=0x%x in cmdpendingq\n",
+ (u32) cmdnode,
+ ((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command);
+
+done:
+ LEAVE();
+ return;
+}
+
+/*
+ * TODO: Fix the issue when DownloadcommandToStation is being called the
+ * second time when the command timesout. All the cmdptr->xxx are in little
+ * endian and therefore all the comparissions will fail.
+ * For now - we are not performing the endian conversion the second time - but
+ * for PS and DEEP_SLEEP we need to worry
+ */
+static int DownloadcommandToStation(wlan_private * priv,
+ struct cmd_ctrl_node *cmdnode)
+{
+ unsigned long flags;
+ struct cmd_ds_command *cmdptr;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ u16 cmdsize;
+ u16 command;
+
+ ENTER();
+
+ if (!adapter || !cmdnode) {
+ lbs_pr_debug(1, "DNLD_CMD: adapter = %#x, cmdnode = %#x\n",
+ (int)adapter, (int)cmdnode);
+ if (cmdnode) {
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ __libertas_cleanup_and_insert_cmd(priv, cmdnode);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ }
+ ret = -1;
+ goto done;
+ }
+
+ cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (!cmdptr || !cmdptr->size) {
+ lbs_pr_debug(1, "DNLD_CMD: cmdptr is Null or cmd size is Zero, "
+ "Not sending\n");
+ __libertas_cleanup_and_insert_cmd(priv, cmdnode);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ ret = -1;
+ goto done;
+ }
+
+ adapter->cur_cmd = cmdnode;
+ adapter->cur_cmd_retcode = 0;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ lbs_pr_debug(1, "DNLD_CMD:: Before download, size of cmd = %d\n",
+ cmdptr->size);
+
+ cmdsize = cmdptr->size;
+
+ command = cpu_to_le16(cmdptr->command);
+
+ cmdnode->cmdwaitqwoken = 0;
+ cmdsize = cpu_to_le16(cmdsize);
+
+ ret = libertas_sbi_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
+
+ if (ret != 0) {
+ lbs_pr_debug(1, "DNLD_CMD: Host to Card failed\n");
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ ret = -1;
+ goto done;
+ }
+
+ lbs_pr_debug(1, "DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies);
+ lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize);
+
+ /* Setup the timer after transmit command */
+ if (command == cmd_802_11_scan
+ || command == cmd_802_11_authenticate
+ || command == cmd_802_11_associate)
+ mod_timer(&adapter->command_timer, jiffies + (10*HZ));
+ else
+ mod_timer(&adapter->command_timer, jiffies + (5*HZ));
+
+ ret = 0;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+static int wlan_cmd_mac_control(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_mac_control);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
+ mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
+
+ lbs_pr_debug(1, "wlan_cmd_mac_control(): action=0x%X size=%d\n",
+ mac->action, cmd->size);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * This function inserts command node to cmdfreeq
+ * after cleans it. Requires adapter->driver_lock held.
+ */
+void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ if (!ptempcmd)
+ goto done;
+
+ cleanup_cmdnode(ptempcmd);
+ list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
+done:
+ return;
+}
+
+void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+ __libertas_cleanup_and_insert_cmd(priv, ptempcmd);
+ spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+}
+
+int libertas_set_radio_control(wlan_private * priv)
+{
+ int ret = 0;
+
+ ENTER();
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_radio_control,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+
+ lbs_pr_debug(1, "RADIO_SET: on or off: 0x%X, preamble = 0x%X\n",
+ priv->adapter->radioon, priv->adapter->preamble);
+
+ LEAVE();
+ return ret;
+}
+
+int libertas_set_mac_packet_filter(wlan_private * priv)
+{
+ int ret = 0;
+
+ ENTER();
+
+ lbs_pr_debug(1, "libertas_set_mac_packet_filter value = %x\n",
+ priv->adapter->currentpacketfilter);
+
+ /* Send MAC control command to station */
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_mac_control, 0, 0, 0, NULL);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepare the command before send to firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param cmd_no command number
+ * @param cmd_action command action: GET or SET
+ * @param wait_option wait option: wait response or not
+ * @param cmd_oid cmd oid: treated as sub command
+ * @param pdata_buf A pointer to informaion buffer
+ * @return 0 or -1
+ */
+int libertas_prepare_and_send_command(wlan_private * priv,
+ u16 cmd_no,
+ u16 cmd_action,
+ u16 wait_option, u32 cmd_oid, void *pdata_buf)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmdnode;
+ struct cmd_ds_command *cmdptr;
+ unsigned long flags;
+
+ ENTER();
+
+ if (!adapter) {
+ lbs_pr_debug(1, "PREP_CMD: adapter is Null\n");
+ ret = -1;
+ goto done;
+ }
+
+ if (adapter->surpriseremoved) {
+ lbs_pr_debug(1, "PREP_CMD: Card is Removed\n");
+ ret = -1;
+ goto done;
+ }
+
+ cmdnode = libertas_get_free_cmd_ctrl_node(priv);
+
+ if (cmdnode == NULL) {
+ lbs_pr_debug(1, "PREP_CMD: No free cmdnode\n");
+
+ /* Wake up main thread to execute next command */
+ wake_up_interruptible(&priv->mainthread.waitq);
+ ret = -1;
+ goto done;
+ }
+
+ libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf);
+
+ cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+ lbs_pr_debug(1, "PREP_CMD: Val of cmd ptr =0x%x, command=0x%X\n",
+ (u32) cmdptr, cmd_no);
+
+ if (!cmdptr) {
+ lbs_pr_debug(1, "PREP_CMD: bufvirtualaddr of cmdnode is NULL\n");
+ libertas_cleanup_and_insert_cmd(priv, cmdnode);
+ ret = -1;
+ goto done;
+ }
+
+ /* Set sequence number, command and INT option */
+ adapter->seqnum++;
+ cmdptr->seqnum = cpu_to_le16(adapter->seqnum);
+
+ cmdptr->command = cmd_no;
+ cmdptr->result = 0;
+
+ switch (cmd_no) {
+ case cmd_get_hw_spec:
+ ret = wlan_cmd_hw_spec(priv, cmdptr);
+ break;
+ case cmd_802_11_ps_mode:
+ ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_scan:
+ ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
+ break;
+
+ case cmd_mac_control:
+ ret = wlan_cmd_mac_control(priv, cmdptr);
+ break;
+
+ case cmd_802_11_associate:
+ case cmd_802_11_reassociate:
+ ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
+ break;
+
+ case cmd_802_11_deauthenticate:
+ ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
+ break;
+
+ case cmd_802_11_set_wep:
+ ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_ad_hoc_start:
+ ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
+ break;
+ case cmd_code_dnld:
+ break;
+
+ case cmd_802_11_reset:
+ ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_get_log:
+ ret = wlan_cmd_802_11_get_log(priv, cmdptr);
+ break;
+
+ case cmd_802_11_authenticate:
+ ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
+ break;
+
+ case cmd_802_11_get_stat:
+ ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
+ break;
+
+ case cmd_802_11_snmp_mib:
+ ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
+ cmd_action, cmd_oid, pdata_buf);
+ break;
+
+ case cmd_mac_reg_access:
+ case cmd_bbp_reg_access:
+ case cmd_rf_reg_access:
+ ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_rf_channel:
+ ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_rf_tx_power:
+ ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_radio_control:
+ ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_rf_antenna:
+ ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_data_rate:
+ ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
+ break;
+ case cmd_802_11_rate_adapt_rateset:
+ ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
+ cmdptr, cmd_action);
+ break;
+
+ case cmd_mac_multicast_adr:
+ ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_ad_hoc_join:
+ ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
+ break;
+
+ case cmd_802_11_rssi:
+ ret = wlan_cmd_802_11_rssi(priv, cmdptr);
+ break;
+
+ case cmd_802_11_ad_hoc_stop:
+ ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
+ break;
+
+ case cmd_802_11_enable_rsn:
+ ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_key_material:
+ ret = wlan_cmd_802_11_key_material(priv, cmdptr,
+ cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+
+ case cmd_802_11_pairwise_tsc:
+ break;
+ case cmd_802_11_group_tsc:
+ break;
+
+ case cmd_802_11_mac_address:
+ ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_eeprom_access:
+ ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_set_afc:
+ case cmd_802_11_get_afc:
+
+ cmdptr->command = cpu_to_le16(cmd_no);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
+ S_DS_GEN);
+
+ memmove(&cmdptr->params.afc,
+ pdata_buf, sizeof(struct cmd_ds_802_11_afc));
+
+ ret = 0;
+ goto done;
+
+ case cmd_802_11d_domain_info:
+ ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
+ cmd_no, cmd_action);
+ break;
+
+ case cmd_802_11_sleep_params:
+ ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
+ break;
+ case cmd_802_11_inactivity_timeout:
+ ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
+ cmd_action, pdata_buf);
+ libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
+ break;
+
+ case cmd_802_11_tpc_cfg:
+ cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
+ S_DS_GEN);
+
+ memmove(&cmdptr->params.tpccfg,
+ pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
+
+ ret = 0;
+ break;
+ case cmd_802_11_led_gpio_ctrl:
+ {
+ struct mrvlietypes_ledgpio *gpio =
+ (struct mrvlietypes_ledgpio*)
+ cmdptr->params.ledgpio.data;
+
+ memmove(&cmdptr->params.ledgpio,
+ pdata_buf,
+ sizeof(struct cmd_ds_802_11_led_ctrl));
+
+ cmdptr->command =
+ cpu_to_le16(cmd_802_11_led_gpio_ctrl);
+
+#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
+ cmdptr->size =
+ cpu_to_le16(gpio->header.len + S_DS_GEN +
+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
+ gpio->header.len = cpu_to_le16(gpio->header.len);
+
+ ret = 0;
+ break;
+ }
+ case cmd_802_11_pwr_cfg:
+ cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
+ S_DS_GEN);
+ memmove(&cmdptr->params.pwrcfg, pdata_buf,
+ sizeof(struct cmd_ds_802_11_pwr_cfg));
+
+ ret = 0;
+ break;
+ case cmd_bt_access:
+ ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+ case cmd_fwt_access:
+ ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+ case cmd_mesh_access:
+ ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+ case cmd_get_tsf:
+ cmdptr->command = cpu_to_le16(cmd_get_tsf);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_get_tsf)
+ + S_DS_GEN);
+ ret = 0;
+ break;
+ case cmd_802_11_tx_rate_query:
+ cmdptr->command =
+ cpu_to_le16(cmd_802_11_tx_rate_query);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_tx_rate_query) +
+ S_DS_GEN);
+ adapter->txrate = 0;
+ ret = 0;
+ break;
+ default:
+ lbs_pr_debug(1, "PREP_CMD: unknown command- %#x\n", cmd_no);
+ ret = -1;
+ break;
+ }
+
+ /* return error, since the command preparation failed */
+ if (ret != 0) {
+ lbs_pr_debug(1, "PREP_CMD: command preparation failed\n");
+ libertas_cleanup_and_insert_cmd(priv, cmdnode);
+ ret = -1;
+ goto done;
+ }
+
+ cmdnode->cmdwaitqwoken = 0;
+
+ libertas_queue_cmd(adapter, cmdnode, 1);
+ adapter->nr_cmd_pending++;
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ if (wait_option & cmd_option_waitforrsp) {
+ lbs_pr_debug(1, "PREP_CMD: Wait for CMD response\n");
+ might_sleep();
+ wait_event_interruptible(cmdnode->cmdwait_q,
+ cmdnode->cmdwaitqwoken);
+ }
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->cur_cmd_retcode) {
+ lbs_pr_debug(1, "PREP_CMD: command failed with return code=%d\n",
+ adapter->cur_cmd_retcode);
+ adapter->cur_cmd_retcode = 0;
+ ret = -1;
+ }
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function allocates the command buffer and link
+ * it to command free queue.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+int libertas_allocate_cmd_buffer(wlan_private * priv)
+{
+ int ret = 0;
+ u32 ulbufsize;
+ u32 i;
+ struct cmd_ctrl_node *tempcmd_array;
+ u8 *ptempvirtualaddr;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* Allocate and initialize cmdCtrlNode */
+ ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
+
+ if (!(tempcmd_array = kmalloc(ulbufsize, GFP_KERNEL))) {
+ lbs_pr_debug(1,
+ "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n");
+ ret = -1;
+ goto done;
+ }
+
+ adapter->cmd_array = tempcmd_array;
+ memset(adapter->cmd_array, 0, ulbufsize);
+
+ /* Allocate and initialize command buffers */
+ ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ if (!(ptempvirtualaddr = kmalloc(ulbufsize, GFP_KERNEL))) {
+ lbs_pr_debug(1,
+ "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n");
+ ret = -1;
+ goto done;
+ }
+
+ memset(ptempvirtualaddr, 0, ulbufsize);
+
+ /* Update command buffer virtual */
+ tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
+ }
+
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
+ libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
+ }
+
+ ret = 0;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the command buffer.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+int libertas_free_cmd_buffer(wlan_private * priv)
+{
+ u32 ulbufsize;
+ unsigned int i;
+ struct cmd_ctrl_node *tempcmd_array;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* need to check if cmd array is allocated or not */
+ if (adapter->cmd_array == NULL) {
+ lbs_pr_debug(1, "FREE_CMD_BUF: cmd_array is Null\n");
+ goto done;
+ }
+
+ tempcmd_array = adapter->cmd_array;
+
+ /* Release shared memory buffers */
+ ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ if (tempcmd_array[i].bufvirtualaddr) {
+ lbs_pr_debug(1, "Free all the array\n");
+ kfree(tempcmd_array[i].bufvirtualaddr);
+ tempcmd_array[i].bufvirtualaddr = NULL;
+ }
+ }
+
+ /* Release cmd_ctrl_node */
+ if (adapter->cmd_array) {
+ lbs_pr_debug(1, "Free cmd_array\n");
+ kfree(adapter->cmd_array);
+ adapter->cmd_array = NULL;
+ }
+
+done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function gets a free command node if available in
+ * command free queue.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
+ */
+struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
+{
+ struct cmd_ctrl_node *tempnode;
+ wlan_adapter *adapter = priv->adapter;
+ unsigned long flags;
+
+ if (!adapter)
+ return NULL;
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+
+ if (!list_empty(&adapter->cmdfreeq)) {
+ tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
+ list_del((struct list_head *)tempnode);
+ } else {
+ lbs_pr_debug(1, "GET_CMD_NODE: cmd_ctrl_node is not available\n");
+ tempnode = NULL;
+ }
+
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ if (tempnode) {
+ lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n");
+ lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n",
+ tempnode);
+ cleanup_cmdnode(tempnode);
+ }
+
+ return tempnode;
+}
+
+/**
+ * @brief This function cleans command node.
+ *
+ * @param ptempnode A pointer to cmdCtrlNode structure
+ * @return n/a
+ */
+static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
+{
+ if (!ptempnode)
+ return;
+ ptempnode->cmdwaitqwoken = 1;
+ wake_up_interruptible(&ptempnode->cmdwait_q);
+ ptempnode->status = 0;
+ ptempnode->cmd_oid = (u32) 0;
+ ptempnode->wait_option = 0;
+ ptempnode->pdata_buf = NULL;
+
+ if (ptempnode->bufvirtualaddr != NULL)
+ memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ return;
+}
+
+/**
+ * @brief This function initializes the command node.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param ptempnode A pointer to cmd_ctrl_node structure
+ * @param cmd_oid cmd oid: treated as sub command
+ * @param wait_option wait option: wait response or not
+ * @param pdata_buf A pointer to informaion buffer
+ * @return 0 or -1
+ */
+void libertas_set_cmd_ctrl_node(wlan_private * priv,
+ struct cmd_ctrl_node *ptempnode,
+ u32 cmd_oid, u16 wait_option, void *pdata_buf)
+{
+ ENTER();
+
+ if (!ptempnode)
+ return;
+
+ ptempnode->cmd_oid = cmd_oid;
+ ptempnode->wait_option = wait_option;
+ ptempnode->pdata_buf = pdata_buf;
+
+ LEAVE();
+}
+
+/**
+ * @brief This function executes next command in command
+ * pending queue. It will put fimware back to PS mode
+ * if applicable.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+int libertas_execute_next_command(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmdnode = NULL;
+ struct cmd_ds_command *cmdptr;
+ unsigned long flags;
+ int ret = 0;
+
+ lbs_pr_debug(1, "libertas_execute_next_command\n");
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+
+ if (adapter->cur_cmd) {
+ lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n");
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ ret = -1;
+ goto done;
+ }
+
+ if (!list_empty(&adapter->cmdpendingq)) {
+ cmdnode = (struct cmd_ctrl_node *)
+ adapter->cmdpendingq.next;
+ }
+
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ if (cmdnode) {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: Got next command from cmdpendingq\n");
+ cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+ if (is_command_allowed_in_ps(cmdptr->command)) {
+ if ((adapter->psstate == PS_STATE_SLEEP)
+ || (adapter->psstate == PS_STATE_PRE_SLEEP)
+ ) {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n",
+ cmdptr->command, adapter->psstate);
+ ret = -1;
+ goto done;
+ }
+ lbs_pr_debug(1, "EXEC_NEXT_CMD: OK to send command "
+ "0x%x in psstate %d\n",
+ cmdptr->command, adapter->psstate);
+ } else if (adapter->psstate != PS_STATE_FULL_POWER) {
+ /*
+ * 1. Non-PS command:
+ * Queue it. set needtowakeup to TRUE if current state
+ * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS.
+ * 2. PS command but not Exit_PS:
+ * Ignore it.
+ * 3. PS command Exit_PS:
+ * Set needtowakeup to TRUE if current state is SLEEP,
+ * otherwise send this command down to firmware
+ * immediately.
+ */
+ if (cmdptr->command !=
+ cpu_to_le16(cmd_802_11_ps_mode)) {
+ /* Prepare to send Exit PS,
+ * this non PS command will be sent later */
+ if ((adapter->psstate == PS_STATE_SLEEP)
+ || (adapter->psstate == PS_STATE_PRE_SLEEP)
+ ) {
+ /* w/ new scheme, it will not reach here.
+ since it is blocked in main_thread. */
+ adapter->needtowakeup = 1;
+ } else
+ libertas_ps_wakeup(priv, 0);
+
+ ret = 0;
+ goto done;
+ } else {
+ /*
+ * PS command. Ignore it if it is not Exit_PS.
+ * otherwise send it down immediately.
+ */
+ struct cmd_ds_802_11_ps_mode *psm =
+ &cmdptr->params.psmode;
+
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: PS cmd- action=0x%x\n",
+ psm->action);
+ if (psm->action !=
+ cpu_to_le16(cmd_subcmd_exit_ps)) {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+ list_del((struct list_head *)cmdnode);
+ libertas_cleanup_and_insert_cmd(priv, cmdnode);
+
+ ret = 0;
+ goto done;
+ }
+
+ if ((adapter->psstate == PS_STATE_SLEEP)
+ || (adapter->psstate == PS_STATE_PRE_SLEEP)
+ ) {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
+ list_del((struct list_head *)cmdnode);
+ libertas_cleanup_and_insert_cmd(priv, cmdnode);
+ adapter->needtowakeup = 1;
+
+ ret = 0;
+ goto done;
+ }
+
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
+ }
+ }
+ list_del((struct list_head *)cmdnode);
+ lbs_pr_debug(1, "EXEC_NEXT_CMD: Sending 0x%04X command\n",
+ cmdptr->command);
+ DownloadcommandToStation(priv, cmdnode);
+ } else {
+ /*
+ * check if in power save mode, if yes, put the device back
+ * to PS mode
+ */
+ if ((adapter->psmode != wlan802_11powermodecam) &&
+ (adapter->psstate == PS_STATE_FULL_POWER) &&
+ (adapter->connect_status == libertas_connected)) {
+ if (adapter->secinfo.WPAenabled
+ || adapter->secinfo.WPA2enabled) {
+ /* check for valid WPA group keys */
+ if (adapter->wpa_mcast_key.len
+ || adapter->wpa_unicast_key.len) {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
+ " go back to PS_SLEEP");
+ libertas_ps_sleep(priv, 0);
+ }
+ } else {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: command PendQ is empty,"
+ " go back to PS_SLEEP");
+ libertas_ps_sleep(priv, 0);
+ }
+ }
+ }
+
+ ret = 0;
+done:
+ return ret;
+}
+
+void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
+{
+ union iwreq_data iwrq;
+ u8 buf[50];
+
+ ENTER();
+
+ memset(&iwrq, 0, sizeof(union iwreq_data));
+ memset(buf, 0, sizeof(buf));
+
+ snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+ iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+ /* Send Event to upper layer */
+ lbs_pr_debug(1, "Event Indication string = %s\n",
+ (char *)buf);
+ lbs_pr_debug(1, "Event Indication String length = %d\n", iwrq.data.length);
+
+ lbs_pr_debug(1, "Sending wireless event IWEVCUSTOM for %s\n", str);
+ wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf);
+
+ LEAVE();
+ return;
+}
+
+static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
+{
+ unsigned long flags;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ lbs_pr_debug(1, "SEND_SLEEPC_CMD: Before download, size of cmd = %d\n",
+ size);
+
+ lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size);
+
+ ret = libertas_sbi_host_to_card(priv, MVMS_CMD, cmdptr, size);
+ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->intcounter || adapter->currenttxskb)
+ lbs_pr_debug(1, "SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n",
+ adapter->intcounter, adapter->currenttxskb);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ if (ret) {
+ lbs_pr_alert(
+ "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
+ } else {
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (!adapter->intcounter) {
+ adapter->psstate = PS_STATE_SLEEP;
+ } else {
+ lbs_pr_debug(1, "SEND_SLEEPC_CMD: After sent,IntC=%d\n",
+ adapter->intcounter);
+ }
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ lbs_pr_debug(1, "SEND_SLEEPC_CMD: Sent Confirm Sleep command\n");
+ lbs_pr_debug(1, "+");
+ }
+
+ LEAVE();
+ return ret;
+}
+
+void libertas_ps_sleep(wlan_private * priv, int wait_option)
+{
+
+ ENTER();
+
+ /*
+ * PS is currently supported only in Infrastructure mode
+ * Remove this check if it is to be supported in IBSS mode also
+ */
+
+ libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+ cmd_subcmd_enter_ps, wait_option, 0, NULL);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function sends Eixt_PS command to firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param wait_option wait response or not
+ * @return n/a
+ */
+void libertas_ps_wakeup(wlan_private * priv, int wait_option)
+{
+ enum WLAN_802_11_POWER_MODE Localpsmode;
+
+ ENTER();
+
+ Localpsmode = wlan802_11powermodecam;
+
+ lbs_pr_debug(1, "Exit_PS: Localpsmode = %d\n", Localpsmode);
+
+ libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+ cmd_subcmd_exit_ps,
+ wait_option, 0, &Localpsmode);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function checks condition and prepares to
+ * send sleep confirm command to firmware if ok.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param psmode Power Saving mode
+ * @return n/a
+ */
+void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode)
+{
+ unsigned long flags =0;
+ wlan_adapter *adapter = priv->adapter;
+ u8 allowed = 1;
+
+ ENTER();
+
+ if (priv->wlan_dev.dnld_sent) {
+ allowed = 0;
+ lbs_pr_debug(1, "D");
+ }
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->cur_cmd) {
+ allowed = 0;
+ lbs_pr_debug(1, "C");
+ }
+ if (adapter->intcounter > 0) {
+ allowed = 0;
+ lbs_pr_debug(1, "I%d", adapter->intcounter);
+ }
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ if (allowed) {
+ lbs_pr_debug(1, "Sending libertas_ps_confirm_sleep\n");
+ sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
+ sizeof(struct PS_CMD_ConfirmSleep));
+ } else {
+ lbs_pr_debug(1, "Sleep Confirm has been delayed\n");
+ }
+
+ LEAVE();
+}
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
new file mode 100644
index 000000000000..cdb012c7e9cf
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -0,0 +1,1031 @@
+/**
+ * This file contains the handling of command
+ * responses as well as events generated by firmware.
+ */
+#include <linux/delay.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+/**
+ * @brief This function handles disconnect event. it
+ * reports disconnect to upper layer, clean tx/rx packets,
+ * reset link state etc.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return n/a
+ */
+void libertas_mac_event_disconnected(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ union iwreq_data wrqu;
+
+ if (adapter->connect_status != libertas_connected)
+ return;
+
+ lbs_pr_debug(1, "Handles disconnect event.\n");
+
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+ /*
+ * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
+ * It causes problem in the Supplicant
+ */
+
+ msleep_interruptible(1000);
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+ /* Free Tx and Rx packets */
+ kfree_skb(priv->adapter->currenttxskb);
+ priv->adapter->currenttxskb = NULL;
+
+ /* report disconnect to upper layer */
+ netif_stop_queue(priv->wlan_dev.netdev);
+ netif_carrier_off(priv->wlan_dev.netdev);
+
+ /* reset SNR/NF/RSSI values */
+ memset(adapter->SNR, 0x00, sizeof(adapter->SNR));
+ memset(adapter->NF, 0x00, sizeof(adapter->NF));
+ memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI));
+ memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
+ memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
+ adapter->nextSNRNF = 0;
+ adapter->numSNRNF = 0;
+ adapter->rxpd_rate = 0;
+ lbs_pr_debug(1, "Current SSID=%s, ssid length=%u\n",
+ adapter->curbssparams.ssid.ssid,
+ adapter->curbssparams.ssid.ssidlength);
+ lbs_pr_debug(1, "Previous SSID=%s, ssid length=%u\n",
+ adapter->previousssid.ssid, adapter->previousssid.ssidlength);
+
+ /* reset internal flags */
+ adapter->secinfo.WPAenabled = 0;
+ adapter->secinfo.WPA2enabled = 0;
+ adapter->wpa_ie_len = 0;
+ adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
+ adapter->secinfo.Encryptionmode = CIPHER_NONE;
+
+ adapter->connect_status = libertas_disconnected;
+
+ /*
+ * memorize the previous SSID and BSSID
+ * it could be used for re-assoc
+ */
+ memcpy(&adapter->previousssid,
+ &adapter->curbssparams.ssid, sizeof(struct WLAN_802_11_SSID));
+ memcpy(adapter->previousbssid,
+ adapter->curbssparams.bssid, ETH_ALEN);
+
+ /* need to erase the current SSID and BSSID info */
+ adapter->pattemptedbssdesc = NULL;
+ memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+
+ if (adapter->psstate != PS_STATE_FULL_POWER) {
+ /* make firmware to exit PS mode */
+ lbs_pr_debug(1, "Disconnected, so exit PS mode.\n");
+ libertas_ps_wakeup(priv, 0);
+ }
+}
+
+/**
+ * @brief This function handles MIC failure event.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @para event the event id
+ * @return n/a
+ */
+static void handle_mic_failureevent(wlan_private * priv, u32 event)
+{
+ char buf[50];
+
+ memset(buf, 0, sizeof(buf));
+
+ sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
+
+ if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
+ strcat(buf, "unicast ");
+ } else {
+ strcat(buf, "multicast ");
+ }
+
+ libertas_send_iwevcustom_event(priv, buf);
+}
+
+static int wlan_ret_reg_access(wlan_private * priv,
+ u16 type, struct cmd_ds_command *resp)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ switch (type) {
+ case cmd_ret_mac_reg_access:
+ {
+ struct cmd_ds_mac_reg_access *reg;
+
+ reg =
+ (struct cmd_ds_mac_reg_access *)&resp->params.
+ macreg;
+
+ adapter->offsetvalue.offset = reg->offset;
+ adapter->offsetvalue.value = reg->value;
+ break;
+ }
+
+ case cmd_ret_bbp_reg_access:
+ {
+ struct cmd_ds_bbp_reg_access *reg;
+ reg =
+ (struct cmd_ds_bbp_reg_access *)&resp->params.
+ bbpreg;
+
+ adapter->offsetvalue.offset = reg->offset;
+ adapter->offsetvalue.value = reg->value;
+ break;
+ }
+
+ case cmd_ret_rf_reg_access:
+ {
+ struct cmd_ds_rf_reg_access *reg;
+ reg =
+ (struct cmd_ds_rf_reg_access *)&resp->params.
+ rfreg;
+
+ adapter->offsetvalue.offset = reg->offset;
+ adapter->offsetvalue.value = reg->value;
+ break;
+ }
+
+ default:
+ LEAVE();
+ return -1;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_get_hw_spec(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ u32 i;
+ struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);
+
+ adapter->fwreleasenumber = hwspec->fwreleasenumber;
+
+ lbs_pr_debug(1, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n",
+ adapter->fwreleasenumber);
+ lbs_pr_debug(1, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
+ hwspec->permanentaddr[0], hwspec->permanentaddr[1],
+ hwspec->permanentaddr[2], hwspec->permanentaddr[3],
+ hwspec->permanentaddr[4], hwspec->permanentaddr[5]);
+ lbs_pr_debug(1, "GET_HW_SPEC: hwifversion=0x%X version=0x%X\n",
+ hwspec->hwifversion, hwspec->version);
+
+ adapter->regioncode = le16_to_cpu(hwspec->regioncode);
+
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* use the region code to search for the index */
+ if (adapter->regioncode == libertas_region_code_to_index[i]) {
+ adapter->regiontableindex = (u16) i;
+ break;
+ }
+ }
+
+ /* if it's unidentified region code, use the default (USA) */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ adapter->regioncode = 0x10;
+ adapter->regiontableindex = 0;
+ lbs_pr_info(
+ "unidentified region code, use the default (USA)\n");
+ }
+
+ if (adapter->current_addr[0] == 0xff) {
+ memmove(adapter->current_addr, hwspec->permanentaddr,
+ ETH_ALEN);
+ }
+
+ memcpy(priv->wlan_dev.netdev->dev_addr, adapter->current_addr, ETH_ALEN);
+ memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+
+ if (libertas_set_regiontable(priv, adapter->regioncode, 0)) {
+ ret = -1;
+ goto done;
+ }
+
+ if (libertas_set_universaltable(priv, 0)) {
+ ret = -1;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+static int wlan_ret_802_11_sleep_params(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ lbs_pr_debug(1, "error=%x offset=%x stabletime=%x calcontrol=%x\n"
+ " extsleepclk=%x\n", sp->error, sp->offset,
+ sp->stabletime, sp->calcontrol, sp->externalsleepclk);
+ adapter->sp.sp_error = le16_to_cpu(sp->error);
+ adapter->sp.sp_offset = le16_to_cpu(sp->offset);
+ adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
+ adapter->sp.sp_calcontrol = le16_to_cpu(sp->calcontrol);
+ adapter->sp.sp_extsleepclk = le16_to_cpu(sp->externalsleepclk);
+ adapter->sp.sp_reserved = le16_to_cpu(sp->reserved);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_stat(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+/* currently adapter->wlan802_11Stat is unused
+
+ struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
+ wlan_adapter *adapter = priv->adapter;
+
+ // TODO Convert it to Big endian befor copy
+ memcpy(&adapter->wlan802_11Stat,
+ p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
+*/
+ return 0;
+}
+
+static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
+ u16 oid = le16_to_cpu(smib->oid);
+ u16 querytype = le16_to_cpu(smib->querytype);
+
+ ENTER();
+
+ lbs_pr_debug(1, "SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
+ querytype);
+ lbs_pr_debug(1, "SNMP_RESP: Buf size = %x\n",
+ le16_to_cpu(smib->bufsize));
+
+ if (querytype == cmd_act_get) {
+ switch (oid) {
+ case fragthresh_i:
+ priv->adapter->fragthsd =
+ le16_to_cpu(*
+ ((unsigned short *)(smib->value)));
+ lbs_pr_debug(1, "SNMP_RESP: fragthsd =%u\n",
+ priv->adapter->fragthsd);
+ break;
+ case rtsthresh_i:
+ priv->adapter->rtsthsd =
+ le16_to_cpu(*
+ ((unsigned short *)(smib->value)));
+ lbs_pr_debug(1, "SNMP_RESP: rtsthsd =%u\n",
+ priv->adapter->rtsthsd);
+ break;
+ case short_retrylim_i:
+ priv->adapter->txretrycount =
+ le16_to_cpu(*
+ ((unsigned short *)(smib->value)));
+ lbs_pr_debug(1, "SNMP_RESP: txretrycount =%u\n",
+ priv->adapter->rtsthsd);
+ break;
+ default:
+ break;
+ }
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_key_material(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_key_material *pkeymaterial =
+ &resp->params.keymaterial;
+ wlan_adapter *adapter = priv->adapter;
+ u16 action = le16_to_cpu(pkeymaterial->action);
+
+ ENTER();
+
+ /* Copy the returned key to driver private data */
+ if (action == cmd_act_get) {
+ u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
+ u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
+
+ while (buf_ptr < resp_end) {
+ struct MrvlIEtype_keyParamSet * pkeyparamset =
+ (struct MrvlIEtype_keyParamSet *) buf_ptr;
+ struct WLAN_802_11_KEY * pkey;
+ u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
+ u16 param_set_len = le16_to_cpu(pkeyparamset->length);
+ u8 * end;
+ u16 key_len = le16_to_cpu(pkeyparamset->keylen);
+
+ end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
+ + sizeof (pkeyparamset->length)
+ + param_set_len;
+ /* Make sure we don't access past the end of the IEs */
+ if (end > resp_end)
+ break;
+
+ if (key_info & KEY_INFO_WPA_UNICAST)
+ pkey = &adapter->wpa_unicast_key;
+ else if (key_info & KEY_INFO_WPA_MCAST)
+ pkey = &adapter->wpa_mcast_key;
+ else
+ break;
+
+ /* Copy returned key into driver */
+ memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+ if (key_len > sizeof(pkey->key))
+ break;
+ pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
+ pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
+ pkey->len = le16_to_cpu(pkeyparamset->keylen);
+ memcpy(pkey->key, pkeyparamset->key, pkey->len);
+
+ buf_ptr = end + 1;
+ }
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_mac_address(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
+
+ lbs_pr_debug(1, "Current TxPower Level = %d\n", adapter->txpowerlevel);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
+ wlan_adapter *adapter = priv->adapter;
+ u16 action = le16_to_cpu(pAntenna->action);
+
+ if (action == cmd_act_get_rx)
+ adapter->rxantennamode =
+ le16_to_cpu(pAntenna->antennamode);
+
+ if (action == cmd_act_get_tx)
+ adapter->txantennamode =
+ le16_to_cpu(pAntenna->antennamode);
+
+ lbs_pr_debug(1, "RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
+ action, le16_to_cpu(pAntenna->antennamode));
+
+ return 0;
+}
+
+static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rate_adapt_rateset *rates =
+ &resp->params.rateset;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (rates->action == cmd_act_get) {
+ adapter->enablehwauto = rates->enablehwauto;
+ adapter->ratebitmap = rates->bitmap;
+ }
+
+ LEAVE();
+
+ return 0;
+}
+
+static int wlan_ret_802_11_data_rate(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
+ wlan_adapter *adapter = priv->adapter;
+ u8 dot11datarate;
+
+ ENTER();
+
+ lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
+ (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
+
+ dot11datarate = pdatarate->datarate[0];
+ if (pdatarate->action == cmd_act_get_tx_rate) {
+ memcpy(adapter->libertas_supported_rates, pdatarate->datarate,
+ sizeof(adapter->libertas_supported_rates));
+ }
+ adapter->datarate = libertas_index_to_data_rate(dot11datarate);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_rf_channel(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rf_channel *rfchannel =
+ &resp->params.rfchannel;
+ wlan_adapter *adapter = priv->adapter;
+ u16 action = le16_to_cpu(rfchannel->action);
+ u16 newchannel = le16_to_cpu(rfchannel->currentchannel);
+
+ ENTER();
+
+ if (action == cmd_opt_802_11_rf_channel_get
+ && adapter->curbssparams.channel != newchannel) {
+ lbs_pr_debug(1, "channel Switch: %d to %d\n",
+ adapter->curbssparams.channel, newchannel);
+
+ /* Update the channel again */
+ adapter->curbssparams.channel = newchannel;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_rssi(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
+ wlan_adapter *adapter = priv->adapter;
+
+ /* store the non average value */
+ adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
+ adapter->NF[TYPE_BEACON][TYPE_NOAVG] =
+ le16_to_cpu(rssirsp->noisefloor);
+
+ adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
+ adapter->NF[TYPE_BEACON][TYPE_AVG] =
+ le16_to_cpu(rssirsp->avgnoisefloor);
+
+ adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
+ CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+ adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+ adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
+ CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
+ adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
+
+ lbs_pr_debug(1, "Beacon RSSI value = 0x%x\n",
+ adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
+
+ return 0;
+}
+
+static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_ioctl_regrdwr *pbuf;
+ pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
+
+ lbs_pr_debug(1, "eeprom read len=%x\n",
+ le16_to_cpu(resp->params.rdeeprom.bytecount));
+ if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
+ pbuf->NOB = 0;
+ lbs_pr_debug(1, "eeprom read return length is too big\n");
+ return -1;
+ }
+ pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
+ if (pbuf->NOB > 0) {
+
+ memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
+ le16_to_cpu(resp->params.rdeeprom.bytecount));
+ lbs_dbg_hex("adapter", (char *)&pbuf->value,
+ le16_to_cpu(resp->params.rdeeprom.bytecount));
+ }
+ return 0;
+}
+
+static int wlan_ret_get_log(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_get_log *logmessage =
+ (struct cmd_ds_802_11_get_log *)&resp->params.glog;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* TODO Convert it to Big Endian before copy */
+ memcpy(&adapter->logmsg, logmessage,
+ sizeof(struct cmd_ds_802_11_get_log));
+
+ LEAVE();
+ return 0;
+}
+
+static inline int handle_cmd_response(u16 respcmd,
+ struct cmd_ds_command *resp,
+ wlan_private *priv)
+{
+ int ret = 0;
+ unsigned long flags;
+ wlan_adapter *adapter = priv->adapter;
+
+ switch (respcmd) {
+ case cmd_ret_mac_reg_access:
+ case cmd_ret_bbp_reg_access:
+ case cmd_ret_rf_reg_access:
+ ret = wlan_ret_reg_access(priv, respcmd, resp);
+ break;
+
+ case cmd_ret_hw_spec_info:
+ ret = wlan_ret_get_hw_spec(priv, resp);
+ break;
+
+ case cmd_ret_802_11_scan:
+ ret = libertas_ret_80211_scan(priv, resp);
+ break;
+
+ case cmd_ret_802_11_get_log:
+ ret = wlan_ret_get_log(priv, resp);
+ break;
+
+ case cmd_ret_802_11_associate:
+ case cmd_ret_802_11_reassociate:
+ ret = libertas_ret_80211_associate(priv, resp);
+ break;
+
+ case cmd_ret_802_11_disassociate:
+ case cmd_ret_802_11_deauthenticate:
+ ret = libertas_ret_80211_disassociate(priv, resp);
+ break;
+
+ case cmd_ret_802_11_ad_hoc_start:
+ case cmd_ret_802_11_ad_hoc_join:
+ ret = libertas_ret_80211_ad_hoc_start(priv, resp);
+ break;
+
+ case cmd_ret_802_11_stat:
+ ret = wlan_ret_802_11_stat(priv, resp);
+ break;
+
+ case cmd_ret_802_11_snmp_mib:
+ ret = wlan_ret_802_11_snmp_mib(priv, resp);
+ break;
+
+ case cmd_ret_802_11_rf_tx_power:
+ ret = wlan_ret_802_11_rf_tx_power(priv, resp);
+ break;
+
+ case cmd_ret_802_11_set_afc:
+ case cmd_ret_802_11_get_afc:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ memmove(adapter->cur_cmd->pdata_buf,
+ &resp->params.afc,
+ sizeof(struct cmd_ds_802_11_afc));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ break;
+ case cmd_ret_802_11_rf_antenna:
+ ret = wlan_ret_802_11_rf_antenna(priv, resp);
+ break;
+
+ case cmd_ret_mac_multicast_adr:
+ case cmd_ret_mac_control:
+ case cmd_ret_802_11_set_wep:
+ case cmd_ret_802_11_reset:
+ case cmd_ret_802_11_authenticate:
+ case cmd_ret_802_11_radio_control:
+ case cmd_ret_802_11_beacon_stop:
+ case cmd_ret_802_11_enable_rsn:
+ break;
+
+ case cmd_ret_802_11_data_rate:
+ ret = wlan_ret_802_11_data_rate(priv, resp);
+ break;
+ case cmd_ret_802_11_rate_adapt_rateset:
+ ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
+ break;
+ case cmd_ret_802_11_rf_channel:
+ ret = wlan_ret_802_11_rf_channel(priv, resp);
+ break;
+
+ case cmd_ret_802_11_rssi:
+ ret = wlan_ret_802_11_rssi(priv, resp);
+ break;
+
+ case cmd_ret_802_11_mac_address:
+ ret = wlan_ret_802_11_mac_address(priv, resp);
+ break;
+
+ case cmd_ret_802_11_ad_hoc_stop:
+ ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
+ break;
+
+ case cmd_ret_802_11_key_material:
+ lbs_pr_debug(1, "CMD_RESP: KEY_MATERIAL command response\n");
+ ret = wlan_ret_802_11_key_material(priv, resp);
+ break;
+
+ case cmd_ret_802_11_eeprom_access:
+ ret = wlan_ret_802_11_eeprom_access(priv, resp);
+ break;
+
+ case cmd_ret_802_11d_domain_info:
+ ret = libertas_ret_802_11d_domain_info(priv, resp);
+ break;
+
+ case cmd_ret_802_11_sleep_params:
+ ret = wlan_ret_802_11_sleep_params(priv, resp);
+ break;
+ case cmd_ret_802_11_inactivity_timeout:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ *((u16 *) adapter->cur_cmd->pdata_buf) =
+ le16_to_cpu(resp->params.inactivity_timeout.timeout);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+
+ case cmd_ret_802_11_tpc_cfg:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ memmove(adapter->cur_cmd->pdata_buf,
+ &resp->params.tpccfg,
+ sizeof(struct cmd_ds_802_11_tpc_cfg));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+ case cmd_ret_802_11_led_gpio_ctrl:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ memmove(adapter->cur_cmd->pdata_buf,
+ &resp->params.ledgpio,
+ sizeof(struct cmd_ds_802_11_led_ctrl));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+ case cmd_ret_802_11_pwr_cfg:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ memmove(adapter->cur_cmd->pdata_buf,
+ &resp->params.pwrcfg,
+ sizeof(struct cmd_ds_802_11_pwr_cfg));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ break;
+
+ case cmd_ret_get_tsf:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ memcpy(priv->adapter->cur_cmd->pdata_buf,
+ &resp->params.gettsf.tsfvalue, sizeof(u64));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+ case cmd_ret_bt_access:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->cur_cmd->pdata_buf)
+ memcpy(adapter->cur_cmd->pdata_buf,
+ &resp->params.bt.addr1, 2 * ETH_ALEN);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+ case cmd_ret_fwt_access:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->cur_cmd->pdata_buf)
+ memcpy(adapter->cur_cmd->pdata_buf,
+ &resp->params.fwt,
+ sizeof(resp->params.fwt));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+ case cmd_ret_mesh_access:
+ if (adapter->cur_cmd->pdata_buf)
+ memcpy(adapter->cur_cmd->pdata_buf,
+ &resp->params.mesh,
+ sizeof(resp->params.mesh));
+ break;
+ case cmd_rte_802_11_tx_rate_query:
+ priv->adapter->txrate = resp->params.txrate.txrate;
+ break;
+ default:
+ lbs_pr_debug(1, "CMD_RESP: Unknown command response %#x\n",
+ resp->command);
+ break;
+ }
+ return ret;
+}
+
+int libertas_process_rx_command(wlan_private * priv)
+{
+ u16 respcmd;
+ struct cmd_ds_command *resp;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ ulong flags;
+ u16 result;
+
+ ENTER();
+
+ lbs_pr_debug(1, "CMD_RESP: @ %lu\n", jiffies);
+
+ /* Now we got response from FW, cancel the command timer */
+ del_timer(&adapter->command_timer);
+
+ mutex_lock(&adapter->lock);
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+
+ if (!adapter->cur_cmd) {
+ lbs_pr_debug(1, "CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
+ ret = -1;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ goto done;
+ }
+ resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
+
+ lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
+ priv->wlan_dev.upld_len);
+
+ respcmd = le16_to_cpu(resp->command);
+
+ result = le16_to_cpu(resp->result);
+
+ lbs_pr_debug(1, "CMD_RESP: %x result: %d length: %d\n", respcmd,
+ result, priv->wlan_dev.upld_len);
+
+ if (!(respcmd & 0x8000)) {
+ lbs_pr_debug(1, "Invalid response to command!");
+ adapter->cur_cmd_retcode = -1;
+ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->nr_cmd_pending--;
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ ret = -1;
+ goto done;
+ }
+
+ /* Store the response code to cur_cmd_retcode. */
+ adapter->cur_cmd_retcode = le16_to_cpu(resp->result);
+
+ if (respcmd == cmd_ret_802_11_ps_mode) {
+ struct cmd_ds_802_11_ps_mode *psmode;
+
+ psmode = &resp->params.psmode;
+ lbs_pr_debug(1,
+ "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+ resp->result, psmode->action);
+ psmode->action = cpu_to_le16(psmode->action);
+
+ if (result) {
+ lbs_pr_debug(1, "CMD_RESP: PS command failed- %#x \n",
+ resp->result);
+ if (adapter->inframode == wlan802_11ibss) {
+ /*
+ * We should not re-try enter-ps command in
+ * ad-hoc mode. It takes place in
+ * libertas_execute_next_command().
+ */
+ if (psmode->action == cmd_subcmd_enter_ps)
+ adapter->psmode =
+ wlan802_11powermodecam;
+ }
+ } else if (psmode->action == cmd_subcmd_enter_ps) {
+ adapter->needtowakeup = 0;
+ adapter->psstate = PS_STATE_AWAKE;
+
+ lbs_pr_debug(1, "CMD_RESP: Enter_PS command response\n");
+ if (adapter->connect_status != libertas_connected) {
+ /*
+ * When Deauth Event received before Enter_PS command
+ * response, We need to wake up the firmware.
+ */
+ lbs_pr_debug(1,
+ "Disconnected, Going to invoke libertas_ps_wakeup\n");
+
+ mutex_unlock(&adapter->lock);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ libertas_ps_wakeup(priv, 0);
+ mutex_lock(&adapter->lock);
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ }
+ } else if (psmode->action == cmd_subcmd_exit_ps) {
+ adapter->needtowakeup = 0;
+ adapter->psstate = PS_STATE_FULL_POWER;
+ lbs_pr_debug(1, "CMD_RESP: Exit_PS command response\n");
+ } else {
+ lbs_pr_debug(1, "CMD_RESP: PS- action=0x%X\n",
+ psmode->action);
+ }
+
+ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->nr_cmd_pending--;
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ ret = 0;
+ goto done;
+ }
+
+ if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
+ /* Copy the response back to response buffer */
+ memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
+
+ adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
+ }
+
+ /* If the command is not successful, cleanup and return failure */
+ if ((result != 0 || !(respcmd & 0x8000))) {
+ lbs_pr_debug(1, "CMD_RESP: command reply %#x result=%#x\n",
+ resp->command, resp->result);
+ /*
+ * Handling errors here
+ */
+ switch (respcmd) {
+ case cmd_ret_hw_spec_info:
+ case cmd_ret_802_11_reset:
+ lbs_pr_debug(1, "CMD_RESP: Reset command failed\n");
+ break;
+
+ }
+
+ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->nr_cmd_pending--;
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ ret = -1;
+ goto done;
+ }
+
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ ret = handle_cmd_response(respcmd, resp, priv);
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->cur_cmd) {
+ /* Clean up and Put current command back to cmdfreeq */
+ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->nr_cmd_pending--;
+ WARN_ON(adapter->nr_cmd_pending > 128);
+ adapter->cur_cmd = NULL;
+ }
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+done:
+ mutex_unlock(&adapter->lock);
+ LEAVE();
+ return ret;
+}
+
+int libertas_process_event(wlan_private * priv)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+ u32 eventcause;
+
+ spin_lock_irq(&adapter->driver_lock);
+ eventcause = adapter->eventcause;
+ spin_unlock_irq(&adapter->driver_lock);
+
+ ENTER();
+
+ lbs_pr_debug(1, "EVENT Cause %x\n", eventcause);
+
+ switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
+ case MACREG_INT_CODE_LINK_SENSED:
+ lbs_pr_debug(1, "EVENT: MACREG_INT_CODE_LINK_SENSED\n");
+ break;
+
+ case MACREG_INT_CODE_DEAUTHENTICATED:
+ lbs_pr_debug(1, "EVENT: Deauthenticated\n");
+ libertas_mac_event_disconnected(priv);
+ break;
+
+ case MACREG_INT_CODE_DISASSOCIATED:
+ lbs_pr_debug(1, "EVENT: Disassociated\n");
+ libertas_mac_event_disconnected(priv);
+ break;
+
+ case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
+ lbs_pr_debug(1, "EVENT: Link lost\n");
+ libertas_mac_event_disconnected(priv);
+ break;
+
+ case MACREG_INT_CODE_PS_SLEEP:
+ lbs_pr_debug(1, "EVENT: SLEEP\n");
+ lbs_pr_debug(1, "_");
+
+ /* handle unexpected PS SLEEP event */
+ if (adapter->psstate == PS_STATE_FULL_POWER) {
+ lbs_pr_debug(1,
+ "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
+ break;
+ }
+ adapter->psstate = PS_STATE_PRE_SLEEP;
+
+ libertas_ps_confirm_sleep(priv, (u16) adapter->psmode);
+
+ break;
+
+ case MACREG_INT_CODE_PS_AWAKE:
+ lbs_pr_debug(1, "EVENT: AWAKE \n");
+ lbs_pr_debug(1, "|");
+
+ /* handle unexpected PS AWAKE event */
+ if (adapter->psstate == PS_STATE_FULL_POWER) {
+ lbs_pr_debug(1,
+ "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
+ break;
+ }
+
+ adapter->psstate = PS_STATE_AWAKE;
+
+ if (adapter->needtowakeup) {
+ /*
+ * wait for the command processing to finish
+ * before resuming sending
+ * adapter->needtowakeup will be set to FALSE
+ * in libertas_ps_wakeup()
+ */
+ lbs_pr_debug(1, "Waking up...\n");
+ libertas_ps_wakeup(priv, 0);
+ }
+ break;
+
+ case MACREG_INT_CODE_MIC_ERR_UNICAST:
+ lbs_pr_debug(1, "EVENT: UNICAST MIC ERROR\n");
+ handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
+ break;
+
+ case MACREG_INT_CODE_MIC_ERR_MULTICAST:
+ lbs_pr_debug(1, "EVENT: MULTICAST MIC ERROR\n");
+ handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
+ break;
+ case MACREG_INT_CODE_MIB_CHANGED:
+ case MACREG_INT_CODE_INIT_DONE:
+ break;
+
+ case MACREG_INT_CODE_ADHOC_BCN_LOST:
+ lbs_pr_debug(1, "EVENT: HWAC - ADHOC BCN LOST\n");
+ break;
+
+ case MACREG_INT_CODE_RSSI_LOW:
+ lbs_pr_alert( "EVENT: RSSI_LOW\n");
+ break;
+ case MACREG_INT_CODE_SNR_LOW:
+ lbs_pr_alert( "EVENT: SNR_LOW\n");
+ break;
+ case MACREG_INT_CODE_MAX_FAIL:
+ lbs_pr_alert( "EVENT: MAX_FAIL\n");
+ break;
+ case MACREG_INT_CODE_RSSI_HIGH:
+ lbs_pr_alert( "EVENT: RSSI_HIGH\n");
+ break;
+ case MACREG_INT_CODE_SNR_HIGH:
+ lbs_pr_alert( "EVENT: SNR_HIGH\n");
+ break;
+
+ default:
+ lbs_pr_alert( "EVENT: unknown event id: %#x\n",
+ eventcause >> SBI_EVENT_CAUSE_SHIFT);
+ break;
+ }
+
+ spin_lock_irq(&adapter->driver_lock);
+ adapter->eventcause = 0;
+ spin_unlock_irq(&adapter->driver_lock);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
new file mode 100644
index 000000000000..51dfd202f558
--- /dev/null
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -0,0 +1,1935 @@
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <net/iw_handler.h>
+#include "dev.h"
+#include "decl.h"
+#include "host.h"
+
+static struct dentry *libertas_dir = NULL;
+static char *szStates[] = {
+ "Connected",
+ "Disconnected"
+};
+
+void libertas_debug_init(wlan_private * priv, struct net_device *dev);
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static const size_t len = PAGE_SIZE;
+
+static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ ssize_t res;
+
+ pos += snprintf(buf+pos, len-pos, "state = %s\n",
+ szStates[priv->adapter->connect_status]);
+ pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
+ (u32) priv->adapter->regioncode);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+ free_page(addr);
+ return res;
+}
+
+
+static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ size_t pos = 0;
+ int numscansdone = 0, res;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ pos += snprintf(buf+pos, len-pos,
+ "---------------------------------------");
+ pos += snprintf(buf+pos, len-pos,
+ "---------------------------------------\n");
+ pos += snprintf(buf+pos, len-pos,
+ "# | ch | ss | bssid | cap | TSF | Qual | SSID \n");
+ pos += snprintf(buf+pos, len-pos,
+ "---------------------------------------");
+ pos += snprintf(buf+pos, len-pos,
+ "---------------------------------------\n");
+
+ while (numscansdone < priv->adapter->numinscantable) {
+ struct bss_descriptor *pbssinfo;
+ u16 cap;
+
+ pbssinfo = &priv->adapter->scantable[numscansdone];
+ memcpy(&cap, &pbssinfo->cap, sizeof(cap));
+ pos += snprintf(buf+pos, len-pos,
+ "%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |",
+ numscansdone, pbssinfo->channel, pbssinfo->rssi,
+ pbssinfo->macaddress[0], pbssinfo->macaddress[1],
+ pbssinfo->macaddress[2], pbssinfo->macaddress[3],
+ pbssinfo->macaddress[4], pbssinfo->macaddress[5]);
+ pos += snprintf(buf+pos, len-pos, " %04x-", cap);
+ pos += snprintf(buf+pos, len-pos, "%c%c%c |",
+ pbssinfo->cap.ibss ? 'A' : 'I',
+ pbssinfo->cap.privacy ? 'P' : ' ',
+ pbssinfo->cap.spectrummgmt ? 'S' : ' ');
+ pos += snprintf(buf+pos, len-pos, " %08llx |", pbssinfo->networktsf);
+ pos += snprintf(buf+pos, len-pos, " %d |",
+ SCAN_RSSI(priv->adapter->scantable[numscansdone].rssi));
+
+ pos += snprintf(buf+pos, len-pos, " %s\n", pbssinfo->ssid.ssid);
+
+ numscansdone++;
+ }
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_sleepparams_write(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t buf_size, res;
+ int p1, p2, p3, p4, p5, p6;
+ struct sleep_params sp;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, user_buf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
+ if (res != 6) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ sp.sp_error = p1;
+ sp.sp_offset = p2;
+ sp.sp_stabletime = p3;
+ sp.sp_calcontrol = p4;
+ sp.sp_extsleepclk = p5;
+ sp.sp_reserved = p6;
+
+ memcpy(&priv->adapter->sp, &sp, sizeof(struct sleep_params));
+
+ res = libertas_prepare_and_send_command(priv,
+ cmd_802_11_sleep_params,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (!res)
+ res = count;
+ else
+ res = -EINVAL;
+
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res;
+ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_prepare_and_send_command(priv,
+ cmd_802_11_sleep_params,
+ cmd_act_get,
+ cmd_option_waitforrsp, 0, NULL);
+ if (res) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
+ adapter->sp.sp_offset, adapter->sp.sp_stabletime,
+ adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
+ adapter->sp.sp_reserved);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ struct WLAN_802_11_SSID extscan_ssid;
+ union iwreq_data wrqu;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1);
+ extscan_ssid.ssidlength = strlen(buf)-1;
+
+ libertas_send_specific_SSID_scan(priv, &extscan_ssid, 1);
+
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+out_unlock:
+ free_page(addr);
+ return count;
+}
+
+static int libertas_parse_chan(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
+{
+ char *start, *end, *hold, *str;
+ int i = 0;
+
+ start = strstr(buf, "chan=");
+ if (!start)
+ return -EINVAL;
+ start += 5;
+ end = strstr(start, " ");
+ if (!end)
+ end = buf + count;
+ hold = kzalloc((end - start)+1, GFP_KERNEL);
+ if (!hold)
+ return -ENOMEM;
+ strncpy(hold, start, end - start);
+ hold[(end-start)+1] = '\0';
+ while(hold && (str = strsep(&hold, ","))) {
+ int chan;
+ char band, passive = 0;
+ sscanf(str, "%d%c%c", &chan, &band, &passive);
+ scan_cfg->chanlist[i].channumber = chan;
+ scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
+ if (band == 'b' || band == 'g')
+ scan_cfg->chanlist[i].radiotype = 0;
+ else if (band == 'a')
+ scan_cfg->chanlist[i].radiotype = 1;
+
+ scan_cfg->chanlist[i].scantime = dur;
+ i++;
+ }
+
+ kfree(hold);
+ return i;
+}
+
+static void libertas_parse_bssid(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold;
+ unsigned int mac[ETH_ALEN];
+ int i;
+
+ hold = strstr(buf, "bssid=");
+ if (!hold)
+ return;
+ hold += 6;
+ sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3,
+ mac+4, mac+5);
+ for(i=0;i<ETH_ALEN;i++)
+ scan_cfg->specificBSSID[i] = mac[i];
+}
+
+static void libertas_parse_ssid(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold, *end;
+ ssize_t size;
+
+ hold = strstr(buf, "ssid=");
+ if (!hold)
+ return;
+ hold += 5;
+ end = strstr(hold, " ");
+ if (!end)
+ end = buf + count - 1;
+
+ size = min(IW_ESSID_MAX_SIZE, end - hold);
+ strncpy(scan_cfg->specificSSID, hold, size);
+
+ return;
+}
+
+static void libertas_parse_keep(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold;
+ int val;
+
+ hold = strstr(buf, "keep=");
+ if (!hold)
+ return;
+ hold += 5;
+ sscanf(hold, "%d", &val);
+
+ if (val != 0)
+ val = 1;
+
+ scan_cfg->keeppreviousscan = val;
+ return;
+}
+
+static int libertas_parse_dur(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold;
+ int val;
+
+ hold = strstr(buf, "dur=");
+ if (!hold)
+ return 0;
+ hold += 4;
+ sscanf(hold, "%d", &val);
+
+ return val;
+}
+
+static void libertas_parse_probes(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold;
+ int val;
+
+ hold = strstr(buf, "probes=");
+ if (!hold)
+ return;
+ hold += 7;
+ sscanf(hold, "%d", &val);
+
+ scan_cfg->numprobes = val;
+
+ return;
+}
+
+static void libertas_parse_type(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold;
+ int val;
+
+ hold = strstr(buf, "type=");
+ if (!hold)
+ return;
+ hold += 5;
+ sscanf(hold, "%d", &val);
+
+ /* type=1,2 or 3 */
+ if (val < 1 || val > 3)
+ return;
+
+ scan_cfg->bsstype = val;
+
+ return;
+}
+
+static ssize_t libertas_setuserscan(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ struct wlan_ioctl_user_scan_cfg *scan_cfg;
+ union iwreq_data wrqu;
+ int dur;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
+ if (!scan_cfg)
+ return -ENOMEM;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;
+
+ dur = libertas_parse_dur(buf, count, scan_cfg);
+ libertas_parse_chan(buf, count, scan_cfg, dur);
+ libertas_parse_bssid(buf, count, scan_cfg);
+ libertas_parse_ssid(buf, count, scan_cfg);
+ libertas_parse_keep(buf, count, scan_cfg);
+ libertas_parse_probes(buf, count, scan_cfg);
+ libertas_parse_type(buf, count, scan_cfg);
+
+ wlan_scan_networks(priv, scan_cfg);
+ wait_event_interruptible(priv->adapter->cmd_pending,
+ !priv->adapter->nr_cmd_pending);
+
+ memset(&wrqu, 0x00, sizeof(union iwreq_data));
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+out_unlock:
+ free_page(addr);
+ kfree(scan_cfg);
+ return count;
+}
+
+static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
+ struct cmd_ctrl_node **cmdnode,
+ struct cmd_ds_command **cmd)
+{
+ u16 wait_option = cmd_option_waitforrsp;
+
+ if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
+ lbs_pr_debug(1, "failed libertas_get_free_cmd_ctrl_node\n");
+ return -ENOMEM;
+ }
+ if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
+ lbs_pr_debug(1, "failed to allocate response buffer!\n");
+ return -ENOMEM;
+ }
+ libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
+ init_waitqueue_head(&(*cmdnode)->cmdwait_q);
+ (*cmdnode)->pdata_buf = *response_buf;
+ (*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
+ (*cmdnode)->cmdwaitqwoken = 0;
+ *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
+ (*cmd)->command = cmd_802_11_subscribe_event;
+ (*cmd)->seqnum = ++priv->adapter->seqnum;
+ (*cmd)->result = 0;
+ return 0;
+}
+
+static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_rssithreshold *Lowrssi;
+ case TLV_TYPE_RSSI_LOW:
+ Lowrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+ Lowrssi->rssivalue,
+ Lowrssi->rssifreq,
+ (event->events & 0x0001)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static u16 libertas_get_events_bitmap(wlan_private *priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res;
+ u16 event_bitmap;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ return res;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ return 0;
+ }
+
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ event_bitmap = event->events;
+ kfree(response_buf);
+ return event_bitmap;
+}
+
+static ssize_t libertas_lowrssi_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_rssithreshold *rssi_threshold;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_rssithreshold));
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+ rssi_threshold->header.type = cpu_to_le16(0x0104);
+ rssi_threshold->header.len = 2;
+ rssi_threshold->rssivalue = cpu_to_le16(value);
+ rssi_threshold->rssifreq = cpu_to_le16(freq);
+ event_bitmap |= subscribed ? 0x0001 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_snrthreshold *LowSnr;
+ case TLV_TYPE_SNR_LOW:
+ LowSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+ LowSnr->snrvalue,
+ LowSnr->snrfreq,
+ (event->events & 0x0002)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_lowsnr_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_snrthreshold *snr_threshold;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_snrthreshold));
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+ snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
+ snr_threshold->header.len = 2;
+ snr_threshold->snrvalue = cpu_to_le16(value);
+ snr_threshold->snrfreq = cpu_to_le16(freq);
+ event_bitmap |= subscribed ? 0x0002 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ res = count;
+
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_failurecount *failcount;
+ case TLV_TYPE_FAILCOUNT:
+ failcount = (struct mrvlietypes_failurecount *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+ failcount->failvalue,
+ failcount->Failfreq,
+ (event->events & 0x0004)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_failurecount);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_failcount_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_failurecount *failcount;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_failurecount));
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ failcount = (struct mrvlietypes_failurecount *)(ptr);
+ failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
+ failcount->header.len = 2;
+ failcount->failvalue = cpu_to_le16(value);
+ failcount->Failfreq = cpu_to_le16(freq);
+ event_bitmap |= subscribed ? 0x0004 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = (struct cmd_ds_command *)response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ free_page(addr);
+ kfree(response_buf);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ free_page(addr);
+ kfree(response_buf);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_beaconsmissed *bcnmiss;
+ case TLV_TYPE_BCNMISS:
+ bcnmiss = (struct mrvlietypes_beaconsmissed *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
+ bcnmiss->beaconmissed,
+ (event->events & 0x0008)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_bcnmiss_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_beaconsmissed *bcnmiss;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_beaconsmissed));
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
+ bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
+ bcnmiss->header.len = 2;
+ bcnmiss->beaconmissed = cpu_to_le16(value);
+ event_bitmap |= subscribed ? 0x0008 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ free_page(addr);
+ kfree(response_buf);
+ return 0;
+ }
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_rssithreshold *Highrssi;
+ case TLV_TYPE_RSSI_HIGH:
+ Highrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+ Highrssi->rssivalue,
+ Highrssi->rssifreq,
+ (event->events & 0x0010)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_highrssi_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_rssithreshold *rssi_threshold;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_rssithreshold));
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+ rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
+ rssi_threshold->header.len = 2;
+ rssi_threshold->rssivalue = cpu_to_le16(value);
+ rssi_threshold->rssifreq = cpu_to_le16(freq);
+ event_bitmap |= subscribed ? 0x0010 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ return 0;
+ }
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_snrthreshold *HighSnr;
+ case TLV_TYPE_SNR_HIGH:
+ HighSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+ HighSnr->snrvalue,
+ HighSnr->snrfreq,
+ (event->events & 0x0020)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_highsnr_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_snrthreshold *snr_threshold;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_snrthreshold));
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+ snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
+ snr_threshold->header.len = 2;
+ snr_threshold->snrvalue = cpu_to_le16(value);
+ snr_threshold->snrfreq = cpu_to_le16(freq);
+ event_bitmap |= subscribed ? 0x0020 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_offset_value offval;
+ ssize_t pos = 0;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ offval.offset = priv->mac_offset;
+ offval.value = 0;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_mac_reg_access, 0,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+ pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
+ priv->mac_offset, adapter->offsetvalue.value);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return ret;
+}
+
+static ssize_t libertas_rdmac_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_wrmac_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ u32 offset, value;
+ struct wlan_offset_value offval;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%x %x", &offset, &value);
+ if (res != 2) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ offval.offset = offset;
+ offval.value = value;
+ res = libertas_prepare_and_send_command(priv,
+ cmd_mac_reg_access, 1,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_offset_value offval;
+ ssize_t pos = 0;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ offval.offset = priv->bbp_offset;
+ offval.value = 0;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_bbp_reg_access, 0,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+ pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
+ priv->bbp_offset, adapter->offsetvalue.value);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+
+ return ret;
+}
+
+static ssize_t libertas_rdbbp_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_wrbbp_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ u32 offset, value;
+ struct wlan_offset_value offval;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%x %x", &offset, &value);
+ if (res != 2) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ offval.offset = offset;
+ offval.value = value;
+ res = libertas_prepare_and_send_command(priv,
+ cmd_bbp_reg_access, 1,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_offset_value offval;
+ ssize_t pos = 0;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ offval.offset = priv->rf_offset;
+ offval.value = 0;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_rf_reg_access, 0,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+ pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
+ priv->rf_offset, adapter->offsetvalue.value);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+
+ return ret;
+}
+
+static ssize_t libertas_rdrf_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_wrrf_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ u32 offset, value;
+ struct wlan_offset_value offval;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%x %x", &offset, &value);
+ if (res != 2) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ offval.offset = offset;
+ offval.value = value;
+ res = libertas_prepare_and_send_command(priv,
+ cmd_rf_reg_access, 1,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+#define FOPS(fread, fwrite) { \
+ .owner = THIS_MODULE, \
+ .open = open_file_generic, \
+ .read = (fread), \
+ .write = (fwrite), \
+}
+
+struct libertas_debugfs_files {
+ char *name;
+ int perm;
+ struct file_operations fops;
+};
+
+struct libertas_debugfs_files debugfs_files[] = {
+ { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
+ { "getscantable", 0444, FOPS(libertas_getscantable,
+ write_file_dummy), },
+ { "sleepparams", 0644, FOPS(libertas_sleepparams_read,
+ libertas_sleepparams_write), },
+ { "extscan", 0600, FOPS(NULL, libertas_extscan), },
+ { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
+};
+
+struct libertas_debugfs_files debugfs_events_files[] = {
+ {"low_rssi", 0644, FOPS(libertas_lowrssi_read,
+ libertas_lowrssi_write), },
+ {"low_snr", 0644, FOPS(libertas_lowsnr_read,
+ libertas_lowsnr_write), },
+ {"failure_count", 0644, FOPS(libertas_failcount_read,
+ libertas_failcount_write), },
+ {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
+ libertas_bcnmiss_write), },
+ {"high_rssi", 0644, FOPS(libertas_highrssi_read,
+ libertas_highrssi_write), },
+ {"high_snr", 0644, FOPS(libertas_highsnr_read,
+ libertas_highsnr_write), },
+};
+
+struct libertas_debugfs_files debugfs_regs_files[] = {
+ {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
+ {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
+ {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
+ {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
+ {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
+ {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
+};
+
+void libertas_debugfs_init(void)
+{
+ if (!libertas_dir)
+ libertas_dir = debugfs_create_dir("libertas_wireless", NULL);
+
+ return;
+}
+
+void libertas_debugfs_remove(void)
+{
+ if (libertas_dir)
+ debugfs_remove(libertas_dir);
+ return;
+}
+
+void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
+{
+ int i;
+ struct libertas_debugfs_files *files;
+ if (!libertas_dir)
+ goto exit;
+
+ priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
+ if (!priv->debugfs_dir)
+ goto exit;
+
+ for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
+ files = &debugfs_files[i];
+ priv->debugfs_files[i] = debugfs_create_file(files->name,
+ files->perm,
+ priv->debugfs_dir,
+ priv,
+ &files->fops);
+ }
+
+ priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
+ if (!priv->events_dir)
+ goto exit;
+
+ for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
+ files = &debugfs_events_files[i];
+ priv->debugfs_events_files[i] = debugfs_create_file(files->name,
+ files->perm,
+ priv->events_dir,
+ priv,
+ &files->fops);
+ }
+
+ priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
+ if (!priv->regs_dir)
+ goto exit;
+
+ for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
+ files = &debugfs_regs_files[i];
+ priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
+ files->perm,
+ priv->regs_dir,
+ priv,
+ &files->fops);
+ }
+
+#ifdef PROC_DEBUG
+ libertas_debug_init(priv, dev);
+#endif
+exit:
+ return;
+}
+
+void libertas_debugfs_remove_one(wlan_private *priv)
+{
+ int i;
+
+ for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
+ debugfs_remove(priv->debugfs_regs_files[i]);
+
+ debugfs_remove(priv->regs_dir);
+
+ for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+ debugfs_remove(priv->debugfs_events_files[i]);
+
+ debugfs_remove(priv->events_dir);
+#ifdef PROC_DEBUG
+ debugfs_remove(priv->debugfs_debug);
+#endif
+ for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+ debugfs_remove(priv->debugfs_files[i]);
+}
+
+/* debug entry */
+
+#define item_size(n) (FIELD_SIZEOF(wlan_adapter, n))
+#define item_addr(n) (offsetof(wlan_adapter, n))
+
+struct debug_data {
+ char name[32];
+ u32 size;
+ u32 addr;
+};
+
+/* To debug any member of wlan_adapter, simply add one line here.
+ */
+static struct debug_data items[] = {
+ {"intcounter", item_size(intcounter), item_addr(intcounter)},
+ {"psmode", item_size(psmode), item_addr(psmode)},
+ {"psstate", item_size(psstate), item_addr(psstate)},
+};
+
+static int num_of_items = ARRAY_SIZE(items);
+
+/**
+ * @brief proc read function
+ *
+ * @param page pointer to buffer
+ * @param s read data starting position
+ * @param off offset
+ * @param cnt counter
+ * @param eof end of file flag
+ * @param data data to output
+ * @return number of output data
+ */
+static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ int val = 0;
+ size_t pos = 0;
+ ssize_t res;
+ char *p;
+ int i;
+ struct debug_data *d;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ p = buf;
+
+ d = (struct debug_data *)file->private_data;
+
+ for (i = 0; i < num_of_items; i++) {
+ if (d[i].size == 1)
+ val = *((u8 *) d[i].addr);
+ else if (d[i].size == 2)
+ val = *((u16 *) d[i].addr);
+ else if (d[i].size == 4)
+ val = *((u32 *) d[i].addr);
+
+ pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
+ }
+
+ res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
+
+ free_page(addr);
+ return res;
+}
+
+/**
+ * @brief proc write function
+ *
+ * @param f file pointer
+ * @param buf pointer to data buffer
+ * @param cnt data number to write
+ * @param data data to write
+ * @return number of data
+ */
+static int wlan_debugfs_write(struct file *f, const char __user *buf,
+ size_t cnt, loff_t *ppos)
+{
+ int r, i;
+ char *pdata;
+ char *p;
+ char *p0;
+ char *p1;
+ char *p2;
+ struct debug_data *d = (struct debug_data *)f->private_data;
+
+ pdata = (char *)kmalloc(cnt, GFP_KERNEL);
+ if (pdata == NULL)
+ return 0;
+
+ if (copy_from_user(pdata, buf, cnt)) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ kfree(pdata);
+ return 0;
+ }
+
+ p0 = pdata;
+ for (i = 0; i < num_of_items; i++) {
+ do {
+ p = strstr(p0, d[i].name);
+ if (p == NULL)
+ break;
+ p1 = strchr(p, '\n');
+ if (p1 == NULL)
+ break;
+ p0 = p1++;
+ p2 = strchr(p, '=');
+ if (!p2)
+ break;
+ p2++;
+ r = simple_strtoul(p2, NULL, 0);
+ if (d[i].size == 1)
+ *((u8 *) d[i].addr) = (u8) r;
+ else if (d[i].size == 2)
+ *((u16 *) d[i].addr) = (u16) r;
+ else if (d[i].size == 4)
+ *((u32 *) d[i].addr) = (u32) r;
+ break;
+ } while (1);
+ }
+ kfree(pdata);
+
+ return cnt;
+}
+
+static struct file_operations libertas_debug_fops = {
+ .owner = THIS_MODULE,
+ .open = open_file_generic,
+ .write = wlan_debugfs_write,
+ .read = wlan_debugfs_read,
+};
+
+/**
+ * @brief create debug proc file
+ *
+ * @param priv pointer wlan_private
+ * @param dev pointer net_device
+ * @return N/A
+ */
+void libertas_debug_init(wlan_private * priv, struct net_device *dev)
+{
+ int i;
+
+ if (!priv->debugfs_dir)
+ return;
+
+ for (i = 0; i < num_of_items; i++)
+ items[i].addr += (u32) priv->adapter;
+
+ priv->debugfs_debug = debugfs_create_file("debug", 0644,
+ priv->debugfs_dir, &items[0],
+ &libertas_debug_fops);
+}
+
+/**
+ * @brief remove proc file
+ *
+ * @param priv pointer wlan_private
+ * @return N/A
+ */
+void libertas_debug_remove(wlan_private * priv)
+{
+ debugfs_remove(priv->debugfs_debug);
+}
diff --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h
new file mode 100644
index 000000000000..880a11b95d26
--- /dev/null
+++ b/drivers/net/wireless/libertas/debugfs.h
@@ -0,0 +1,6 @@
+void libertas_debugfs_init(void);
+void libertas_debugfs_remove(void);
+
+void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev);
+void libertas_debugfs_remove_one(wlan_private *priv);
+
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
new file mode 100644
index 000000000000..606bdd002be7
--- /dev/null
+++ b/drivers/net/wireless/libertas/decl.h
@@ -0,0 +1,83 @@
+/**
+ * This file contains declaration referring to
+ * functions defined in other source files
+ */
+
+#ifndef _WLAN_DECL_H_
+#define _WLAN_DECL_H_
+
+#include "defs.h"
+
+/** Function Prototype Declaration */
+struct wlan_private;
+struct sk_buff;
+struct net_device;
+
+extern char *libertas_fw_name;
+
+void libertas_free_adapter(wlan_private * priv);
+int libertas_set_mac_packet_filter(wlan_private * priv);
+
+int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt);
+void libertas_send_tx_feedback(wlan_private * priv);
+u8 libertas_check_last_packet_indication(wlan_private * priv);
+
+int libertas_free_cmd_buffer(wlan_private * priv);
+struct cmd_ctrl_node;
+struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv);
+
+void libertas_set_cmd_ctrl_node(wlan_private * priv,
+ struct cmd_ctrl_node *ptempnode,
+ u32 cmd_oid, u16 wait_option, void *pdata_buf);
+
+int libertas_prepare_and_send_command(wlan_private * priv,
+ u16 cmd_no,
+ u16 cmd_action,
+ u16 wait_option, u32 cmd_oid, void *pdata_buf);
+
+void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail);
+
+int libertas_allocate_cmd_buffer(wlan_private * priv);
+int libertas_execute_next_command(wlan_private * priv);
+int libertas_process_event(wlan_private * priv);
+void libertas_interrupt(struct net_device *);
+int libertas_set_radio_control(wlan_private * priv);
+u32 libertas_index_to_data_rate(u8 index);
+u8 libertas_data_rate_to_index(u32 rate);
+void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
+
+int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
+
+/** The proc fs interface */
+int libertas_process_rx_command(wlan_private * priv);
+int libertas_process_tx(wlan_private * priv, struct sk_buff *skb);
+void libertas_cleanup_and_insert_cmd(wlan_private * priv,
+ struct cmd_ctrl_node *ptempcmd);
+void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
+ struct cmd_ctrl_node *ptempcmd);
+
+int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band);
+
+int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *);
+
+void libertas_ps_sleep(wlan_private * priv, int wait_option);
+void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode);
+void libertas_ps_wakeup(wlan_private * priv, int wait_option);
+
+void libertas_tx_runqueue(wlan_private *priv);
+
+extern struct chan_freq_power *libertas_find_cfp_by_band_and_channel(
+ wlan_adapter * adapter, u8 band, u16 channel);
+
+extern void libertas_mac_event_disconnected(wlan_private * priv);
+
+void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str);
+
+int reset_device(wlan_private *priv);
+/* main.c */
+extern struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band,
+ int *cfp_no);
+wlan_private *wlan_add_card(void *card);
+int wlan_remove_card(void *card);
+
+#endif /* _WLAN_DECL_H_ */
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
new file mode 100644
index 000000000000..fb1478c1b87d
--- /dev/null
+++ b/drivers/net/wireless/libertas/defs.h
@@ -0,0 +1,369 @@
+/**
+ * This header file contains global constant/enum definitions,
+ * global variable declaration.
+ */
+#ifndef _WLAN_DEFS_H_
+#define _WLAN_DEFS_H_
+
+#include <linux/spinlock.h>
+
+extern unsigned int libertas_debug;
+
+#define DRV_NAME "usb8xxx"
+
+#define lbs_pr_info(format, args...) \
+ printk(KERN_INFO DRV_NAME": " format, ## args)
+#define lbs_pr_err(format, args...) \
+ printk(KERN_ERR DRV_NAME": " format, ## args)
+#define lbs_pr_alert(format, args...) \
+ printk(KERN_ALERT DRV_NAME": " format, ## args)
+
+#ifdef DEBUG
+#define lbs_pr_debug(level, format, args...) \
+ do { if (libertas_debug >= level) \
+ printk(KERN_INFO DRV_NAME": " format, ##args); } while (0)
+#define lbs_dev_dbg(level, device, format, args...) \
+ lbs_pr_debug(level, "%s: " format, \
+ (device)->bus_id , ## args)
+
+static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
+{
+ int i = 0;
+
+ if (!libertas_debug)
+ return;
+
+ printk(KERN_DEBUG "%s: ", prompt);
+ for (i = 1; i <= len; i++) {
+ printk(KERN_DEBUG "%02x ", (u8) * buf);
+ buf++;
+ }
+ printk("\n");
+}
+#else
+#define lbs_pr_debug(level, format, args...) do {} while (0)
+#define lbs_dev_dbg(level, device, format, args...) do {} while (0)
+#define lbs_dbg_hex(x,y,z) do {} while (0)
+#endif
+
+#define ENTER() lbs_pr_debug(1, "Enter: %s, %s:%i\n", \
+ __FUNCTION__, __FILE__, __LINE__)
+#define LEAVE() lbs_pr_debug(1, "Leave: %s, %s:%i\n", \
+ __FUNCTION__, __FILE__, __LINE__)
+
+/** Buffer Constants */
+
+/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
+* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+* driver has more local TxPDs. Each TxPD on the host memory is associated
+* with a Tx control node. The driver maintains 8 RxPD descriptors for
+* station firmware to store Rx packet information.
+*
+* Current version of MAC has a 32x6 multicast address buffer.
+*
+* 802.11b can have up to 14 channels, the driver keeps the
+* BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+*/
+
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
+#define MRVDRV_NUM_OF_CMD_BUFFER 10
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
+#define MRVDRV_MAX_CHANNEL_SIZE 14
+#define MRVDRV_MAX_BSSID_LIST 64
+#define MRVDRV_ASSOCIATION_TIME_OUT 255
+#define MRVDRV_SNAP_HEADER_LEN 8
+
+#define WLAN_UPLD_SIZE 2312
+#define DEV_NAME_LEN 32
+
+/** Misc constants */
+/* This section defines 802.11 specific contants */
+
+#define MRVDRV_MAX_BSS_DESCRIPTS 16
+#define MRVDRV_MAX_REGION_CODE 6
+
+#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
+#define MRVDRV_MIN_MULTIPLE_DTIM 1
+#define MRVDRV_MAX_MULTIPLE_DTIM 5
+#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
+
+#define MRVDRV_DEFAULT_LISTEN_INTERVAL 10
+
+#define MRVDRV_CHANNELS_PER_SCAN 4
+#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
+
+#define MRVDRV_DEBUG_RX_PATH 0x00000001
+#define MRVDRV_DEBUG_TX_PATH 0x00000002
+
+#define MRVDRV_MIN_BEACON_INTERVAL 20
+#define MRVDRV_MAX_BEACON_INTERVAL 1000
+#define MRVDRV_BEACON_INTERVAL 100
+
+/** TxPD status */
+
+/* Station firmware use TxPD status field to report final Tx transmit
+* result, Bit masks are used to present combined situations.
+*/
+
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/** Tx mesh flag */
+/* Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define TxPD_CONTROL_WDS_FRAME (1<<17)
+#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
+
+/** RxPD status */
+
+#define MRVDRV_RXPD_STATUS_OK 0x0001
+
+/** RxPD status - Received packet types */
+/** Rx mesh flag */
+/* Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define RxPD_CONTROL_WDS_FRAME (0x40)
+#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
+
+/** RSSI-related defines */
+/* RSSI constants are used to implement 802.11 RSSI threshold
+* indication. if the Rx packet signal got too weak for 5 consecutive
+* times, miniport driver (driver) will report this event to wrapper
+*/
+
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
+
+/** RTS/FRAG related defines */
+#define MRVDRV_RTS_MIN_VALUE 0
+#define MRVDRV_RTS_MAX_VALUE 2347
+#define MRVDRV_FRAG_MIN_VALUE 256
+#define MRVDRV_FRAG_MAX_VALUE 2346
+
+/* This is for firmware specific length */
+#define EXTRA_LEN 36
+
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+ (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
+
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+ (ETH_FRAME_LEN + sizeof(struct rxpd) \
+ + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+#define CMD_F_HOSTCMD (1 << 0)
+#define FW_CAPINFO_WPA (1 << 0)
+
+/** WPA key LENGTH*/
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
+
+#define KEY_LEN_WPA_AES 16
+#define KEY_LEN_WPA_TKIP 32
+#define KEY_LEN_WEP_104 13
+#define KEY_LEN_WEP_40 5
+
+#define RF_ANTENNA_1 0x1
+#define RF_ANTENNA_2 0x2
+#define RF_ANTENNA_AUTO 0xFFFF
+
+#define BAND_B (0x01)
+#define BAND_G (0x02)
+#define ALL_802_11_BANDS (BAND_B | BAND_G)
+
+/** MACRO DEFINITIONS */
+#define CAL_NF(NF) ((s32)(-(s32)(NF)))
+#define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF)))
+#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
+
+#define DEFAULT_BCN_AVG_FACTOR 8
+#define DEFAULT_DATA_AVG_FACTOR 8
+#define AVG_SCALE 100
+#define CAL_AVG_SNR_NF(AVG, SNRNF, N) \
+ (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
+ ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
+ AVG_SCALE)) / N))
+
+#define B_SUPPORTED_RATES 8
+#define G_SUPPORTED_RATES 14
+
+#define WLAN_SUPPORTED_RATES 14
+
+#define MAX_LEDS 8
+
+#define IS_MESH_FRAME(x) (x->cb[6])
+#define SET_MESH_FRAME(x) (x->cb[6]=1)
+#define UNSET_MESH_FRAME(x) (x->cb[6]=0)
+
+/** Global Variable Declaration */
+typedef struct _wlan_private wlan_private;
+typedef struct _wlan_adapter wlan_adapter;
+extern const char libertas_driver_version[];
+extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
+
+extern u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES];
+
+extern u8 libertas_supported_rates[G_SUPPORTED_RATES];
+
+extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES];
+
+extern u8 libertas_adhoc_rates_b[4];
+
+/** ENUM definition*/
+/** SNRNF_TYPE */
+enum SNRNF_TYPE {
+ TYPE_BEACON = 0,
+ TYPE_RXPD,
+ MAX_TYPE_B
+};
+
+/** SNRNF_DATA*/
+enum SNRNF_DATA {
+ TYPE_NOAVG = 0,
+ TYPE_AVG,
+ MAX_TYPE_AVG
+};
+
+/** WLAN_802_11_AUTH_ALG*/
+enum WLAN_802_11_AUTH_ALG {
+ AUTH_ALG_OPEN_SYSTEM = 1,
+ AUTH_ALG_SHARED_KEY = 2,
+ AUTH_ALG_NETWORK_EAP = 8,
+};
+
+/** WLAN_802_1X_AUTH_ALG */
+enum WLAN_802_1X_AUTH_ALG {
+ WLAN_1X_AUTH_ALG_NONE = 1,
+ WLAN_1X_AUTH_ALG_LEAP = 2,
+ WLAN_1X_AUTH_ALG_TLS = 4,
+ WLAN_1X_AUTH_ALG_TTLS = 8,
+ WLAN_1X_AUTH_ALG_MD5 = 16,
+};
+
+/** WLAN_802_11_ENCRYPTION_MODE */
+enum WLAN_802_11_ENCRYPTION_MODE {
+ CIPHER_NONE,
+ CIPHER_WEP40,
+ CIPHER_TKIP,
+ CIPHER_CCMP,
+ CIPHER_WEP104,
+};
+
+/** WLAN_802_11_POWER_MODE */
+enum WLAN_802_11_POWER_MODE {
+ wlan802_11powermodecam,
+ wlan802_11powermodemax_psp,
+ wlan802_11Powermodefast_psp,
+ /*not a real mode, defined as an upper bound */
+ wlan802_11powemodemax
+};
+
+/** PS_STATE */
+enum PS_STATE {
+ PS_STATE_FULL_POWER,
+ PS_STATE_AWAKE,
+ PS_STATE_PRE_SLEEP,
+ PS_STATE_SLEEP
+};
+
+/** DNLD_STATE */
+enum DNLD_STATE {
+ DNLD_RES_RECEIVED,
+ DNLD_DATA_SENT,
+ DNLD_CMD_SENT
+};
+
+/** WLAN_MEDIA_STATE */
+enum WLAN_MEDIA_STATE {
+ libertas_connected,
+ libertas_disconnected
+};
+
+/** WLAN_802_11_PRIVACY_FILTER */
+enum WLAN_802_11_PRIVACY_FILTER {
+ wlan802_11privfilteracceptall,
+ wlan802_11privfilter8021xWEP
+};
+
+/** mv_ms_type */
+enum mv_ms_type {
+ MVMS_DAT = 0,
+ MVMS_CMD = 1,
+ MVMS_TXDONE = 2,
+ MVMS_EVENT
+};
+
+/** WLAN_802_11_NETWORK_INFRASTRUCTURE */
+enum WLAN_802_11_NETWORK_INFRASTRUCTURE {
+ wlan802_11ibss,
+ wlan802_11infrastructure,
+ wlan802_11autounknown,
+ /*defined as upper bound */
+ wlan802_11infrastructuremax
+};
+
+/** WLAN_802_11_AUTHENTICATION_MODE */
+enum WLAN_802_11_AUTHENTICATION_MODE {
+ wlan802_11authmodeopen = 0x00,
+ wlan802_11authmodeshared = 0x01,
+ wlan802_11authmodenetworkEAP = 0x80,
+};
+
+/** WLAN_802_11_WEP_STATUS */
+enum WLAN_802_11_WEP_STATUS {
+ wlan802_11WEPenabled,
+ wlan802_11WEPdisabled,
+};
+
+/** SNMP_MIB_INDEX_e */
+enum SNMP_MIB_INDEX_e {
+ desired_bsstype_i = 0,
+ op_rateset_i,
+ bcnperiod_i,
+ dtimperiod_i,
+ assocrsp_timeout_i,
+ rtsthresh_i,
+ short_retrylim_i,
+ long_retrylim_i,
+ fragthresh_i,
+ dot11d_i,
+ dot11h_i,
+ manufid_i,
+ prodID_i,
+ manuf_oui_i,
+ manuf_name_i,
+ manuf_prodname_i,
+ manuf_prodver_i,
+};
+
+/** KEY_TYPE_ID */
+enum KEY_TYPE_ID {
+ KEY_TYPE_ID_WEP = 0,
+ KEY_TYPE_ID_TKIP,
+ KEY_TYPE_ID_AES
+};
+
+/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
+enum KEY_INFO_WPA {
+ KEY_INFO_WPA_MCAST = 0x01,
+ KEY_INFO_WPA_UNICAST = 0x02,
+ KEY_INFO_WPA_ENABLED = 0x04
+};
+
+/** SNMP_MIB_VALUE_e */
+enum SNMP_MIB_VALUE_e {
+ SNMP_MIB_VALUE_INFRA = 1,
+ SNMP_MIB_VALUE_ADHOC
+};
+
+/* Default values for fwt commands. */
+#define FWT_DEFAULT_METRIC 0
+#define FWT_DEFAULT_DIR 1
+#define FWT_DEFAULT_SSN 0xffffffff
+#define FWT_DEFAULT_DSN 0
+#define FWT_DEFAULT_HOPCOUNT 0
+#define FWT_DEFAULT_TTL 0
+#define FWT_DEFAULT_EXPIRATION 0
+#define FWT_DEFAULT_SLEEPMODE 0
+#define FWT_DEFAULT_SNR 0
+
+#endif /* _WLAN_DEFS_H_ */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
new file mode 100644
index 000000000000..b1f876f9693b
--- /dev/null
+++ b/drivers/net/wireless/libertas/dev.h
@@ -0,0 +1,403 @@
+/**
+ * This file contains definitions and data structures specific
+ * to Marvell 802.11 NIC. It contains the Device Information
+ * structure wlan_adapter.
+ */
+#ifndef _WLAN_DEV_H_
+#define _WLAN_DEV_H_
+
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/ethtool.h>
+#include <linux/debugfs.h>
+
+#include "defs.h"
+#include "scan.h"
+#include "thread.h"
+
+extern struct ethtool_ops libertas_ethtool_ops;
+
+#define MAX_BSSID_PER_CHANNEL 16
+
+#define NR_TX_QUEUE 3
+
+/* For the extended Scan */
+#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \
+ MRVDRV_MAX_CHANNEL_SIZE + 1
+
+#define MAX_REGION_CHANNEL_NUM 2
+
+/** Chan-freq-TxPower mapping table*/
+struct chan_freq_power {
+ /** channel Number */
+ u16 channel;
+ /** frequency of this channel */
+ u32 freq;
+ /** Max allowed Tx power level */
+ u16 maxtxpower;
+ /** TRUE:channel unsupported; FLASE:supported*/
+ u8 unsupported;
+};
+
+/** region-band mapping table*/
+struct region_channel {
+ /** TRUE if this entry is valid */
+ u8 valid;
+ /** region code for US, Japan ... */
+ u8 region;
+ /** band B/G/A, used for BAND_CONFIG cmd */
+ u8 band;
+ /** Actual No. of elements in the array below */
+ u8 nrcfp;
+ /** chan-freq-txpower mapping table*/
+ struct chan_freq_power *CFP;
+};
+
+struct wlan_802_11_security {
+ u8 WPAenabled;
+ u8 WPA2enabled;
+ enum WLAN_802_11_WEP_STATUS WEPstatus;
+ enum WLAN_802_11_AUTHENTICATION_MODE authmode;
+ enum WLAN_802_1X_AUTH_ALG auth1xalg;
+ enum WLAN_802_11_ENCRYPTION_MODE Encryptionmode;
+};
+
+/** Current Basic Service Set State Structure */
+struct current_bss_params {
+ struct bss_descriptor bssdescriptor;
+ /** bssid */
+ u8 bssid[ETH_ALEN];
+ /** ssid */
+ struct WLAN_802_11_SSID ssid;
+
+ /** band */
+ u8 band;
+ /** channel */
+ u8 channel;
+ /** number of rates supported */
+ int numofrates;
+ /** supported rates*/
+ u8 datarates[WLAN_SUPPORTED_RATES];
+};
+
+/** sleep_params */
+struct sleep_params {
+ u16 sp_error;
+ u16 sp_offset;
+ u16 sp_stabletime;
+ u8 sp_calcontrol;
+ u8 sp_extsleepclk;
+ u16 sp_reserved;
+};
+
+/** Data structure for the Marvell WLAN device */
+typedef struct _wlan_dev {
+ /** device name */
+ char name[DEV_NAME_LEN];
+ /** card pointer */
+ void *card;
+ /** IO port */
+ u32 ioport;
+ /** Upload received */
+ u32 upld_rcv;
+ /** Upload type */
+ u32 upld_typ;
+ /** Upload length */
+ u32 upld_len;
+ /** netdev pointer */
+ struct net_device *netdev;
+ /* Upload buffer */
+ u8 upld_buf[WLAN_UPLD_SIZE];
+ /* Download sent:
+ bit0 1/0=data_sent/data_tx_done,
+ bit1 1/0=cmd_sent/cmd_tx_done,
+ all other bits reserved 0 */
+ u8 dnld_sent;
+} wlan_dev_t, *pwlan_dev_t;
+
+/* Mesh statistics */
+struct wlan_mesh_stats {
+ u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
+ u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
+ u32 fwd_drop_ttl; /* Fwd: TTL zero */
+ u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
+ u32 fwd_drop_noroute; /* Fwd: No route to Destination */
+ u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
+ u32 drop_blind; /* Rx: Dropped by blinding table */
+};
+
+/** Private structure for the MV device */
+struct _wlan_private {
+ int open;
+ int mesh_open;
+ int infra_open;
+
+ wlan_adapter *adapter;
+ wlan_dev_t wlan_dev;
+
+ struct net_device_stats stats;
+ struct net_device *mesh_dev ; /* Virtual device */
+
+ struct iw_statistics wstats;
+ struct wlan_mesh_stats mstats;
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_debug;
+ struct dentry *debugfs_files[6];
+
+ struct dentry *events_dir;
+ struct dentry *debugfs_events_files[6];
+
+ struct dentry *regs_dir;
+ struct dentry *debugfs_regs_files[6];
+
+ u32 mac_offset;
+ u32 bbp_offset;
+ u32 rf_offset;
+
+ const struct firmware *firmware;
+ struct device *hotplug_device;
+
+ /** thread to service interrupts */
+ struct wlan_thread mainthread;
+
+ struct delayed_work assoc_work;
+ struct workqueue_struct *assoc_thread;
+};
+
+/** Association request
+ *
+ * Encapsulates all the options that describe a specific assocation request
+ * or configuration of the wireless card's radio, mode, and security settings.
+ */
+struct assoc_request {
+#define ASSOC_FLAG_SSID 1
+#define ASSOC_FLAG_CHANNEL 2
+#define ASSOC_FLAG_MODE 3
+#define ASSOC_FLAG_BSSID 4
+#define ASSOC_FLAG_WEP_KEYS 5
+#define ASSOC_FLAG_WEP_TX_KEYIDX 6
+#define ASSOC_FLAG_WPA_MCAST_KEY 7
+#define ASSOC_FLAG_WPA_UCAST_KEY 8
+#define ASSOC_FLAG_SECINFO 9
+#define ASSOC_FLAG_WPA_IE 10
+ unsigned long flags;
+
+ struct WLAN_802_11_SSID ssid;
+ u8 channel;
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode;
+ u8 bssid[ETH_ALEN];
+
+ /** WEP keys */
+ struct WLAN_802_11_KEY wep_keys[4];
+ u16 wep_tx_keyidx;
+
+ /** WPA keys */
+ struct WLAN_802_11_KEY wpa_mcast_key;
+ struct WLAN_802_11_KEY wpa_unicast_key;
+
+ struct wlan_802_11_security secinfo;
+
+ /** WPA Information Elements*/
+#define MAX_WPA_IE_LEN 64
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ u8 wpa_ie_len;
+};
+
+/** Wlan adapter data structure*/
+struct _wlan_adapter {
+ /** STATUS variables */
+ u32 fwreleasenumber;
+ u32 fwcapinfo;
+ /* protected with big lock */
+
+ struct mutex lock;
+
+ u8 tmptxbuf[WLAN_UPLD_SIZE];
+ /* protected by hard_start_xmit serialization */
+
+ /** command-related variables */
+ u16 seqnum;
+ /* protected by big lock */
+
+ struct cmd_ctrl_node *cmd_array;
+ /** Current command */
+ struct cmd_ctrl_node *cur_cmd;
+ int cur_cmd_retcode;
+ /** command Queues */
+ /** Free command buffers */
+ struct list_head cmdfreeq;
+ /** Pending command buffers */
+ struct list_head cmdpendingq;
+
+ wait_queue_head_t cmd_pending;
+ u8 nr_cmd_pending;
+ /* command related variables protected by adapter->driver_lock */
+
+ /** Async and Sync Event variables */
+ u32 intcounter;
+ u32 eventcause;
+ u8 nodename[16]; /* nickname */
+
+ /** spin locks */
+ spinlock_t driver_lock;
+
+ /** Timers */
+ struct timer_list command_timer;
+
+ /* TX queue used in PS mode */
+ spinlock_t txqueue_lock;
+ struct sk_buff *tx_queue_ps[NR_TX_QUEUE];
+ unsigned int tx_queue_idx;
+
+ u8 hisregcpy;
+
+ /** current ssid/bssid related parameters*/
+ struct current_bss_params curbssparams;
+
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
+
+ struct bss_descriptor *pattemptedbssdesc;
+
+ struct WLAN_802_11_SSID previousssid;
+ u8 previousbssid[ETH_ALEN];
+
+ struct bss_descriptor *scantable;
+ u32 numinscantable;
+
+ u8 scantype;
+ u32 scanmode;
+
+ u16 beaconperiod;
+ u8 adhoccreate;
+
+ /** capability Info used in Association, start, join */
+ struct ieeetypes_capinfo capinfo;
+
+ /** MAC address information */
+ u8 current_addr[ETH_ALEN];
+ u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+ u32 nr_of_multicastmacaddr;
+
+ /** 802.11 statistics */
+// struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
+
+ u16 enablehwauto;
+ u16 ratebitmap;
+ /** control G rates */
+ u8 adhoc_grate_enabled;
+
+ u32 txantenna;
+ u32 rxantenna;
+
+ u8 adhocchannel;
+ u32 fragthsd;
+ u32 rtsthsd;
+
+ u32 datarate;
+ u8 is_datarate_auto;
+
+ u16 listeninterval;
+ u16 prescan;
+ u8 txretrycount;
+
+ /** Tx-related variables (for single packet tx) */
+ struct sk_buff *currenttxskb;
+ u16 TxLockFlag;
+
+ /** NIC Operation characteristics */
+ u16 currentpacketfilter;
+ u32 connect_status;
+ u16 regioncode;
+ u16 regiontableindex;
+ u16 txpowerlevel;
+
+ /** POWER MANAGEMENT AND PnP SUPPORT */
+ u8 surpriseremoved;
+ u16 atimwindow;
+
+ u16 psmode; /* Wlan802_11PowermodeCAM=disable
+ Wlan802_11PowermodeMAX_PSP=enable */
+ u16 multipledtim;
+ u32 psstate;
+ u8 needtowakeup;
+
+ struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep;
+ u16 locallisteninterval;
+ u16 nullpktinterval;
+
+ struct assoc_request * assoc_req;
+
+ /** Encryption parameter */
+ struct wlan_802_11_security secinfo;
+
+ /** WEP keys */
+ struct WLAN_802_11_KEY wep_keys[4];
+ u16 wep_tx_keyidx;
+
+ /** WPA keys */
+ struct WLAN_802_11_KEY wpa_mcast_key;
+ struct WLAN_802_11_KEY wpa_unicast_key;
+
+ /** WPA Information Elements*/
+#define MAX_WPA_IE_LEN 64
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ u8 wpa_ie_len;
+
+ u16 rxantennamode;
+ u16 txantennamode;
+
+ /** Requested Signal Strength*/
+ u16 bcn_avg_factor;
+ u16 data_avg_factor;
+ u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
+ u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
+ u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
+ u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
+ u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
+ u16 nextSNRNF;
+ u16 numSNRNF;
+ u16 rxpd_rate;
+
+ u8 radioon;
+ u32 preamble;
+
+ /** Multi bands Parameter*/
+ u8 libertas_supported_rates[G_SUPPORTED_RATES];
+
+ /** Blue Tooth Co-existence Arbitration */
+
+ /** sleep_params */
+ struct sleep_params sp;
+
+ /** RF calibration data */
+
+#define MAX_REGION_CHANNEL_NUM 2
+ /** region channel data */
+ struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
+
+ struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
+
+ /** 11D and Domain Regulatory Data */
+ struct wlan_802_11d_domain_reg domainreg;
+ struct parsed_region_chan_11d parsed_region_chan;
+
+ /** FSM variable for 11d support */
+ u32 enable11d;
+
+ /** MISCELLANEOUS */
+ u8 *prdeeprom;
+ struct wlan_offset_value offsetvalue;
+
+ struct cmd_ds_802_11_get_log logmsg;
+ u16 scanprobes;
+
+ u32 pkttxctrl;
+
+ u16 txrate;
+ u32 linkmode;
+ u32 radiomode;
+ u32 debugmode;
+ u8 fw_ready;
+};
+
+#endif /* _WLAN_DEV_H_ */
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
new file mode 100644
index 000000000000..0064de542963
--- /dev/null
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -0,0 +1,184 @@
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+static const char * mesh_stat_strings[]= {
+ "drop_duplicate_bcast",
+ "drop_ttl_zero",
+ "drop_no_fwd_route",
+ "drop_no_buffers",
+ "fwded_unicast_cnt",
+ "fwded_bcast_cnt",
+ "drop_blind_table"
+};
+
+static void libertas_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ wlan_private *priv = (wlan_private *) dev->priv;
+ char fwver[32];
+
+ libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1);
+
+ strcpy(info->driver, "libertas");
+ strcpy(info->version, libertas_driver_version);
+ strcpy(info->fw_version, fwver);
+}
+
+/* All 8388 parts have 16KiB EEPROM size at the time of writing.
+ * In case that changes this needs fixing.
+ */
+#define LIBERTAS_EEPROM_LEN 16384
+
+static int libertas_ethtool_get_eeprom_len(struct net_device *dev)
+{
+ return LIBERTAS_EEPROM_LEN;
+}
+
+static int libertas_ethtool_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 * bytes)
+{
+ wlan_private *priv = (wlan_private *) dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_ioctl_regrdwr regctrl;
+ char *ptr;
+ int ret;
+
+ regctrl.action = 0;
+ regctrl.offset = eeprom->offset;
+ regctrl.NOB = eeprom->len;
+
+ if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN)
+ return -EINVAL;
+
+// mutex_lock(&priv->mutex);
+
+ adapter->prdeeprom =
+ (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
+ if (!adapter->prdeeprom)
+ return -ENOMEM;
+ memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
+
+ /* +14 is for action, offset, and NOB in
+ * response */
+ lbs_pr_debug(1, "action:%d offset: %x NOB: %02x\n",
+ regctrl.action, regctrl.offset, regctrl.NOB);
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_eeprom_access,
+ regctrl.action,
+ cmd_option_waitforrsp, 0,
+ &regctrl);
+
+ if (ret) {
+ if (adapter->prdeeprom)
+ kfree(adapter->prdeeprom);
+ LEAVE();
+ return ret;
+ }
+
+ mdelay(10);
+
+ ptr = (char *)adapter->prdeeprom;
+
+ /* skip the command header, but include the "value" u32 variable */
+ ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4;
+
+ /*
+ * Return the result back to the user
+ */
+ memcpy(bytes, ptr, eeprom->len);
+
+ if (adapter->prdeeprom)
+ kfree(adapter->prdeeprom);
+// mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void libertas_ethtool_get_stats(struct net_device * dev,
+ struct ethtool_stats * stats, u64 * data)
+{
+ wlan_private *priv = dev->priv;
+
+ ENTER();
+
+ stats->cmd = ETHTOOL_GSTATS;
+ BUG_ON(stats->n_stats != MESH_STATS_NUM);
+
+ data[0] = priv->mstats.fwd_drop_rbt;
+ data[1] = priv->mstats.fwd_drop_ttl;
+ data[2] = priv->mstats.fwd_drop_noroute;
+ data[3] = priv->mstats.fwd_drop_nobuf;
+ data[4] = priv->mstats.fwd_unicast_cnt;
+ data[5] = priv->mstats.fwd_bcast_cnt;
+ data[6] = priv->mstats.drop_blind;
+
+ LEAVE();
+}
+
+static int libertas_ethtool_get_stats_count(struct net_device * dev)
+{
+ int ret;
+ wlan_private *priv = dev->priv;
+ struct cmd_ds_mesh_access mesh_access;
+
+ ENTER();
+ /* Get Mesh Statistics */
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_mesh_access, cmd_act_mesh_get_stats,
+ cmd_option_waitforrsp, 0, &mesh_access);
+
+ if (ret) {
+ LEAVE();
+ return 0;
+ }
+
+ priv->mstats.fwd_drop_rbt = mesh_access.data[0];
+ priv->mstats.fwd_drop_ttl = mesh_access.data[1];
+ priv->mstats.fwd_drop_noroute = mesh_access.data[2];
+ priv->mstats.fwd_drop_nobuf = mesh_access.data[3];
+ priv->mstats.fwd_unicast_cnt = mesh_access.data[4];
+ priv->mstats.fwd_bcast_cnt = mesh_access.data[5];
+ priv->mstats.drop_blind = mesh_access.data[6];
+
+ LEAVE();
+ return MESH_STATS_NUM;
+}
+
+static void libertas_ethtool_get_strings (struct net_device * dev,
+ u32 stringset,
+ u8 * s)
+{
+ int i;
+
+ ENTER();
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i=0; i < MESH_STATS_NUM; i++) {
+ memcpy(s + i * ETH_GSTRING_LEN,
+ mesh_stat_strings[i],
+ ETH_GSTRING_LEN);
+ }
+ break;
+ }
+ LEAVE();
+}
+
+struct ethtool_ops libertas_ethtool_ops = {
+ .get_drvinfo = libertas_ethtool_get_drvinfo,
+ .get_eeprom = libertas_ethtool_get_eeprom,
+ .get_eeprom_len = libertas_ethtool_get_eeprom_len,
+ .get_stats_count = libertas_ethtool_get_stats_count,
+ .get_ethtool_stats = libertas_ethtool_get_stats,
+ .get_strings = libertas_ethtool_get_strings,
+};
+
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c
new file mode 100644
index 000000000000..b194a4570791
--- /dev/null
+++ b/drivers/net/wireless/libertas/fw.c
@@ -0,0 +1,361 @@
+/**
+ * This file contains the initialization for FW and HW
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/version.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "defs.h"
+#include "decl.h"
+#include "dev.h"
+#include "fw.h"
+#include "wext.h"
+#include "if_usb.h"
+
+char *libertas_fw_name = NULL;
+module_param_named(fw_name, libertas_fw_name, charp, 0644);
+
+unsigned int libertas_debug = 0;
+module_param(libertas_debug, int, 0);
+
+/**
+ * @brief This function checks the validity of Boot2/FW image.
+ *
+ * @param data pointer to image
+ * len image length
+ * @return 0 or -1
+ */
+static int check_fwfile_format(u8 *data, u32 totlen)
+{
+ u8 bincmd, exit;
+ u32 blksize, offset, len;
+ int ret;
+
+ ret = 1;
+ exit = len = 0;
+
+ do {
+ bincmd = *data;
+ blksize = *(u32*)(data + offsetof(struct fwheader, datalength));
+ switch (bincmd) {
+ case FW_HAS_DATA_TO_RECV:
+ offset = sizeof(struct fwheader) + blksize;
+ data += offset;
+ len += offset;
+ if (len >= totlen)
+ exit = 1;
+ break;
+ case FW_HAS_LAST_BLOCK:
+ exit = 1;
+ ret = 0;
+ break;
+ default:
+ exit = 1;
+ break;
+ }
+ } while (!exit);
+
+ if (ret)
+ lbs_pr_err("bin file format check FAIL...\n");
+ else
+ lbs_pr_debug(1, "bin file format check PASS...\n");
+
+ return ret;
+}
+
+/**
+ * @brief This function downloads firmware image, gets
+ * HW spec from firmware and set basic parameters to
+ * firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+static int wlan_setup_station_hw(wlan_private * priv)
+{
+ int ret = -1;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if ((ret = request_firmware(&priv->firmware, libertas_fw_name,
+ priv->hotplug_device)) < 0) {
+ lbs_pr_err("request_firmware() failed, error code = %#x\n",
+ ret);
+ lbs_pr_err("%s not found in /lib/firmware\n", libertas_fw_name);
+ goto done;
+ }
+
+ if(check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
+ release_firmware(priv->firmware);
+ goto done;
+ }
+
+ ret = libertas_sbi_prog_firmware(priv);
+
+ release_firmware(priv->firmware);
+
+ if (ret) {
+ lbs_pr_debug(1, "Bootloader in invalid state!\n");
+ ret = -1;
+ goto done;
+ }
+
+ /*
+ * Read MAC address from HW
+ */
+ memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec,
+ 0, cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ libertas_set_mac_packet_filter(priv);
+
+ /* Get the supported Data rates */
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+ cmd_act_get_tx_rate,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ ret = 0;
+done:
+ LEAVE();
+
+ return (ret);
+}
+
+static int wlan_allocate_adapter(wlan_private * priv)
+{
+ u32 ulbufsize;
+ wlan_adapter *adapter = priv->adapter;
+
+ struct bss_descriptor *ptempscantable;
+
+ /* Allocate buffer to store the BSSID list */
+ ulbufsize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST;
+ if (!(ptempscantable = kmalloc(ulbufsize, GFP_KERNEL))) {
+ libertas_free_adapter(priv);
+ return -1;
+ }
+
+ adapter->scantable = ptempscantable;
+ memset(adapter->scantable, 0, ulbufsize);
+
+ /* Allocate the command buffers */
+ libertas_allocate_cmd_buffer(priv);
+
+ memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
+ adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
+ adapter->libertas_ps_confirm_sleep.command =
+ cpu_to_le16(cmd_802_11_ps_mode);
+ adapter->libertas_ps_confirm_sleep.size =
+ cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
+ adapter->libertas_ps_confirm_sleep.result = 0;
+ adapter->libertas_ps_confirm_sleep.action =
+ cpu_to_le16(cmd_subcmd_sleep_confirmed);
+
+ return 0;
+}
+
+static void wlan_init_adapter(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i;
+
+ adapter->scanprobes = 0;
+
+ adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+ adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+ /* ATIM params */
+ adapter->atimwindow = 0;
+
+ adapter->connect_status = libertas_disconnected;
+ memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+ /* scan type */
+ adapter->scantype = cmd_scan_type_active;
+
+ /* scan mode */
+ adapter->scanmode = cmd_bss_type_any;
+
+ /* 802.11 specific */
+ adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
+ i++)
+ memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY));
+ adapter->wep_tx_keyidx = 0;
+ adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ adapter->secinfo.authmode = wlan802_11authmodeopen;
+ adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
+ adapter->secinfo.Encryptionmode = CIPHER_NONE;
+ adapter->inframode = wlan802_11infrastructure;
+
+ adapter->assoc_req = NULL;
+
+ adapter->numinscantable = 0;
+ adapter->pattemptedbssdesc = NULL;
+ mutex_init(&adapter->lock);
+
+ adapter->prescan = 1;
+
+ memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+
+ /* PnP and power profile */
+ adapter->surpriseremoved = 0;
+
+ adapter->currentpacketfilter =
+ cmd_act_mac_rx_on | cmd_act_mac_tx_on;
+
+ adapter->radioon = RADIO_ON;
+ adapter->txantenna = RF_ANTENNA_2;
+ adapter->rxantenna = RF_ANTENNA_AUTO;
+
+ adapter->is_datarate_auto = 1;
+ adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
+
+ // set default value of capinfo.
+#define SHORT_PREAMBLE_ALLOWED 1
+ memset(&adapter->capinfo, 0, sizeof(adapter->capinfo));
+ adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED;
+
+ adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
+
+ adapter->psmode = wlan802_11powermodecam;
+ adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+
+ adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
+
+ adapter->psstate = PS_STATE_FULL_POWER;
+ adapter->needtowakeup = 0;
+ adapter->locallisteninterval = 0; /* default value in firmware will be used */
+
+ adapter->datarate = 0; // Initially indicate the rate as auto
+
+ adapter->adhoc_grate_enabled = 0;
+
+ adapter->intcounter = 0;
+
+ adapter->currenttxskb = NULL;
+ adapter->pkttxctrl = 0;
+
+ memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
+ adapter->tx_queue_idx = 0;
+ spin_lock_init(&adapter->txqueue_lock);
+
+ return;
+}
+
+static void command_timer_fn(unsigned long data);
+
+int libertas_init_fw(wlan_private * priv)
+{
+ int ret = -1;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* Allocate adapter structure */
+ if ((ret = wlan_allocate_adapter(priv)) != 0)
+ goto done;
+
+ /* init adapter structure */
+ wlan_init_adapter(priv);
+
+ /* init timer etc. */
+ setup_timer(&adapter->command_timer, command_timer_fn,
+ (unsigned long)priv);
+
+ /* download fimrware etc. */
+ if ((ret = wlan_setup_station_hw(priv)) != 0) {
+ del_timer_sync(&adapter->command_timer);
+ goto done;
+ }
+
+ /* init 802.11d */
+ libertas_init_11d(priv);
+
+ ret = 0;
+done:
+ LEAVE();
+ return ret;
+}
+
+void libertas_free_adapter(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ if (!adapter) {
+ lbs_pr_debug(1, "Why double free adapter?:)\n");
+ return;
+ }
+
+ lbs_pr_debug(1, "Free command buffer\n");
+ libertas_free_cmd_buffer(priv);
+
+ lbs_pr_debug(1, "Free commandTimer\n");
+ del_timer(&adapter->command_timer);
+
+ lbs_pr_debug(1, "Free scantable\n");
+ if (adapter->scantable) {
+ kfree(adapter->scantable);
+ adapter->scantable = NULL;
+ }
+
+ lbs_pr_debug(1, "Free adapter\n");
+
+ /* Free the adapter object itself */
+ kfree(adapter);
+ priv->adapter = NULL;
+}
+
+/**
+ * This function handles the timeout of command sending.
+ * It will re-send the same command again.
+ */
+static void command_timer_fn(unsigned long data)
+{
+ wlan_private *priv = (wlan_private *)data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *ptempnode;
+ struct cmd_ds_command *cmd;
+ unsigned long flags;
+
+ ptempnode = adapter->cur_cmd;
+ cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
+
+ lbs_pr_info("command_timer_fn fired (%x)\n", cmd->command);
+
+ if (!adapter->fw_ready)
+ return;
+
+ if (ptempnode == NULL) {
+ lbs_pr_debug(1, "PTempnode Empty\n");
+ return;
+ }
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ lbs_pr_debug(1, "Re-sending same command as it timeout...!\n");
+ libertas_queue_cmd(adapter, ptempnode, 0);
+
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ return;
+}
diff --git a/drivers/net/wireless/libertas/fw.h b/drivers/net/wireless/libertas/fw.h
new file mode 100644
index 000000000000..1f9ae267a9e0
--- /dev/null
+++ b/drivers/net/wireless/libertas/fw.h
@@ -0,0 +1,13 @@
+/**
+ * This header file contains FW interface related definitions.
+ */
+#ifndef _WLAN_FW_H_
+#define _WLAN_FW_H_
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+int libertas_init_fw(wlan_private * priv);
+
+#endif /* _WLAN_FW_H_ */
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
new file mode 100644
index 000000000000..c0faaecaf5be
--- /dev/null
+++ b/drivers/net/wireless/libertas/host.h
@@ -0,0 +1,338 @@
+/**
+ * This file contains definitions of WLAN commands.
+ */
+
+#ifndef _HOST_H_
+#define _HOST_H_
+
+/** PUBLIC DEFINITIONS */
+#define DEFAULT_AD_HOC_CHANNEL 6
+#define DEFAULT_AD_HOC_CHANNEL_A 36
+
+/** IEEE 802.11 oids */
+#define OID_802_11_SSID 0x00008002
+#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008
+#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009
+#define OID_802_11_RTS_THRESHOLD 0x0000800A
+#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D
+#define OID_802_11_SUPPORTED_RATES 0x0000800E
+#define OID_802_11_STATISTICS 0x00008012
+#define OID_802_11_TX_RETRYCOUNT 0x0000801D
+#define OID_802_11D_ENABLE 0x00008020
+
+#define cmd_option_waitforrsp 0x0002
+
+/** Host command ID */
+#define cmd_code_dnld 0x0002
+#define cmd_get_hw_spec 0x0003
+#define cmd_eeprom_update 0x0004
+#define cmd_802_11_reset 0x0005
+#define cmd_802_11_scan 0x0006
+#define cmd_802_11_get_log 0x000b
+#define cmd_mac_multicast_adr 0x0010
+#define cmd_802_11_authenticate 0x0011
+#define cmd_802_11_eeprom_access 0x0059
+#define cmd_802_11_associate 0x0050
+#define cmd_802_11_set_wep 0x0013
+#define cmd_802_11_get_stat 0x0014
+#define cmd_802_3_get_stat 0x0015
+#define cmd_802_11_snmp_mib 0x0016
+#define cmd_mac_reg_map 0x0017
+#define cmd_bbp_reg_map 0x0018
+#define cmd_mac_reg_access 0x0019
+#define cmd_bbp_reg_access 0x001a
+#define cmd_rf_reg_access 0x001b
+#define cmd_802_11_radio_control 0x001c
+#define cmd_802_11_rf_channel 0x001d
+#define cmd_802_11_rf_tx_power 0x001e
+#define cmd_802_11_rssi 0x001f
+#define cmd_802_11_rf_antenna 0x0020
+
+#define cmd_802_11_ps_mode 0x0021
+
+#define cmd_802_11_data_rate 0x0022
+#define cmd_rf_reg_map 0x0023
+#define cmd_802_11_deauthenticate 0x0024
+#define cmd_802_11_reassociate 0x0025
+#define cmd_802_11_disassociate 0x0026
+#define cmd_mac_control 0x0028
+#define cmd_802_11_ad_hoc_start 0x002b
+#define cmd_802_11_ad_hoc_join 0x002c
+
+#define cmd_802_11_query_tkip_reply_cntrs 0x002e
+#define cmd_802_11_enable_rsn 0x002f
+#define cmd_802_11_pairwise_tsc 0x0036
+#define cmd_802_11_group_tsc 0x0037
+#define cmd_802_11_key_material 0x005e
+
+#define cmd_802_11_set_afc 0x003c
+#define cmd_802_11_get_afc 0x003d
+
+#define cmd_802_11_ad_hoc_stop 0x0040
+
+#define cmd_802_11_beacon_stop 0x0049
+
+#define cmd_802_11_mac_address 0x004D
+#define cmd_802_11_eeprom_access 0x0059
+
+#define cmd_802_11_band_config 0x0058
+
+#define cmd_802_11d_domain_info 0x005b
+
+#define cmd_802_11_sleep_params 0x0066
+
+#define cmd_802_11_inactivity_timeout 0x0067
+
+#define cmd_802_11_tpc_cfg 0x0072
+#define cmd_802_11_pwr_cfg 0x0073
+
+#define cmd_802_11_led_gpio_ctrl 0x004e
+
+#define cmd_802_11_subscribe_event 0x0075
+
+#define cmd_802_11_rate_adapt_rateset 0x0076
+
+#define cmd_802_11_tx_rate_query 0x007f
+
+#define cmd_get_tsf 0x0080
+
+#define cmd_bt_access 0x0087
+#define cmd_ret_bt_access 0x8087
+
+#define cmd_fwt_access 0x0088
+#define cmd_ret_fwt_access 0x8088
+
+#define cmd_mesh_access 0x0090
+#define cmd_ret_mesh_access 0x8090
+
+/* For the IEEE Power Save */
+#define cmd_subcmd_enter_ps 0x0030
+#define cmd_subcmd_exit_ps 0x0031
+#define cmd_subcmd_sleep_confirmed 0x0034
+#define cmd_subcmd_full_powerdown 0x0035
+#define cmd_subcmd_full_powerup 0x0036
+
+/* command RET code, MSB is set to 1 */
+#define cmd_ret_hw_spec_info 0x8003
+#define cmd_ret_eeprom_update 0x8004
+#define cmd_ret_802_11_reset 0x8005
+#define cmd_ret_802_11_scan 0x8006
+#define cmd_ret_802_11_get_log 0x800b
+#define cmd_ret_mac_control 0x8028
+#define cmd_ret_mac_multicast_adr 0x8010
+#define cmd_ret_802_11_authenticate 0x8011
+#define cmd_ret_802_11_deauthenticate 0x8024
+#define cmd_ret_802_11_associate 0x8012
+#define cmd_ret_802_11_reassociate 0x8025
+#define cmd_ret_802_11_disassociate 0x8026
+#define cmd_ret_802_11_set_wep 0x8013
+#define cmd_ret_802_11_stat 0x8014
+#define cmd_ret_802_3_stat 0x8015
+#define cmd_ret_802_11_snmp_mib 0x8016
+#define cmd_ret_mac_reg_map 0x8017
+#define cmd_ret_bbp_reg_map 0x8018
+#define cmd_ret_rf_reg_map 0x8023
+#define cmd_ret_mac_reg_access 0x8019
+#define cmd_ret_bbp_reg_access 0x801a
+#define cmd_ret_rf_reg_access 0x801b
+#define cmd_ret_802_11_radio_control 0x801c
+#define cmd_ret_802_11_rf_channel 0x801d
+#define cmd_ret_802_11_rssi 0x801f
+#define cmd_ret_802_11_rf_tx_power 0x801e
+#define cmd_ret_802_11_rf_antenna 0x8020
+#define cmd_ret_802_11_ps_mode 0x8021
+#define cmd_ret_802_11_data_rate 0x8022
+
+#define cmd_ret_802_11_ad_hoc_start 0x802B
+#define cmd_ret_802_11_ad_hoc_join 0x802C
+
+#define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e
+#define cmd_ret_802_11_enable_rsn 0x802f
+#define cmd_ret_802_11_pairwise_tsc 0x8036
+#define cmd_ret_802_11_group_tsc 0x8037
+#define cmd_ret_802_11_key_material 0x805e
+
+#define cmd_enable_rsn 0x0001
+#define cmd_disable_rsn 0x0000
+
+#define cmd_act_set 0x0001
+#define cmd_act_get 0x0000
+
+#define cmd_act_get_AES (cmd_act_get + 2)
+#define cmd_act_set_AES (cmd_act_set + 2)
+#define cmd_act_remove_aes (cmd_act_set + 3)
+
+#define cmd_ret_802_11_set_afc 0x803c
+#define cmd_ret_802_11_get_afc 0x803d
+
+#define cmd_ret_802_11_ad_hoc_stop 0x8040
+
+#define cmd_ret_802_11_beacon_stop 0x8049
+
+#define cmd_ret_802_11_mac_address 0x804D
+#define cmd_ret_802_11_eeprom_access 0x8059
+
+#define cmd_ret_802_11_band_config 0x8058
+
+#define cmd_ret_802_11_sleep_params 0x8066
+
+#define cmd_ret_802_11_inactivity_timeout 0x8067
+
+#define cmd_ret_802_11d_domain_info (0x8000 | \
+ cmd_802_11d_domain_info)
+
+#define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000)
+#define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000)
+
+#define cmd_ret_802_11_led_gpio_ctrl 0x804e
+
+#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000)
+
+#define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000)
+
+#define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000)
+
+#define cmd_ret_get_tsf 0x8080
+
+/* Define action or option for cmd_802_11_set_wep */
+#define cmd_act_add 0x0002
+#define cmd_act_remove 0x0004
+#define cmd_act_use_default 0x0008
+
+#define cmd_type_wep_40_bit 0x0001
+#define cmd_type_wep_104_bit 0x0002
+
+#define cmd_NUM_OF_WEP_KEYS 4
+
+#define cmd_WEP_KEY_INDEX_MASK 0x3fff
+
+/* Define action or option for cmd_802_11_reset */
+#define cmd_act_halt 0x0003
+
+/* Define action or option for cmd_802_11_scan */
+#define cmd_bss_type_bss 0x0001
+#define cmd_bss_type_ibss 0x0002
+#define cmd_bss_type_any 0x0003
+
+/* Define action or option for cmd_802_11_scan */
+#define cmd_scan_type_active 0x0000
+#define cmd_scan_type_passive 0x0001
+
+#define cmd_scan_radio_type_bg 0
+
+#define cmd_scan_probe_delay_time 0
+
+/* Define action or option for cmd_mac_control */
+#define cmd_act_mac_rx_on 0x0001
+#define cmd_act_mac_tx_on 0x0002
+#define cmd_act_mac_loopback_on 0x0004
+#define cmd_act_mac_wep_enable 0x0008
+#define cmd_act_mac_int_enable 0x0010
+#define cmd_act_mac_multicast_enable 0x0020
+#define cmd_act_mac_broadcast_enable 0x0040
+#define cmd_act_mac_promiscuous_enable 0x0080
+#define cmd_act_mac_all_multicast_enable 0x0100
+#define cmd_act_mac_strict_protection_enable 0x0400
+
+/* Define action or option for cmd_802_11_radio_control */
+#define cmd_type_auto_preamble 0x0001
+#define cmd_type_short_preamble 0x0002
+#define cmd_type_long_preamble 0x0003
+
+#define TURN_ON_RF 0x01
+#define RADIO_ON 0x01
+#define RADIO_OFF 0x00
+
+#define SET_AUTO_PREAMBLE 0x05
+#define SET_SHORT_PREAMBLE 0x03
+#define SET_LONG_PREAMBLE 0x01
+
+/* Define action or option for CMD_802_11_RF_CHANNEL */
+#define cmd_opt_802_11_rf_channel_get 0x00
+#define cmd_opt_802_11_rf_channel_set 0x01
+
+/* Define action or option for cmd_802_11_rf_tx_power */
+#define cmd_act_tx_power_opt_get 0x0000
+#define cmd_act_tx_power_opt_set_high 0x8007
+#define cmd_act_tx_power_opt_set_mid 0x8004
+#define cmd_act_tx_power_opt_set_low 0x8000
+
+#define cmd_act_tx_power_index_high 0x0007
+#define cmd_act_tx_power_index_mid 0x0004
+#define cmd_act_tx_power_index_low 0x0000
+
+/* Define action or option for cmd_802_11_data_rate */
+#define cmd_act_set_tx_auto 0x0000
+#define cmd_act_set_tx_fix_rate 0x0001
+#define cmd_act_get_tx_rate 0x0002
+
+#define cmd_act_set_rx 0x0001
+#define cmd_act_set_tx 0x0002
+#define cmd_act_set_both 0x0003
+#define cmd_act_get_rx 0x0004
+#define cmd_act_get_tx 0x0008
+#define cmd_act_get_both 0x000c
+
+/* Define action or option for cmd_802_11_ps_mode */
+#define cmd_type_cam 0x0000
+#define cmd_type_max_psp 0x0001
+#define cmd_type_fast_psp 0x0002
+
+/* Define action or option for cmd_bt_access */
+enum cmd_bt_access_opts {
+ /* The bt commands start at 5 instead of 1 because the old dft commands
+ * are mapped to 1-4. These old commands are no longer maintained and
+ * should not be called.
+ */
+ cmd_act_bt_access_add = 5,
+ cmd_act_bt_access_del,
+ cmd_act_bt_access_list,
+ cmd_act_bt_access_reset
+};
+
+/* Define action or option for cmd_fwt_access */
+enum cmd_fwt_access_opts {
+ cmd_act_fwt_access_add = 1,
+ cmd_act_fwt_access_del,
+ cmd_act_fwt_access_lookup,
+ cmd_act_fwt_access_list,
+ cmd_act_fwt_access_list_route,
+ cmd_act_fwt_access_list_neighbor,
+ cmd_act_fwt_access_reset,
+ cmd_act_fwt_access_cleanup,
+ cmd_act_fwt_access_time,
+};
+
+/* Define action or option for cmd_mesh_access */
+enum cmd_mesh_access_opts {
+ cmd_act_mesh_get_ttl = 1,
+ cmd_act_mesh_set_ttl,
+ cmd_act_mesh_get_stats,
+ cmd_act_mesh_get_mpp,
+ cmd_act_mesh_set_mpp,
+};
+
+/** Card Event definition */
+#define MACREG_INT_CODE_TX_PPA_FREE 0x00000000
+#define MACREG_INT_CODE_TX_DMA_DONE 0x00000001
+#define MACREG_INT_CODE_LINK_LOSE_W_SCAN 0x00000002
+#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN 0x00000003
+#define MACREG_INT_CODE_LINK_SENSED 0x00000004
+#define MACREG_INT_CODE_CMD_FINISHED 0x00000005
+#define MACREG_INT_CODE_MIB_CHANGED 0x00000006
+#define MACREG_INT_CODE_INIT_DONE 0x00000007
+#define MACREG_INT_CODE_DEAUTHENTICATED 0x00000008
+#define MACREG_INT_CODE_DISASSOCIATED 0x00000009
+#define MACREG_INT_CODE_PS_AWAKE 0x0000000a
+#define MACREG_INT_CODE_PS_SLEEP 0x0000000b
+#define MACREG_INT_CODE_MIC_ERR_MULTICAST 0x0000000d
+#define MACREG_INT_CODE_MIC_ERR_UNICAST 0x0000000e
+#define MACREG_INT_CODE_WM_AWAKE 0x0000000f
+#define MACREG_INT_CODE_ADHOC_BCN_LOST 0x00000011
+#define MACREG_INT_CODE_RSSI_LOW 0x00000019
+#define MACREG_INT_CODE_SNR_LOW 0x0000001a
+#define MACREG_INT_CODE_MAX_FAIL 0x0000001b
+#define MACREG_INT_CODE_RSSI_HIGH 0x0000001c
+#define MACREG_INT_CODE_SNR_HIGH 0x0000001d
+
+#endif /* _HOST_H_ */
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
new file mode 100644
index 000000000000..f239e5d2435b
--- /dev/null
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -0,0 +1,693 @@
+/*
+ * This file contains the function prototypes, data structure
+ * and defines for all the host/station commands
+ */
+#ifndef __HOSTCMD__H
+#define __HOSTCMD__H
+
+#include <linux/wireless.h>
+#include "11d.h"
+#include "types.h"
+
+/* 802.11-related definitions */
+
+/* TxPD descriptor */
+struct txpd {
+ /* Current Tx packet status */
+ u32 tx_status;
+ /* Tx control */
+ u32 tx_control;
+ u32 tx_packet_location;
+ /* Tx packet length */
+ u16 tx_packet_length;
+ /* First 2 byte of destination MAC address */
+ u8 tx_dest_addr_high[2];
+ /* Last 4 byte of destination MAC address */
+ u8 tx_dest_addr_low[4];
+ /* Pkt Priority */
+ u8 priority;
+ /* Pkt Trasnit Power control */
+ u8 powermgmt;
+ /* Amount of time the packet has been queued in the driver (units = 2ms) */
+ u8 pktdelay_2ms;
+ /* reserved */
+ u8 reserved1;
+};
+
+/* RxPD Descriptor */
+struct rxpd {
+ /* Current Rx packet status */
+ u16 status;
+
+ /* SNR */
+ u8 snr;
+
+ /* Tx control */
+ u8 rx_control;
+
+ /* Pkt length */
+ u16 pkt_len;
+
+ /* Noise Floor */
+ u8 nf;
+
+ /* Rx Packet Rate */
+ u8 rx_rate;
+
+ /* Pkt addr */
+ u32 pkt_ptr;
+
+ /* Next Rx RxPD addr */
+ u32 next_rxpd_ptr;
+
+ /* Pkt Priority */
+ u8 priority;
+ u8 reserved[3];
+};
+
+struct cmd_ctrl_node {
+ /* CMD link list */
+ struct list_head list;
+ u32 status;
+ /* CMD ID */
+ u32 cmd_oid;
+ /*CMD wait option: wait for finish or no wait */
+ u16 wait_option;
+ /* command parameter */
+ void *pdata_buf;
+ /*command data */
+ u8 *bufvirtualaddr;
+ u16 cmdflags;
+ /* wait queue */
+ u16 cmdwaitqwoken;
+ wait_queue_head_t cmdwait_q;
+};
+
+/* WLAN_802_11_KEY
+ *
+ * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES)
+ * is determined from the keylength field.
+ */
+struct WLAN_802_11_KEY {
+ u32 len;
+ u32 flags; /* KEY_INFO_* from wlan_defs.h */
+ u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH];
+ u16 type; /* KEY_TYPE_* from wlan_defs.h */
+};
+
+struct IE_WPA {
+ u8 elementid;
+ u8 len;
+ u8 oui[4];
+ u16 version;
+};
+
+struct WLAN_802_11_SSID {
+ /* SSID length */
+ u32 ssidlength;
+
+ /* SSID information field */
+ u8 ssid[IW_ESSID_MAX_SIZE];
+};
+
+struct WPA_SUPPLICANT {
+ u8 wpa_ie[256];
+ u8 wpa_ie_len;
+};
+
+/* wlan_offset_value */
+struct wlan_offset_value {
+ u32 offset;
+ u32 value;
+};
+
+struct WLAN_802_11_FIXED_IEs {
+ u8 timestamp[8];
+ u16 beaconinterval;
+ u16 capabilities;
+};
+
+struct WLAN_802_11_VARIABLE_IEs {
+ u8 elementid;
+ u8 length;
+ u8 data[1];
+};
+
+/* Define general data structure */
+/* cmd_DS_GEN */
+struct cmd_ds_gen {
+ u16 command;
+ u16 size;
+ u16 seqnum;
+ u16 result;
+};
+
+#define S_DS_GEN sizeof(struct cmd_ds_gen)
+/*
+ * Define data structure for cmd_get_hw_spec
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+struct cmd_ds_get_hw_spec {
+ /* HW Interface version number */
+ u16 hwifversion;
+ /* HW version number */
+ u16 version;
+ /* Max number of TxPD FW can handle */
+ u16 nr_txpd;
+ /* Max no of Multicast address */
+ u16 nr_mcast_adr;
+ /* MAC address */
+ u8 permanentaddr[6];
+
+ /* region Code */
+ u16 regioncode;
+
+ /* Number of antenna used */
+ u16 nr_antenna;
+
+ /* FW release number, example 0x1234=1.2.3.4 */
+ u32 fwreleasenumber;
+
+ /* Base Address of TxPD queue */
+ u32 wcb_base;
+ /* Read Pointer of RxPd queue */
+ u32 rxpd_rdptr;
+
+ /* Write Pointer of RxPd queue */
+ u32 rxpd_wrptr;
+
+ /*FW/HW capability */
+ u32 fwcapinfo;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_reset {
+ u16 action;
+};
+
+struct cmd_ds_802_11_subscribe_event {
+ u16 action;
+ u16 events;
+};
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for cmd_802_11_scan
+ */
+struct cmd_ds_802_11_scan {
+ u8 bsstype;
+ u8 BSSID[ETH_ALEN];
+ u8 tlvbuffer[1];
+#if 0
+ mrvlietypes_ssidparamset_t ssidParamSet;
+ mrvlietypes_chanlistparamset_t ChanListParamSet;
+ mrvlietypes_ratesparamset_t OpRateSet;
+#endif
+};
+
+struct cmd_ds_802_11_scan_rsp {
+ u16 bssdescriptsize;
+ u8 nr_sets;
+ u8 bssdesc_and_tlvbuffer[1];
+};
+
+struct cmd_ds_802_11_get_log {
+ u32 mcasttxframe;
+ u32 failed;
+ u32 retry;
+ u32 multiretry;
+ u32 framedup;
+ u32 rtssuccess;
+ u32 rtsfailure;
+ u32 ackfailure;
+ u32 rxfrag;
+ u32 mcastrxframe;
+ u32 fcserror;
+ u32 txframe;
+ u32 wepundecryptable;
+};
+
+struct cmd_ds_mac_control {
+ u16 action;
+ u16 reserved;
+};
+
+struct cmd_ds_mac_multicast_adr {
+ u16 action;
+ u16 nr_of_adrs;
+ u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+};
+
+struct cmd_ds_802_11_authenticate {
+ u8 macaddr[ETH_ALEN];
+ u8 authtype;
+ u8 reserved[10];
+};
+
+struct cmd_ds_802_11_deauthenticate {
+ u8 macaddr[6];
+ u16 reasoncode;
+};
+
+struct cmd_ds_802_11_associate {
+ u8 peerstaaddr[6];
+ struct ieeetypes_capinfo capinfo;
+ u16 listeninterval;
+ u16 bcnperiod;
+ u8 dtimperiod;
+
+#if 0
+ mrvlietypes_ssidparamset_t ssidParamSet;
+ mrvlietypes_phyparamset_t phyparamset;
+ mrvlietypes_ssparamset_t ssparamset;
+ mrvlietypes_ratesparamset_t ratesParamSet;
+#endif
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_disassociate {
+ u8 destmacaddr[6];
+ u16 reasoncode;
+};
+
+struct cmd_ds_802_11_associate_rsp {
+ struct ieeetypes_assocrsp assocRsp;
+};
+
+struct cmd_ds_802_11_ad_hoc_result {
+ u8 PAD[3];
+ u8 BSSID[ETH_ALEN];
+};
+
+struct cmd_ds_802_11_set_wep {
+ /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
+ u16 action;
+
+ /* key Index selected for Tx */
+ u16 keyindex;
+
+ /* 40, 128bit or TXWEP */
+ u8 keytype[4];
+ u8 keymaterial[4][16];
+};
+
+struct cmd_ds_802_3_get_stat {
+ u32 xmitok;
+ u32 rcvok;
+ u32 xmiterror;
+ u32 rcverror;
+ u32 rcvnobuffer;
+ u32 rcvcrcerror;
+};
+
+struct cmd_ds_802_11_get_stat {
+ u32 txfragmentcnt;
+ u32 mcasttxframecnt;
+ u32 failedcnt;
+ u32 retrycnt;
+ u32 Multipleretrycnt;
+ u32 rtssuccesscnt;
+ u32 rtsfailurecnt;
+ u32 ackfailurecnt;
+ u32 frameduplicatecnt;
+ u32 rxfragmentcnt;
+ u32 mcastrxframecnt;
+ u32 fcserrorcnt;
+ u32 bcasttxframecnt;
+ u32 bcastrxframecnt;
+ u32 txbeacon;
+ u32 rxbeacon;
+ u32 wepundecryptable;
+};
+
+struct cmd_ds_802_11_snmp_mib {
+ u16 querytype;
+ u16 oid;
+ u16 bufsize;
+ u8 value[128];
+};
+
+struct cmd_ds_mac_reg_map {
+ u16 buffersize;
+ u8 regmap[128];
+ u16 reserved;
+};
+
+struct cmd_ds_bbp_reg_map {
+ u16 buffersize;
+ u8 regmap[128];
+ u16 reserved;
+};
+
+struct cmd_ds_rf_reg_map {
+ u16 buffersize;
+ u8 regmap[64];
+ u16 reserved;
+};
+
+struct cmd_ds_mac_reg_access {
+ u16 action;
+ u16 offset;
+ u32 value;
+};
+
+struct cmd_ds_bbp_reg_access {
+ u16 action;
+ u16 offset;
+ u8 value;
+ u8 reserved[3];
+};
+
+struct cmd_ds_rf_reg_access {
+ u16 action;
+ u16 offset;
+ u8 value;
+ u8 reserved[3];
+};
+
+struct cmd_ds_802_11_radio_control {
+ u16 action;
+ u16 control;
+};
+
+struct cmd_ds_802_11_sleep_params {
+ /* ACT_GET/ACT_SET */
+ u16 action;
+
+ /* Sleep clock error in ppm */
+ u16 error;
+
+ /* Wakeup offset in usec */
+ u16 offset;
+
+ /* Clock stabilization time in usec */
+ u16 stabletime;
+
+ /* control periodic calibration */
+ u8 calcontrol;
+
+ /* control the use of external sleep clock */
+ u8 externalsleepclk;
+
+ /* reserved field, should be set to zero */
+ u16 reserved;
+};
+
+struct cmd_ds_802_11_inactivity_timeout {
+ /* ACT_GET/ACT_SET */
+ u16 action;
+
+ /* Inactivity timeout in msec */
+ u16 timeout;
+};
+
+struct cmd_ds_802_11_rf_channel {
+ u16 action;
+ u16 currentchannel;
+ u16 rftype;
+ u16 reserved;
+ u8 channellist[32];
+};
+
+struct cmd_ds_802_11_rssi {
+ /* weighting factor */
+ u16 N;
+
+ u16 reserved_0;
+ u16 reserved_1;
+ u16 reserved_2;
+};
+
+struct cmd_ds_802_11_rssi_rsp {
+ u16 SNR;
+ u16 noisefloor;
+ u16 avgSNR;
+ u16 avgnoisefloor;
+};
+
+struct cmd_ds_802_11_mac_address {
+ u16 action;
+ u8 macadd[ETH_ALEN];
+};
+
+struct cmd_ds_802_11_rf_tx_power {
+ u16 action;
+ u16 currentlevel;
+};
+
+struct cmd_ds_802_11_rf_antenna {
+ u16 action;
+
+ /* Number of antennas or 0xffff(diversity) */
+ u16 antennamode;
+
+};
+
+struct cmd_ds_802_11_ps_mode {
+ u16 action;
+ u16 nullpktinterval;
+ u16 multipledtim;
+ u16 reserved;
+ u16 locallisteninterval;
+};
+
+struct PS_CMD_ConfirmSleep {
+ u16 command;
+ u16 size;
+ u16 seqnum;
+ u16 result;
+
+ u16 action;
+ u16 reserved1;
+ u16 multipledtim;
+ u16 reserved;
+ u16 locallisteninterval;
+};
+
+struct cmd_ds_802_11_data_rate {
+ u16 action;
+ u16 reserverd;
+ u8 datarate[G_SUPPORTED_RATES];
+};
+
+struct cmd_ds_802_11_rate_adapt_rateset {
+ u16 action;
+ u16 enablehwauto;
+ u16 bitmap;
+};
+
+struct cmd_ds_802_11_ad_hoc_start {
+ u8 SSID[IW_ESSID_MAX_SIZE];
+ u8 bsstype;
+ u16 beaconperiod;
+ u8 dtimperiod;
+ union IEEEtypes_ssparamset ssparamset;
+ union ieeetypes_phyparamset phyparamset;
+ u16 probedelay;
+ struct ieeetypes_capinfo cap;
+ u8 datarate[G_SUPPORTED_RATES];
+ u8 tlv_memory_size_pad[100];
+} __attribute__ ((packed));
+
+struct adhoc_bssdesc {
+ u8 BSSID[6];
+ u8 SSID[32];
+ u8 bsstype;
+ u16 beaconperiod;
+ u8 dtimperiod;
+ u8 timestamp[8];
+ u8 localtime[8];
+ union ieeetypes_phyparamset phyparamset;
+ union IEEEtypes_ssparamset ssparamset;
+ struct ieeetypes_capinfo cap;
+ u8 datarates[G_SUPPORTED_RATES];
+
+ /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
+ * Adhoc join command and will cause a binary layout mismatch with
+ * the firmware
+ */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_join {
+ struct adhoc_bssdesc bssdescriptor;
+ u16 failtimeout;
+ u16 probedelay;
+
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_enable_rsn {
+ u16 action;
+ u16 enable;
+};
+
+struct MrvlIEtype_keyParamSet {
+ /* type ID */
+ u16 type;
+
+ /* length of Payload */
+ u16 length;
+
+ /* type of key: WEP=0, TKIP=1, AES=2 */
+ u16 keytypeid;
+
+ /* key control Info specific to a keytypeid */
+ u16 keyinfo;
+
+ /* length of key */
+ u16 keylen;
+
+ /* key material of size keylen */
+ u8 key[32];
+};
+
+struct cmd_ds_802_11_key_material {
+ u16 action;
+ struct MrvlIEtype_keyParamSet keyParamSet[2];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_eeprom_access {
+ u16 action;
+
+ /* multiple 4 */
+ u16 offset;
+ u16 bytecount;
+ u8 value;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_tpc_cfg {
+ u16 action;
+ u8 enable;
+ s8 P0;
+ s8 P1;
+ s8 P2;
+ u8 usesnr;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_led_ctrl {
+ u16 action;
+ u16 numled;
+ u8 data[256];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_pwr_cfg {
+ u16 action;
+ u8 enable;
+ s8 PA_P0;
+ s8 PA_P1;
+ s8 PA_P2;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_afc {
+ u16 afc_auto;
+ union {
+ struct {
+ u16 threshold;
+ u16 period;
+ };
+ struct {
+ s16 timing_offset;
+ s16 carrier_offset;
+ };
+ };
+} __attribute__ ((packed));
+
+struct cmd_tx_rate_query {
+ u16 txrate;
+} __attribute__ ((packed));
+
+struct cmd_ds_get_tsf {
+ __le64 tsfvalue;
+} __attribute__ ((packed));
+
+struct cmd_ds_bt_access {
+ u16 action;
+ u32 id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_fwt_access {
+ u16 action;
+ u32 id;
+ u8 da[ETH_ALEN];
+ u8 dir;
+ u8 ra[ETH_ALEN];
+ u32 ssn;
+ u32 dsn;
+ u32 metric;
+ u8 hopcount;
+ u8 ttl;
+ u32 expiration;
+ u8 sleepmode;
+ u32 snr;
+ u32 references;
+} __attribute__ ((packed));
+
+#define MESH_STATS_NUM 7
+struct cmd_ds_mesh_access {
+ u16 action;
+ u32 data[MESH_STATS_NUM + 1]; /* last position reserved */
+} __attribute__ ((packed));
+
+struct cmd_ds_command {
+ /* command header */
+ u16 command;
+ u16 size;
+ u16 seqnum;
+ u16 result;
+
+ /* command Body */
+ union {
+ struct cmd_ds_get_hw_spec hwspec;
+ struct cmd_ds_802_11_ps_mode psmode;
+ struct cmd_ds_802_11_scan scan;
+ struct cmd_ds_802_11_scan_rsp scanresp;
+ struct cmd_ds_mac_control macctrl;
+ struct cmd_ds_802_11_associate associate;
+ struct cmd_ds_802_11_deauthenticate deauth;
+ struct cmd_ds_802_11_set_wep wep;
+ struct cmd_ds_802_11_ad_hoc_start ads;
+ struct cmd_ds_802_11_reset reset;
+ struct cmd_ds_802_11_ad_hoc_result result;
+ struct cmd_ds_802_11_get_log glog;
+ struct cmd_ds_802_11_authenticate auth;
+ struct cmd_ds_802_11_get_stat gstat;
+ struct cmd_ds_802_3_get_stat gstat_8023;
+ struct cmd_ds_802_11_snmp_mib smib;
+ struct cmd_ds_802_11_rf_tx_power txp;
+ struct cmd_ds_802_11_rf_antenna rant;
+ struct cmd_ds_802_11_data_rate drate;
+ struct cmd_ds_802_11_rate_adapt_rateset rateset;
+ struct cmd_ds_mac_multicast_adr madr;
+ struct cmd_ds_802_11_ad_hoc_join adj;
+ struct cmd_ds_802_11_radio_control radio;
+ struct cmd_ds_802_11_rf_channel rfchannel;
+ struct cmd_ds_802_11_rssi rssi;
+ struct cmd_ds_802_11_rssi_rsp rssirsp;
+ struct cmd_ds_802_11_disassociate dassociate;
+ struct cmd_ds_802_11_mac_address macadd;
+ struct cmd_ds_802_11_enable_rsn enbrsn;
+ struct cmd_ds_802_11_key_material keymaterial;
+ struct cmd_ds_mac_reg_access macreg;
+ struct cmd_ds_bbp_reg_access bbpreg;
+ struct cmd_ds_rf_reg_access rfreg;
+ struct cmd_ds_802_11_eeprom_access rdeeprom;
+
+ struct cmd_ds_802_11d_domain_info domaininfo;
+ struct cmd_ds_802_11d_domain_info domaininforesp;
+
+ struct cmd_ds_802_11_sleep_params sleep_params;
+ struct cmd_ds_802_11_inactivity_timeout inactivity_timeout;
+ struct cmd_ds_802_11_tpc_cfg tpccfg;
+ struct cmd_ds_802_11_pwr_cfg pwrcfg;
+ struct cmd_ds_802_11_afc afc;
+ struct cmd_ds_802_11_led_ctrl ledgpio;
+
+ struct cmd_tx_rate_query txrate;
+ struct cmd_ds_bt_access bt;
+ struct cmd_ds_fwt_access fwt;
+ struct cmd_ds_mesh_access mesh;
+ struct cmd_ds_get_tsf gettsf;
+ struct cmd_ds_802_11_subscribe_event subscribe_event;
+ } params;
+} __attribute__ ((packed));
+
+#endif
diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c
new file mode 100644
index 000000000000..567000c3e87b
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_bootcmd.c
@@ -0,0 +1,38 @@
+/**
+ * This file contains functions used in USB Boot command
+ * and Boot2/FW update
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "defs.h"
+#include "dev.h"
+#include "if_usb.h"
+
+/**
+ * @brief This function issues Boot command to the Boot2 code
+ * @param ivalue 1:Boot from FW by USB-Download
+ * 2:Boot from FW in EEPROM
+ * @return 0
+ */
+int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ struct bootcmdstr sbootcmd;
+ int i;
+
+ /* Prepare command */
+ sbootcmd.u32magicnumber = BOOT_CMD_MAGIC_NUMBER;
+ sbootcmd.u8cmd_tag = ivalue;
+ for (i=0; i<11; i++)
+ sbootcmd.au8dumy[i]=0x00;
+ memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
+
+ /* Issue command */
+ usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
+
+ return 0;
+}
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
new file mode 100644
index 000000000000..695fb6a66ffe
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -0,0 +1,952 @@
+/**
+ * This file contains functions used in USB interface module.
+ */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "if_usb.h"
+
+#define MESSAGE_HEADER_LEN 4
+
+static const char usbdriver_name[] = "usb8xxx";
+
+static struct usb_device_id if_usb_table[] = {
+ /* Enter the device signature inside */
+ {
+ USB_DEVICE(USB8388_VID_1, USB8388_PID_1),
+ },
+ {
+ USB_DEVICE(USB8388_VID_2, USB8388_PID_2),
+ },
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, if_usb_table);
+
+static void if_usb_receive(struct urb *urb);
+static void if_usb_receive_fwload(struct urb *urb);
+
+/**
+ * @brief call back function to handle the status of the URB
+ * @param urb pointer to urb structure
+ * @return N/A
+ */
+static void if_usb_write_bulk_callback(struct urb *urb)
+{
+ wlan_private *priv = (wlan_private *) (urb->context);
+ wlan_adapter *adapter = priv->adapter;
+ struct net_device *dev = priv->wlan_dev.netdev;
+
+ /* handle the transmission complete validations */
+
+ if (urb->status != 0) {
+ /* print the failure status number for debug */
+ lbs_pr_info("URB in failure status\n");
+ } else {
+ lbs_dev_dbg(2, &urb->dev->dev, "URB status is successfull\n");
+ lbs_dev_dbg(2, &urb->dev->dev, "Actual length transmitted %d\n",
+ urb->actual_length);
+ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+ /* Wake main thread if commands are pending */
+ if (!adapter->cur_cmd)
+ wake_up_interruptible(&priv->mainthread.waitq);
+ if ((adapter->connect_status == libertas_connected))
+ netif_wake_queue(dev);
+ }
+
+ return;
+}
+
+/**
+ * @brief free tx/rx urb, skb and rx buffer
+ * @param cardp pointer usb_card_rec
+ * @return N/A
+ */
+void if_usb_free(struct usb_card_rec *cardp)
+{
+ ENTER();
+
+ /* Unlink tx & rx urb */
+ usb_kill_urb(cardp->tx_urb);
+ usb_kill_urb(cardp->rx_urb);
+
+ usb_free_urb(cardp->tx_urb);
+ cardp->tx_urb = NULL;
+
+ usb_free_urb(cardp->rx_urb);
+ cardp->rx_urb = NULL;
+
+ kfree(cardp->bulk_out_buffer);
+ cardp->bulk_out_buffer = NULL;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief sets the configuration values
+ * @param ifnum interface number
+ * @param id pointer to usb_device_id
+ * @return 0 on success, error code on failure
+ */
+static int if_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ wlan_private *pwlanpriv;
+ struct usb_card_rec *usb_cardp;
+ int i;
+
+ udev = interface_to_usbdev(intf);
+
+ usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
+ if (!usb_cardp) {
+ lbs_pr_err("Out of memory allocating private data.\n");
+ goto error;
+ }
+
+ usb_cardp->udev = udev;
+ iface_desc = intf->cur_altsetting;
+
+ lbs_dev_dbg(1, &udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
+ " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+ udev->descriptor.bcdUSB,
+ udev->descriptor.bDeviceClass,
+ udev->descriptor.bDeviceSubClass,
+ udev->descriptor.bDeviceProtocol);
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK)) {
+ /* we found a bulk in endpoint */
+ lbs_dev_dbg(1, &udev->dev, "Bulk in size is %d\n",
+ endpoint->wMaxPacketSize);
+ if (!
+ (usb_cardp->rx_urb =
+ usb_alloc_urb(0, GFP_KERNEL))) {
+ lbs_dev_dbg(1, &udev->dev,
+ "Rx URB allocation failed\n");
+ goto dealloc;
+ }
+ usb_cardp->rx_urb_recall = 0;
+
+ usb_cardp->bulk_in_size =
+ endpoint->wMaxPacketSize;
+ usb_cardp->bulk_in_endpointAddr =
+ (endpoint->
+ bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ lbs_dev_dbg(1, &udev->dev, "in_endpoint = %d\n",
+ endpoint->bEndpointAddress);
+ }
+
+ if (((endpoint->
+ bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+ USB_DIR_OUT)
+ && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK)) {
+ /* We found bulk out endpoint */
+ if (!
+ (usb_cardp->tx_urb =
+ usb_alloc_urb(0, GFP_KERNEL))) {
+ lbs_dev_dbg(1,&udev->dev,
+ "Tx URB allocation failed\n");
+ goto dealloc;
+ }
+
+ usb_cardp->bulk_out_size =
+ endpoint->wMaxPacketSize;
+ lbs_dev_dbg(1, &udev->dev,
+ "Bulk out size is %d\n",
+ endpoint->wMaxPacketSize);
+ usb_cardp->bulk_out_endpointAddr =
+ endpoint->bEndpointAddress;
+ lbs_dev_dbg(1, &udev->dev, "out_endpoint = %d\n",
+ endpoint->bEndpointAddress);
+ usb_cardp->bulk_out_buffer =
+ kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
+ GFP_KERNEL);
+
+ if (!usb_cardp->bulk_out_buffer) {
+ lbs_dev_dbg(1, &udev->dev,
+ "Could not allocate buffer\n");
+ goto dealloc;
+ }
+ }
+ }
+
+
+ /* At this point wlan_add_card() will be called. Don't worry
+ * about keeping pwlanpriv around since it will be set on our
+ * usb device data in -> add() -> libertas_sbi_register_dev().
+ */
+ if (!(pwlanpriv = wlan_add_card(usb_cardp)))
+ goto dealloc;
+
+ usb_get_dev(udev);
+ usb_set_intfdata(intf, usb_cardp);
+
+ /*
+ * return card structure, which can be got back in the
+ * diconnect function as the ptr
+ * argument.
+ */
+ return 0;
+
+dealloc:
+ if_usb_free(usb_cardp);
+
+error:
+ return -ENOMEM;
+}
+
+/**
+ * @brief free resource and cleanup
+ * @param udev pointer to usb_device
+ * @param ptr pointer to usb_cardp
+ * @return N/A
+ */
+static void if_usb_disconnect(struct usb_interface *intf)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+ wlan_private *priv = (wlan_private *) cardp->priv;
+ wlan_adapter *adapter = NULL;
+
+ adapter = priv->adapter;
+
+ /*
+ * Update Surprise removed to TRUE
+ */
+ adapter->surpriseremoved = 1;
+
+ /* card is removed and we can call wlan_remove_card */
+ lbs_dev_dbg(1, &cardp->udev->dev, "call remove card\n");
+ wlan_remove_card(cardp);
+
+ /* Unlink and free urb */
+ if_usb_free(cardp);
+
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(interface_to_usbdev(intf));
+
+ return;
+}
+
+/**
+ * @brief This function download FW
+ * @param priv pointer to wlan_private
+ * @return 0
+ */
+static int if_prog_firmware(wlan_private * priv)
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ struct FWData *fwdata;
+ struct fwheader *fwheader;
+ u8 *firmware = priv->firmware->data;
+
+ fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
+
+ if (!fwdata)
+ return -1;
+
+ fwheader = &fwdata->fwheader;
+
+ if (!cardp->CRC_OK) {
+ cardp->totalbytes = cardp->fwlastblksent;
+ cardp->fwseqnum = cardp->lastseqnum - 1;
+ }
+
+ lbs_dev_dbg(2, &cardp->udev->dev, "totalbytes = %d\n",
+ cardp->totalbytes);
+
+ memcpy(fwheader, &firmware[cardp->totalbytes],
+ sizeof(struct fwheader));
+
+ cardp->fwlastblksent = cardp->totalbytes;
+ cardp->totalbytes += sizeof(struct fwheader);
+
+ lbs_dev_dbg(2, &cardp->udev->dev,"Copy Data\n");
+ memcpy(fwdata->data, &firmware[cardp->totalbytes],
+ fwdata->fwheader.datalength);
+
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "Data length = %d\n", fwdata->fwheader.datalength);
+
+ cardp->fwseqnum = cardp->fwseqnum + 1;
+
+ fwdata->seqnum = cardp->fwseqnum;
+ cardp->lastseqnum = fwdata->seqnum;
+ cardp->totalbytes += fwdata->fwheader.datalength;
+
+ if (fwheader->dnldcmd == FW_HAS_DATA_TO_RECV) {
+ lbs_dev_dbg(2, &cardp->udev->dev, "There is data to follow\n");
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "seqnum = %d totalbytes = %d\n", cardp->fwseqnum,
+ cardp->totalbytes);
+ memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
+ usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+
+ } else if (fwdata->fwheader.dnldcmd == FW_HAS_LAST_BLOCK) {
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "Host has finished FW downloading\n");
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "Donwloading FW JUMP BLOCK\n");
+ memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
+ usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+ cardp->fwfinalblk = 1;
+ }
+
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "The firmware download is done size is %d\n",
+ cardp->totalbytes);
+
+ kfree(fwdata);
+
+ return 0;
+}
+
+static int libertas_do_reset(wlan_private *priv)
+{
+ int ret;
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+
+ ret = usb_reset_device(cardp->udev);
+ if (!ret) {
+ msleep(10);
+ reset_device(priv);
+ msleep(10);
+ }
+ return ret;
+}
+
+/**
+ * @brief This function transfer the data to the device.
+ * @param priv pointer to wlan_private
+ * @param payload pointer to payload data
+ * @param nb data length
+ * @return 0 or -1
+ */
+int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
+{
+ /* pointer to card structure */
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ int ret = -1;
+
+ /* check if device is removed */
+ if (priv->adapter->surpriseremoved) {
+ lbs_dev_dbg(1, &cardp->udev->dev, "Device removed\n");
+ goto tx_ret;
+ }
+
+ usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
+ usb_sndbulkpipe(cardp->udev,
+ cardp->bulk_out_endpointAddr),
+ payload, nb, if_usb_write_bulk_callback, priv);
+
+ cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+ if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
+ /* transfer failed */
+ lbs_dev_dbg(1, &cardp->udev->dev, "usb_submit_urb failed\n");
+ ret = -1;
+ } else {
+ lbs_dev_dbg(2, &cardp->udev->dev, "usb_submit_urb success\n");
+ ret = 0;
+ }
+
+tx_ret:
+ return ret;
+}
+
+static int __if_usb_submit_rx_urb(wlan_private * priv,
+ void (*callbackfn)
+ (struct urb *urb))
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ struct sk_buff *skb;
+ struct read_cb_info *rinfo = &cardp->rinfo;
+ int ret = -1;
+
+ if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
+ lbs_pr_err("No free skb\n");
+ goto rx_ret;
+ }
+
+ rinfo->skb = skb;
+
+ /* Fill the receive configuration URB and initialise the Rx call back */
+ usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
+ usb_rcvbulkpipe(cardp->udev,
+ cardp->bulk_in_endpointAddr),
+ skb->tail + IPFIELD_ALIGN_OFFSET,
+ MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
+ rinfo);
+
+ cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+ lbs_dev_dbg(2, &cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+ if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
+ /* handle failure conditions */
+ lbs_dev_dbg(1, &cardp->udev->dev, "Submit Rx URB failed\n");
+ ret = -1;
+ } else {
+ lbs_dev_dbg(2, &cardp->udev->dev, "Submit Rx URB success\n");
+ ret = 0;
+ }
+
+rx_ret:
+ return ret;
+}
+
+static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
+{
+ return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
+}
+
+static inline int if_usb_submit_rx_urb(wlan_private * priv)
+{
+ return __if_usb_submit_rx_urb(priv, &if_usb_receive);
+}
+
+static void if_usb_receive_fwload(struct urb *urb)
+{
+ struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
+ wlan_private *priv = rinfo->priv;
+ struct sk_buff *skb = rinfo->skb;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+ struct fwsyncheader *syncfwheader;
+ struct bootcmdrespStr bootcmdresp;
+
+ if (urb->status) {
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "URB status is failed during fw load\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ if (cardp->bootcmdresp == 0) {
+ memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
+ sizeof(bootcmdresp));
+ if (cardp->udev->descriptor.bcdDevice < 0x3106) {
+ kfree_skb(skb);
+ if_usb_submit_rx_urb_fwload(priv);
+ cardp->bootcmdresp = 1;
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Received valid boot command response\n");
+ return;
+ }
+ if (bootcmdresp.u32magicnumber != BOOT_CMD_MAGIC_NUMBER) {
+ lbs_pr_info(
+ "boot cmd response wrong magic number (0x%x)\n",
+ bootcmdresp.u32magicnumber);
+ } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) {
+ lbs_pr_info(
+ "boot cmd response cmd_tag error (%d)\n",
+ bootcmdresp.u8cmd_tag);
+ } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) {
+ lbs_pr_info(
+ "boot cmd response result error (%d)\n",
+ bootcmdresp.u8result);
+ } else {
+ cardp->bootcmdresp = 1;
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Received valid boot command response\n");
+ }
+ kfree_skb(skb);
+ if_usb_submit_rx_urb_fwload(priv);
+ return;
+ }
+
+ syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+ if (!syncfwheader) {
+ lbs_dev_dbg(1, &cardp->udev->dev, "Failure to allocate syncfwheader\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
+ sizeof(struct fwsyncheader));
+
+ if (!syncfwheader->cmd) {
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "FW received Blk with correct CRC\n");
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "FW received Blk seqnum = %d\n",
+ syncfwheader->seqnum);
+ cardp->CRC_OK = 1;
+ } else {
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "FW received Blk with CRC error\n");
+ cardp->CRC_OK = 0;
+ }
+
+ kfree_skb(skb);
+
+ if (cardp->fwfinalblk) {
+ cardp->fwdnldover = 1;
+ goto exit;
+ }
+
+ if_prog_firmware(priv);
+
+ if_usb_submit_rx_urb_fwload(priv);
+exit:
+ kfree(syncfwheader);
+
+ return;
+
+}
+
+#define MRVDRV_MIN_PKT_LEN 30
+
+static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
+ struct usb_card_rec *cardp,
+ wlan_private *priv)
+{
+ if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +
+ MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) {
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Packet length is Invalid\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
+ skb_put(skb, recvlength);
+ skb_pull(skb, MESSAGE_HEADER_LEN);
+ libertas_process_rxed_packet(priv, skb);
+ priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN);
+}
+
+static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
+ struct sk_buff *skb,
+ struct usb_card_rec *cardp,
+ wlan_private *priv)
+{
+ u8 *cmdbuf;
+ if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) {
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "The receive buffer is too large\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ if (!in_interrupt())
+ BUG();
+
+ spin_lock(&priv->adapter->driver_lock);
+ /* take care of cur_cmd = NULL case by reading the
+ * data to clear the interrupt */
+ if (!priv->adapter->cur_cmd) {
+ cmdbuf = priv->wlan_dev.upld_buf;
+ priv->adapter->hisregcpy &= ~his_cmdupldrdy;
+ } else
+ cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
+
+ cardp->usb_int_cause |= his_cmdupldrdy;
+ priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN);
+ memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
+ priv->wlan_dev.upld_len);
+
+ kfree_skb(skb);
+ libertas_interrupt(priv->wlan_dev.netdev);
+ spin_unlock(&priv->adapter->driver_lock);
+
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Wake up main thread to handle cmd response\n");
+
+ return;
+}
+
+/**
+ * @brief This function reads of the packet into the upload buff,
+ * wake up the main thread and initialise the Rx callack.
+ *
+ * @param urb pointer to struct urb
+ * @return N/A
+ */
+static void if_usb_receive(struct urb *urb)
+{
+ struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
+ wlan_private *priv = rinfo->priv;
+ struct sk_buff *skb = rinfo->skb;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+
+ int recvlength = urb->actual_length;
+ u8 *recvbuff = NULL;
+ u32 recvtype;
+
+ ENTER();
+
+ if (recvlength) {
+ if (urb->status) {
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "URB status is failed\n");
+ kfree_skb(skb);
+ goto setup_for_next;
+ }
+
+ recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
+ memcpy(&recvtype, recvbuff, sizeof(u32));
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Recv length = 0x%x\n", recvlength);
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Receive type = 0x%X\n", recvtype);
+ recvtype = le32_to_cpu(recvtype);
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Receive type after = 0x%X\n", recvtype);
+ } else if (urb->status)
+ goto rx_exit;
+
+
+ switch (recvtype) {
+ case CMD_TYPE_DATA:
+ process_cmdtypedata(recvlength, skb, cardp, priv);
+ break;
+
+ case CMD_TYPE_REQUEST:
+ process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
+ break;
+
+ case CMD_TYPE_INDICATION:
+ /* Event cause handling */
+ spin_lock(&priv->adapter->driver_lock);
+ cardp->usb_event_cause = *(u32 *) (recvbuff + MESSAGE_HEADER_LEN);
+ lbs_dev_dbg(1, &cardp->udev->dev,"**EVENT** 0x%X\n",
+ cardp->usb_event_cause);
+ if (cardp->usb_event_cause & 0xffff0000) {
+ libertas_send_tx_feedback(priv);
+ break;
+ }
+ cardp->usb_event_cause = le32_to_cpu(cardp->usb_event_cause) << 3;
+ cardp->usb_int_cause |= his_cardevent;
+ kfree_skb(skb);
+ libertas_interrupt(priv->wlan_dev.netdev);
+ spin_unlock(&priv->adapter->driver_lock);
+ goto rx_exit;
+ default:
+ kfree_skb(skb);
+ break;
+ }
+
+setup_for_next:
+ if_usb_submit_rx_urb(priv);
+rx_exit:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function downloads data to FW
+ * @param priv pointer to wlan_private structure
+ * @param type type of data
+ * @param buf pointer to data buffer
+ * @param len number of bytes
+ * @return 0 or -1
+ */
+int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
+{
+ int ret = -1;
+ u32 tmp;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+
+ lbs_dev_dbg(1, &cardp->udev->dev,"*** type = %u\n", type);
+ lbs_dev_dbg(1, &cardp->udev->dev,"size after = %d\n", nb);
+
+ if (type == MVMS_CMD) {
+ tmp = cpu_to_le32(CMD_TYPE_REQUEST);
+ priv->wlan_dev.dnld_sent = DNLD_CMD_SENT;
+ memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
+ MESSAGE_HEADER_LEN);
+
+ } else {
+ tmp = cpu_to_le32(CMD_TYPE_DATA);
+ priv->wlan_dev.dnld_sent = DNLD_DATA_SENT;
+ memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
+ MESSAGE_HEADER_LEN);
+ }
+
+ memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
+
+ ret =
+ usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN);
+
+ return ret;
+}
+
+/* called with adapter->driver_lock held */
+int libertas_sbi_get_int_status(wlan_private * priv, u8 * ireg)
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+
+ *ireg = cardp->usb_int_cause;
+ cardp->usb_int_cause = 0;
+
+ lbs_dev_dbg(1, &cardp->udev->dev,"Int cause is 0x%X\n", *ireg);
+
+ return 0;
+}
+
+int libertas_sbi_read_event_cause(wlan_private * priv)
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ priv->adapter->eventcause = cardp->usb_event_cause;
+ /* Re-submit rx urb here to avoid event lost issue */
+ if_usb_submit_rx_urb(priv);
+ return 0;
+}
+
+int reset_device(wlan_private *priv)
+{
+ int ret;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset,
+ cmd_act_halt, 0, 0, NULL);
+ msleep_interruptible(10);
+
+ return ret;
+}
+
+int libertas_sbi_unregister_dev(wlan_private * priv)
+{
+ int ret = 0;
+
+ /* Need to send a Reset command to device before USB resources freed
+ * and wlan_remove_card() called, then device can handle FW download
+ * again.
+ */
+ if (priv)
+ reset_device(priv);
+
+ return ret;
+}
+
+
+/**
+ * @brief This function register usb device and initialize parameter
+ * @param priv pointer to wlan_private
+ * @return 0 or -1
+ */
+int libertas_sbi_register_dev(wlan_private * priv)
+{
+
+ struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+ ENTER();
+
+ cardp->priv = priv;
+ cardp->eth_dev = priv->wlan_dev.netdev;
+ priv->hotplug_device = &(cardp->udev->dev);
+
+ SET_NETDEV_DEV(cardp->eth_dev, &(cardp->udev->dev));
+
+ lbs_dev_dbg(1, &cardp->udev->dev, "udev pointer is at %p\n",
+ cardp->udev);
+
+ LEAVE();
+ return 0;
+}
+
+
+
+int libertas_sbi_prog_firmware(wlan_private * priv)
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ int i = 0;
+ static int reset_count = 10;
+
+ ENTER();
+
+ cardp->rinfo.priv = priv;
+
+restart:
+ if (if_usb_submit_rx_urb_fwload(priv) < 0) {
+ lbs_dev_dbg(1, &cardp->udev->dev, "URB submission is failed\n");
+ LEAVE();
+ return -1;
+ }
+
+#ifdef SUPPORT_BOOT_COMMAND
+ cardp->bootcmdresp = 0;
+ do {
+ int j = 0;
+ i++;
+ /* Issue Boot command = 1, Boot from Download-FW */
+ if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
+ /* wait for command response */
+ do {
+ j++;
+ msleep_interruptible(100);
+ } while (cardp->bootcmdresp == 0 && j < 10);
+ } while (cardp->bootcmdresp == 0 && i < 5);
+
+ if (cardp->bootcmdresp == 0) {
+ if (--reset_count >= 0) {
+ libertas_do_reset(priv);
+ goto restart;
+ }
+ return -1;
+ }
+#endif
+
+ i = 0;
+ priv->adapter->fw_ready = 0;
+
+ cardp->totalbytes = 0;
+ cardp->fwlastblksent = 0;
+ cardp->CRC_OK = 1;
+ cardp->fwdnldover = 0;
+ cardp->fwseqnum = -1;
+ cardp->totalbytes = 0;
+ cardp->fwfinalblk = 0;
+
+ if_prog_firmware(priv);
+
+ do {
+ lbs_dev_dbg(1, &cardp->udev->dev,"Wlan sched timeout\n");
+ i++;
+ msleep_interruptible(100);
+ if (priv->adapter->surpriseremoved || i >= 20)
+ break;
+ } while (!cardp->fwdnldover);
+
+ if (!cardp->fwdnldover) {
+ lbs_pr_info("failed to load fw, resetting device!\n");
+ if (--reset_count >= 0) {
+ libertas_do_reset(priv);
+ goto restart;
+ }
+
+ lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
+ LEAVE();
+ return -1;
+ }
+
+ if_usb_submit_rx_urb(priv);
+
+ /* Delay 200 ms to waiting for the FW ready */
+ msleep_interruptible(200);
+
+ priv->adapter->fw_ready = 1;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Given a usb_card_rec return its wlan_private
+ * @param card pointer to a usb_card_rec
+ * @return pointer to wlan_private
+ */
+wlan_private *libertas_sbi_get_priv(void *card)
+{
+ struct usb_card_rec *cardp = card;
+ return cardp->priv;
+}
+
+#ifdef ENABLE_PM
+int libertas_sbi_suspend(wlan_private * priv)
+{
+ return 0;
+}
+
+int libertas_sbi_resume(wlan_private * priv)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+ wlan_private *priv = cardp->priv;
+
+ ENTER();
+
+ if (priv->adapter->psstate != PS_STATE_FULL_POWER)
+ return -1;
+
+ netif_device_detach(cardp->eth_dev);
+
+ /* Unlink tx & rx urb */
+ usb_kill_urb(cardp->tx_urb);
+ usb_kill_urb(cardp->rx_urb);
+
+ cardp->rx_urb_recall = 1;
+
+ LEAVE();
+ return 0;
+}
+
+static int if_usb_resume(struct usb_interface *intf)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+
+ ENTER();
+
+ cardp->rx_urb_recall = 0;
+
+ if_usb_submit_rx_urb(cardp->priv);
+
+ netif_device_attach(cardp->eth_dev);
+
+ LEAVE();
+ return 0;
+}
+#else
+#define if_usb_suspend NULL
+#define if_usb_resume NULL
+#endif
+
+static struct usb_driver if_usb_driver = {
+ /* driver name */
+ .name = usbdriver_name,
+ /* probe function name */
+ .probe = if_usb_probe,
+ /* disconnect function name */
+ .disconnect = if_usb_disconnect,
+ /* device signature table */
+ .id_table = if_usb_table,
+ .suspend = if_usb_suspend,
+ .resume = if_usb_resume,
+};
+
+/**
+ * @brief This function registers driver.
+ * @param add pointer to add_card callback function
+ * @param remove pointer to remove card callback function
+ * @param arg pointer to call back function parameter
+ * @return dummy success variable
+ */
+int libertas_sbi_register(void)
+{
+ /*
+ * API registers the Marvell USB driver
+ * to the USB system
+ */
+ usb_register(&if_usb_driver);
+
+ /* Return success to wlan layer */
+ return 0;
+}
+
+/**
+ * @brief This function removes usb driver.
+ * @return N/A
+ */
+void libertas_sbi_unregister(void)
+{
+ /* API unregisters the driver from USB subsystem */
+ usb_deregister(&if_usb_driver);
+ return;
+}
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
new file mode 100644
index 000000000000..785116720bc6
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -0,0 +1,109 @@
+/**
+ * This file contains definition for USB interface.
+ */
+#define CMD_TYPE_REQUEST 0xF00DFACE
+#define CMD_TYPE_DATA 0xBEADC0DE
+#define CMD_TYPE_INDICATION 0xBEEFFACE
+
+#define IPFIELD_ALIGN_OFFSET 2
+
+#define USB8388_VID_1 0x1286
+#define USB8388_PID_1 0x2001
+#define USB8388_VID_2 0x05a3
+#define USB8388_PID_2 0x8388
+
+#ifdef SUPPORT_BOOT_COMMAND
+#define BOOT_CMD_FW_BY_USB 0x01
+#define BOOT_CMD_FW_IN_EEPROM 0x02
+#define BOOT_CMD_UPDATE_BOOT2 0x03
+#define BOOT_CMD_UPDATE_FW 0x04
+#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */
+
+struct bootcmdstr
+{
+ u32 u32magicnumber;
+ u8 u8cmd_tag;
+ u8 au8dumy[11];
+};
+
+#define BOOT_CMD_RESP_OK 0x0001
+#define BOOT_CMD_RESP_FAIL 0x0000
+
+struct bootcmdrespStr
+{
+ u32 u32magicnumber;
+ u8 u8cmd_tag;
+ u8 u8result;
+ u8 au8dumy[2];
+};
+#endif /* SUPPORT_BOOT_COMMAND */
+
+/* read callback private data */
+struct read_cb_info {
+ wlan_private *priv;
+ struct sk_buff *skb;
+};
+
+/** USB card description structure*/
+struct usb_card_rec {
+ struct net_device *eth_dev;
+ struct usb_device *udev;
+ struct urb *rx_urb, *tx_urb;
+ void *priv;
+ struct read_cb_info rinfo;
+
+ int bulk_in_size;
+ u8 bulk_in_endpointAddr;
+
+ u8 *bulk_out_buffer;
+ int bulk_out_size;
+ u8 bulk_out_endpointAddr;
+
+ u8 CRC_OK;
+ u32 fwseqnum;
+ u32 lastseqnum;
+ u32 totalbytes;
+ u32 fwlastblksent;
+ u8 fwdnldover;
+ u8 fwfinalblk;
+
+ u32 usb_event_cause;
+ u8 usb_int_cause;
+
+ u8 rx_urb_recall;
+
+ u8 bootcmdresp;
+};
+
+/** fwheader */
+struct fwheader {
+ u32 dnldcmd;
+ u32 baseaddr;
+ u32 datalength;
+ u32 CRC;
+};
+
+#define FW_MAX_DATA_BLK_SIZE 600
+/** FWData */
+struct FWData {
+ struct fwheader fwheader;
+ u32 seqnum;
+ u8 data[FW_MAX_DATA_BLK_SIZE];
+};
+
+/** fwsyncheader */
+struct fwsyncheader {
+ u32 cmd;
+ u32 seqnum;
+};
+
+#define FW_HAS_DATA_TO_RECV 0x00000001
+#define FW_HAS_LAST_BLOCK 0x00000004
+
+#define FW_DATA_XMIT_SIZE \
+ sizeof(struct fwheader) + fwdata->fwheader.datalength + sizeof(u32)
+
+int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
+void if_usb_free(struct usb_card_rec *cardp);
+int if_usb_issue_boot_command(wlan_private *priv, int ivalue);
+
diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c
new file mode 100644
index 000000000000..82b39642423a
--- /dev/null
+++ b/drivers/net/wireless/libertas/ioctl.c
@@ -0,0 +1,2500 @@
+/**
+ * This file contains ioctl functions
+ */
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \
+ IW_ESSID_MAX_SIZE + \
+ IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
+ IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
+ IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */
+
+#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
+
+static int setrxantenna(wlan_private * priv, int mode)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ if (mode != RF_ANTENNA_1 && mode != RF_ANTENNA_2
+ && mode != RF_ANTENNA_AUTO) {
+ return -EINVAL;
+ }
+
+ adapter->rxantennamode = mode;
+
+ lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+ cmd_act_set_rx,
+ cmd_option_waitforrsp, 0,
+ &adapter->rxantennamode);
+ return ret;
+}
+
+static int settxantenna(wlan_private * priv, int mode)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ if ((mode != RF_ANTENNA_1) && (mode != RF_ANTENNA_2)
+ && (mode != RF_ANTENNA_AUTO)) {
+ return -EINVAL;
+ }
+
+ adapter->txantennamode = mode;
+
+ lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+ cmd_act_set_tx,
+ cmd_option_waitforrsp, 0,
+ &adapter->txantennamode);
+
+ return ret;
+}
+
+static int getrxantenna(wlan_private * priv, char *buf)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ // clear it, so we will know if the value
+ // returned below is correct or not.
+ adapter->rxantennamode = 0;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+ cmd_act_get_rx,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode);
+
+ return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1;
+}
+
+static int gettxantenna(wlan_private * priv, char *buf)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ // clear it, so we will know if the value
+ // returned below is correct or not.
+ adapter->txantennamode = 0;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+ cmd_act_get_tx,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode);
+
+ return sprintf(buf, "0x%04x", adapter->txantennamode) + 1;
+}
+
+static int wlan_set_region(wlan_private * priv, u16 region_code)
+{
+ int i;
+
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ // use the region code to search for the index
+ if (region_code == libertas_region_code_to_index[i]) {
+ priv->adapter->regiontableindex = (u16) i;
+ priv->adapter->regioncode = region_code;
+ break;
+ }
+ }
+
+ // if it's unidentified region code
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ lbs_pr_debug(1, "region Code not identified\n");
+ LEAVE();
+ return -1;
+ }
+
+ if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Get/Set Firmware wakeup method
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to user data
+ * @return 0--success, otherwise fail
+ */
+static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int data;
+ ENTER();
+
+ if ((int)wrq->u.data.length == 0) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &adapter->pkttxctrl, sizeof(u32))) {
+ lbs_pr_alert("copy_to_user failed!\n");
+ return -EFAULT;
+ }
+ } else {
+ if ((int)wrq->u.data.length > 1) {
+ lbs_pr_alert("ioctl too many args!\n");
+ return -EFAULT;
+ }
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_alert("Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ adapter->pkttxctrl = (u32) data;
+ }
+
+ wrq->u.data.length = 1;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get/Set NULL Package generation interval
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to user data
+ * @return 0--success, otherwise fail
+ */
+static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int data;
+ ENTER();
+
+ if ((int)wrq->u.data.length == 0) {
+ data = adapter->nullpktinterval;
+
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ lbs_pr_alert( "copy_to_user failed!\n");
+ return -EFAULT;
+ }
+ } else {
+ if ((int)wrq->u.data.length > 1) {
+ lbs_pr_alert( "ioctl too many args!\n");
+ return -EFAULT;
+ }
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ adapter->nullpktinterval = data;
+ }
+
+ wrq->u.data.length = 1;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int data[2];
+ ENTER();
+ data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+ data[1] = adapter->rxpd_rate;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+ wrq->u.data.length = 2;
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+ int data[4];
+
+ ENTER();
+ memset(data, 0, sizeof(data));
+ if (wrq->u.data.length) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ min_t(size_t, wrq->u.data.length, 4) * sizeof(int)))
+ return -EFAULT;
+ }
+ if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) {
+ if (adapter->connect_status == libertas_connected) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rssi,
+ 0,
+ cmd_option_waitforrsp,
+ 0, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+ }
+
+ if (wrq->u.data.length == 0) {
+ data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+ data[1] = adapter->SNR[TYPE_BEACON][TYPE_AVG];
+ data[2] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+ data[3] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4))
+ return -EFAULT;
+ wrq->u.data.length = 4;
+ } else if (data[0] == 0) {
+ data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+ return -EFAULT;
+ wrq->u.data.length = 1;
+ } else if (data[0] == 1) {
+ data[0] = adapter->SNR[TYPE_BEACON][TYPE_AVG];
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+ return -EFAULT;
+ wrq->u.data.length = 1;
+ } else if (data[0] == 2) {
+ data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+ return -EFAULT;
+ wrq->u.data.length = 1;
+ } else if (data[0] == 3) {
+ data[0] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+ return -EFAULT;
+ wrq->u.data.length = 1;
+ } else
+ return -ENOTSUPP;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq)
+{
+ int data;
+ wlan_adapter *adapter = priv->adapter;
+
+ if (wrq->u.data.length > 0) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int)))
+ return -EFAULT;
+
+ lbs_pr_debug(1, "WLAN SET BEACON INTERVAL: %d\n", data);
+ if ((data > MRVDRV_MAX_BEACON_INTERVAL)
+ || (data < MRVDRV_MIN_BEACON_INTERVAL))
+ return -ENOTSUPP;
+ adapter->beaconperiod = data;
+ }
+ data = adapter->beaconperiod;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int)))
+ return -EFAULT;
+
+ wrq->u.data.length = 1;
+
+ return 0;
+}
+
+static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+ int temp;
+ int data = 0;
+ int *val;
+
+ ENTER();
+ data = SUBCMD_DATA(wrq);
+ if ((data == 0) || (data == 1)) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rssi,
+ 0, cmd_option_waitforrsp,
+ 0, NULL);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+
+ switch (data) {
+ case 0:
+
+ temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+ adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+ break;
+ case 1:
+ temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG],
+ adapter->NF[TYPE_BEACON][TYPE_AVG]);
+ break;
+ case 2:
+ temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+ adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+ break;
+ case 3:
+ temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+ adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ val = (int *)wrq->u.name;
+ *val = temp;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+ int temp;
+ int data = 0;
+ int *val;
+
+ data = SUBCMD_DATA(wrq);
+ if ((data == 0) || (data == 1)) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rssi,
+ 0, cmd_option_waitforrsp,
+ 0, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+
+ switch (data) {
+ case 0:
+ temp = adapter->NF[TYPE_BEACON][TYPE_NOAVG];
+ break;
+ case 1:
+ temp = adapter->NF[TYPE_BEACON][TYPE_AVG];
+ break;
+ case 2:
+ temp = adapter->NF[TYPE_RXPD][TYPE_NOAVG];
+ break;
+ case 3:
+ temp = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ temp = CAL_NF(temp);
+
+ lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp);
+ val = (int *)wrq->u.name;
+ *val = temp;
+ return 0;
+}
+
+static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int *pdata;
+ struct iwreq *wrq = (struct iwreq *)req;
+ int ret = 0;
+ adapter->txrate = 0;
+ lbs_pr_debug(1, "wlan_get_txrate_ioctl\n");
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query,
+ cmd_act_get, cmd_option_waitforrsp,
+ 0, NULL);
+ if (ret)
+ return ret;
+
+ pdata = (int *)wrq->u.name;
+ *pdata = (int)adapter->txrate;
+ return 0;
+}
+
+static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ char status[64];
+ wlan_adapter *adapter = priv->adapter;
+
+ memset(status, 0, sizeof(status));
+
+ switch (adapter->inframode) {
+ case wlan802_11ibss:
+ if (adapter->connect_status == libertas_connected) {
+ if (adapter->adhoccreate)
+ memcpy(&status, "AdhocStarted", sizeof(status));
+ else
+ memcpy(&status, "AdhocJoined", sizeof(status));
+ } else {
+ memcpy(&status, "AdhocIdle", sizeof(status));
+ }
+ break;
+ case wlan802_11infrastructure:
+ memcpy(&status, "Inframode", sizeof(status));
+ break;
+ default:
+ memcpy(&status, "AutoUnknownmode", sizeof(status));
+ break;
+ }
+
+ lbs_pr_debug(1, "status = %s\n", status);
+ wrq->u.data.length = strlen(status) + 1;
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer,
+ &status, wrq->u.data.length))
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set/Get WPA IE
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (wrq->u.data.length > sizeof(adapter->wpa_ie)) {
+ lbs_pr_debug(1, "failed to copy WPA IE, too big \n");
+ return -EFAULT;
+ }
+ if (copy_from_user(adapter->wpa_ie, wrq->u.data.pointer,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "failed to copy WPA IE \n");
+ return -EFAULT;
+ }
+ adapter->wpa_ie_len = wrq->u.data.length;
+ lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len,
+ adapter->wpa_ie[0]);
+ lbs_dbg_hex("wpa_ie", adapter->wpa_ie, adapter->wpa_ie_len);
+ if (adapter->wpa_ie[0] == WPA_IE)
+ adapter->secinfo.WPAenabled = 1;
+ else if (adapter->wpa_ie[0] == WPA2_IE)
+ adapter->secinfo.WPA2enabled = 1;
+ else {
+ adapter->secinfo.WPAenabled = 0;
+ adapter->secinfo.WPA2enabled = 0;
+ }
+ } else {
+ memset(adapter->wpa_ie, 0, sizeof(adapter->wpa_ie));
+ adapter->wpa_ie_len = wrq->u.data.length;
+ lbs_pr_debug(1, "Reset wpa_ie_len=%d IE=%#x\n",
+ adapter->wpa_ie_len, adapter->wpa_ie[0]);
+ adapter->secinfo.WPAenabled = 0;
+ adapter->secinfo.WPA2enabled = 0;
+ }
+
+ // enable/disable RSN in firmware if WPA is enabled/disabled
+ // depending on variable adapter->secinfo.WPAenabled is set or not
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn,
+ cmd_act_set, cmd_option_waitforrsp,
+ 0, NULL);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Auto prescan
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ int data;
+ wlan_adapter *adapter = priv->adapter;
+ int *val;
+
+ data = SUBCMD_DATA(wrq);
+ lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data);
+ adapter->prescan = data;
+
+ val = (int *)wrq->u.name;
+ *val = data;
+ return 0;
+}
+
+static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ u32 mdtim;
+ int idata;
+ int ret = -EINVAL;
+
+ ENTER();
+
+ idata = SUBCMD_DATA(wrq);
+ mdtim = (u32) idata;
+ if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM)
+ && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM))
+ || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) {
+ priv->adapter->multipledtim = mdtim;
+ ret = 0;
+ }
+ if (ret)
+ lbs_pr_debug(1, "Invalid parameter, multipledtim not changed.\n");
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set authentication mode
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int alg;
+ struct iwreq *wrq = (struct iwreq *)req;
+ wlan_adapter *adapter = priv->adapter;
+
+ if (wrq->u.data.flags == 0) {
+ //from iwpriv subcmd
+ alg = SUBCMD_DATA(wrq);
+ } else {
+ //from wpa_supplicant subcmd
+ if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+ }
+
+ lbs_pr_debug(1, "auth alg is %#x\n", alg);
+
+ switch (alg) {
+ case AUTH_ALG_SHARED_KEY:
+ adapter->secinfo.authmode = wlan802_11authmodeshared;
+ break;
+ case AUTH_ALG_NETWORK_EAP:
+ adapter->secinfo.authmode =
+ wlan802_11authmodenetworkEAP;
+ break;
+ case AUTH_ALG_OPEN_SYSTEM:
+ default:
+ adapter->secinfo.authmode = wlan802_11authmodeopen;
+ break;
+ }
+ return 0;
+}
+
+/**
+ * @brief Set 802.1x authentication mode
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int alg;
+ struct iwreq *wrq = (struct iwreq *)req;
+
+ if (wrq->u.data.flags == 0) {
+ //from iwpriv subcmd
+ alg = SUBCMD_DATA(wrq);
+ } else {
+ //from wpa_supplicant subcmd
+ if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+ }
+ lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg);
+ priv->adapter->secinfo.auth1xalg = alg;
+ return 0;
+}
+
+static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int mode;
+ struct iwreq *wrq = (struct iwreq *)req;
+
+ ENTER();
+
+ if (wrq->u.data.flags == 0) {
+ //from iwpriv subcmd
+ mode = SUBCMD_DATA(wrq);
+ } else {
+ //from wpa_supplicant subcmd
+ if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+ }
+ lbs_pr_debug(1, "encryption mode is %#x\n", mode);
+ priv->adapter->secinfo.Encryptionmode = mode;
+
+ LEAVE();
+ return 0;
+}
+
+static void adjust_mtu(wlan_private * priv)
+{
+ int mtu_increment = 0;
+
+ if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+ mtu_increment += sizeof(struct ieee80211_hdr_4addr);
+
+ if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP)
+ mtu_increment += max(sizeof(struct tx_radiotap_hdr),
+ sizeof(struct rx_radiotap_hdr));
+ priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN
+ - sizeof(struct ethhdr)
+ + mtu_increment;
+}
+
+/**
+ * @brief Set Link-Layer Layer mode
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int mode;
+
+ mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data;
+
+ switch (mode) {
+ case WLAN_LINKMODE_802_3:
+ priv->adapter->linkmode = mode;
+ break;
+ case WLAN_LINKMODE_802_11:
+ priv->adapter->linkmode = mode;
+ break;
+ default:
+ lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n",
+ mode);
+ return -EINVAL;
+ break;
+ }
+ lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode);
+
+ adjust_mtu(priv);
+
+ return 0;
+}
+
+/**
+ * @brief Set Radio header mode
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int mode;
+
+ mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data;
+
+ switch (mode) {
+ case WLAN_RADIOMODE_NONE:
+ priv->adapter->radiomode = mode;
+ break;
+ case WLAN_RADIOMODE_RADIOTAP:
+ priv->adapter->radiomode = mode;
+ break;
+ default:
+ lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n",
+ mode);
+ return -EINVAL;
+ }
+ lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode);
+
+ adjust_mtu(priv);
+ return 0;
+}
+
+/**
+ * @brief Set Debug header mode
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ priv->adapter->debugmode = (int)((struct ifreq *)
+ ((u8 *) req + 4))->ifr_data;
+ return 0;
+}
+
+static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv,
+ struct ifreq *req)
+{
+ int len;
+ char buf[8];
+ struct iwreq *wrq = (struct iwreq *)req;
+
+ lbs_pr_debug(1, "WLAN_SUBCMD_GETRXANTENNA\n");
+ len = getrxantenna(priv, buf);
+
+ wrq->u.data.length = len;
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+ lbs_pr_debug(1, "CopyToUser failed\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv,
+ struct ifreq *req)
+{
+ int len;
+ char buf[8];
+ struct iwreq *wrq = (struct iwreq *)req;
+
+ lbs_pr_debug(1, "WLAN_SUBCMD_GETTXANTENNA\n");
+ len = gettxantenna(priv, buf);
+
+ wrq->u.data.length = len;
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+ lbs_pr_debug(1, "CopyToUser failed\n");
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+/**
+ * @brief Get the MAC TSF value from the firmware
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to iwreq structure containing buffer
+ * space to store a TSF value retrieved from the firmware
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ u64 tsfval;
+ int ret;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_get_tsf,
+ 0, cmd_option_waitforrsp, 0, &tsfval);
+
+ lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval);
+
+ if (ret != 0) {
+ lbs_pr_debug(1, "IOCTL: Get TSF; command exec failed\n");
+ ret = -EFAULT;
+ } else {
+ if (copy_to_user(wrq->u.data.pointer,
+ &tsfval,
+ min_t(size_t, wrq->u.data.length,
+ sizeof(tsfval))) != 0) {
+
+ lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n");
+ ret = -EFAULT;
+ } else {
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+/**
+ * @brief Get/Set adapt rate
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret;
+ wlan_adapter *adapter = priv->adapter;
+ int data[2];
+
+ memset(data, 0, sizeof(data));
+ if (!wrq->u.data.length) {
+ lbs_pr_debug(1, "Get ADAPT RATE SET\n");
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rate_adapt_rateset,
+ cmd_act_get,
+ cmd_option_waitforrsp, 0, NULL);
+ data[0] = adapter->enablehwauto;
+ data[1] = adapter->ratebitmap;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+#define GET_TWO_INT 2
+ wrq->u.data.length = GET_TWO_INT;
+ } else {
+ lbs_pr_debug(1, "Set ADAPT RATE SET\n");
+ if (wrq->u.data.length > 2)
+ return -EINVAL;
+ if (copy_from_user
+ (data, wrq->u.data.pointer,
+ sizeof(int) * wrq->u.data.length)) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ adapter->enablehwauto = data[0];
+ adapter->ratebitmap = data[1];
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rate_adapt_rateset,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+ }
+ return ret;
+}
+
+/**
+ * @brief Get/Set inactivity timeout
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret;
+ int data = 0;
+ u16 timeout = 0;
+
+ ENTER();
+ if (wrq->u.data.length > 1)
+ return -ENOTSUPP;
+
+ if (wrq->u.data.length == 0) {
+ /* Get */
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_inactivity_timeout,
+ cmd_act_get,
+ cmd_option_waitforrsp, 0,
+ &timeout);
+ data = timeout;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+ } else {
+ /* Set */
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ timeout = data;
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_inactivity_timeout,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0,
+ &timeout);
+ }
+
+ wrq->u.data.length = 1;
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret;
+ char buf[GETLOG_BUFSIZE - 1];
+ wlan_adapter *adapter = priv->adapter;
+
+ lbs_pr_debug(1, " GET STATS\n");
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log,
+ 0, cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ return ret;
+ }
+
+ if (wrq->u.data.pointer) {
+ sprintf(buf, "\n mcasttxframe %u failed %u retry %u "
+ "multiretry %u framedup %u "
+ "rtssuccess %u rtsfailure %u ackfailure %u\n"
+ "rxfrag %u mcastrxframe %u fcserror %u "
+ "txframe %u wepundecryptable %u ",
+ adapter->logmsg.mcasttxframe,
+ adapter->logmsg.failed,
+ adapter->logmsg.retry,
+ adapter->logmsg.multiretry,
+ adapter->logmsg.framedup,
+ adapter->logmsg.rtssuccess,
+ adapter->logmsg.rtsfailure,
+ adapter->logmsg.ackfailure,
+ adapter->logmsg.rxfrag,
+ adapter->logmsg.mcastrxframe,
+ adapter->logmsg.fcserror,
+ adapter->logmsg.txframe,
+ adapter->logmsg.wepundecryptable);
+ wrq->u.data.length = strlen(buf) + 1;
+ if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ u8 buf[12];
+ u8 *option[] = { "active", "passive", "get", };
+ int i, max_options = (sizeof(option) / sizeof(option[0]));
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ if (priv->adapter->enable11d) {
+ lbs_pr_debug(1, "11D: Cannot set scantype when 11D enabled\n");
+ return -EFAULT;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf),
+ wrq->u.data.length)))
+ return -EFAULT;
+
+ lbs_pr_debug(1, "Scan type Option = %s\n", buf);
+
+ buf[sizeof(buf) - 1] = '\0';
+
+ for (i = 0; i < max_options; i++) {
+ if (!strcmp(buf, option[i]))
+ break;
+ }
+
+ switch (i) {
+ case 0:
+ adapter->scantype = cmd_scan_type_active;
+ break;
+ case 1:
+ adapter->scantype = cmd_scan_type_passive;
+ break;
+ case 2:
+ wrq->u.data.length = strlen(option[adapter->scantype]) + 1;
+
+ if (copy_to_user(wrq->u.data.pointer,
+ option[adapter->scantype],
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+
+ break;
+ default:
+ lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ wlan_adapter *adapter = priv->adapter;
+ u8 buf[12];
+ u8 *option[] = { "bss", "ibss", "any", "get" };
+ int i, max_options = (sizeof(option) / sizeof(option[0]));
+ int ret = 0;
+
+ ENTER();
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf),
+ wrq->u.data.length))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ lbs_pr_debug(1, "Scan mode Option = %s\n", buf);
+
+ buf[sizeof(buf) - 1] = '\0';
+
+ for (i = 0; i < max_options; i++) {
+ if (!strcmp(buf, option[i]))
+ break;
+ }
+
+ switch (i) {
+
+ case 0:
+ adapter->scanmode = cmd_bss_type_bss;
+ break;
+ case 1:
+ adapter->scanmode = cmd_bss_type_ibss;
+ break;
+ case 2:
+ adapter->scanmode = cmd_bss_type_any;
+ break;
+ case 3:
+
+ wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1;
+
+ lbs_pr_debug(1, "Get Scan mode Option = %s\n",
+ option[adapter->scanmode - 1]);
+
+ lbs_pr_debug(1, "Scan mode length %d\n", wrq->u.data.length);
+
+ if (copy_to_user(wrq->u.data.pointer,
+ option[adapter->scanmode - 1],
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ lbs_pr_debug(1, "GET Scan type Option after copy = %s\n",
+ (char *)wrq->u.data.pointer);
+
+ break;
+
+ default:
+ lbs_pr_debug(1, "Invalid Scan mode Ioctl Option\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set Adhoc G Rate
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to user data
+ * @return 0--success, otherwise fail
+ */
+static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int data, data1;
+ int *val;
+
+ ENTER();
+
+ data1 = SUBCMD_DATA(wrq);
+ switch (data1) {
+ case 0:
+ adapter->adhoc_grate_enabled = 0;
+ break;
+ case 1:
+ adapter->adhoc_grate_enabled = 1;
+ break;
+ case 2:
+ break;
+ default:
+ return -EINVAL;
+ }
+ data = adapter->adhoc_grate_enabled;
+ val = (int *)wrq->u.name;
+ *val = data;
+ LEAVE();
+ return 0;
+}
+
+static inline int hex2int(char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ if (c >= 'a' && c <= 'f')
+ return (c - 'a' + 10);
+ if (c >= 'A' && c <= 'F')
+ return (c - 'A' + 10);
+ return -1;
+}
+
+/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx")
+ into binary format (6 bytes).
+
+ This function expects that each byte is represented with 2 characters
+ (e.g., 11:2:11:11:11:11 is invalid)
+
+ */
+static char *eth_str2addr(char *ethstr, u8 * addr)
+{
+ int i, val, val2;
+ char *pos = ethstr;
+
+ /* get rid of initial blanks */
+ while (*pos == ' ' || *pos == '\t')
+ ++pos;
+
+ for (i = 0; i < 6; i++) {
+ val = hex2int(*pos++);
+ if (val < 0)
+ return NULL;
+ val2 = hex2int(*pos++);
+ if (val2 < 0)
+ return NULL;
+ addr[i] = (val * 16 + val2) & 0xff;
+
+ if (i < 5 && *pos++ != ':')
+ return NULL;
+ }
+ return pos;
+}
+
+/* this writes xx:xx:xx:xx:xx:xx into ethstr
+ (ethstr must have space for 18 chars) */
+static int eth_addr2str(u8 * addr, char *ethstr)
+{
+ int i;
+ char *pos = ethstr;
+
+ for (i = 0; i < 6; i++) {
+ sprintf(pos, "%02x", addr[i] & 0xff);
+ pos += 2;
+ if (i < 5)
+ *pos++ = ':';
+ }
+ return 17;
+}
+
+/**
+ * @brief Add an entry to the BT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char ethaddrs_str[18];
+ char *pos;
+ u8 ethaddr[ETH_ALEN];
+
+ ENTER();
+ if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
+ sizeof(ethaddrs_str)))
+ return -EFAULT;
+
+ if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
+ lbs_pr_info("BT_ADD: Invalid MAC address\n");
+ return -EINVAL;
+ }
+
+ lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str);
+ LEAVE();
+ return (libertas_prepare_and_send_command(priv, cmd_bt_access,
+ cmd_act_bt_access_add,
+ cmd_option_waitforrsp, 0, ethaddr));
+}
+
+/**
+ * @brief Delete an entry from the BT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char ethaddrs_str[18];
+ u8 ethaddr[ETH_ALEN];
+ char *pos;
+
+ ENTER();
+ if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
+ sizeof(ethaddrs_str)))
+ return -EFAULT;
+
+ if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
+ lbs_pr_info("Invalid MAC address\n");
+ return -EINVAL;
+ }
+
+ lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str);
+
+ return (libertas_prepare_and_send_command(priv,
+ cmd_bt_access,
+ cmd_act_bt_access_del,
+ cmd_option_waitforrsp, 0, ethaddr));
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Reset all entries from the BT table
+ * @param priv A pointer to wlan_private structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_bt_reset_ioctl(wlan_private * priv)
+{
+ ENTER();
+
+ lbs_pr_alert( "BT: resetting\n");
+
+ return (libertas_prepare_and_send_command(priv,
+ cmd_bt_access,
+ cmd_act_bt_access_reset,
+ cmd_option_waitforrsp, 0, NULL));
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief List an entry from the BT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int pos;
+ char *addr1;
+ struct iwreq *wrq = (struct iwreq *)req;
+ /* used to pass id and store the bt entry returned by the FW */
+ union {
+ int id;
+ char addr1addr2[2 * ETH_ALEN];
+ } param;
+ static char outstr[64];
+ char *pbuf = outstr;
+ int ret;
+
+ ENTER();
+
+ if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -1;
+ }
+ param.id = simple_strtoul(outstr, NULL, 10);
+ pos = sprintf(pbuf, "%d: ", param.id);
+ pbuf += pos;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
+ cmd_act_bt_access_list,
+ cmd_option_waitforrsp, 0,
+ (char *)&param);
+
+ if (ret == 0) {
+ addr1 = param.addr1addr2;
+
+ pos = sprintf(pbuf, "ignoring traffic from ");
+ pbuf += pos;
+ pos = eth_addr2str(addr1, pbuf);
+ pbuf += pos;
+ } else {
+ sprintf(pbuf, "(null)");
+ pbuf += pos;
+ }
+
+ wrq->u.data.length = strlen(outstr);
+ if (copy_to_user(wrq->u.data.pointer, (char *)outstr,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Find the next parameter in an input string
+ * @param ptr A pointer to the input parameter string
+ * @return A pointer to the next parameter, or 0 if no parameters left.
+ */
+static char * next_param(char * ptr)
+{
+ if (!ptr) return NULL;
+ while (*ptr == ' ' || *ptr == '\t') ++ptr;
+ return (*ptr == '\0') ? NULL : ptr;
+}
+
+/**
+ * @brief Add an entry to the FWT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[128];
+ static struct cmd_ds_fwt_access fwt_access;
+ char *ptr;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+ lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
+ return -EINVAL;
+ }
+
+ if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+ lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
+ return -EINVAL;
+ }
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.metric =
+ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+ else
+ fwt_access.metric = FWT_DEFAULT_METRIC;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+ else
+ fwt_access.dir = FWT_DEFAULT_DIR;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.ssn =
+ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+ else
+ fwt_access.ssn = FWT_DEFAULT_SSN;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.dsn =
+ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+ else
+ fwt_access.dsn = FWT_DEFAULT_DSN;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
+ else
+ fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
+ else
+ fwt_access.ttl = FWT_DEFAULT_TTL;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.expiration =
+ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+ else
+ fwt_access.expiration = FWT_DEFAULT_EXPIRATION;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
+ else
+ fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.snr =
+ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+ else
+ fwt_access.snr = FWT_DEFAULT_SNR;
+
+#ifdef DEBUG
+ {
+ char ethaddr1_str[18], ethaddr2_str[18];
+ eth_addr2str(fwt_access.da, ethaddr1_str);
+ eth_addr2str(fwt_access.ra, ethaddr2_str);
+ lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
+ fwt_access.dir, ethaddr2_str);
+ lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
+ fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
+ fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
+ fwt_access.sleepmode, fwt_access.snr);
+ }
+#endif
+
+ LEAVE();
+ return (libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_add,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access));
+}
+
+/**
+ * @brief Delete an entry from the FWT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[64];
+ static struct cmd_ds_fwt_access fwt_access;
+ char *ptr;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+ lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
+ return -EINVAL;
+ }
+
+ if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+ lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
+ return -EINVAL;
+ }
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+ else
+ fwt_access.dir = FWT_DEFAULT_DIR;
+
+#ifdef DEBUG
+ {
+ char ethaddr1_str[18], ethaddr2_str[18];
+ lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str);
+ eth_addr2str(fwt_access.da, ethaddr1_str);
+ eth_addr2str(fwt_access.ra, ethaddr2_str);
+ lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
+ ethaddr2_str, fwt_access.dir);
+ }
+#endif
+
+ LEAVE();
+ return (libertas_prepare_and_send_command(priv,
+ cmd_fwt_access,
+ cmd_act_fwt_access_del,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access));
+}
+
+
+/**
+ * @brief Print route parameters
+ * @param fwt_access struct cmd_ds_fwt_access with route info
+ * @param buf destination buffer for route info
+ */
+static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
+{
+ buf += sprintf(buf, " ");
+ buf += eth_addr2str(fwt_access.da, buf);
+ buf += sprintf(buf, " ");
+ buf += eth_addr2str(fwt_access.ra, buf);
+ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
+ buf += sprintf(buf, " %u", fwt_access.dir);
+ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
+ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
+ buf += sprintf(buf, " %u", fwt_access.hopcount);
+ buf += sprintf(buf, " %u", fwt_access.ttl);
+ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
+ buf += sprintf(buf, " %u", fwt_access.sleepmode);
+ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr));
+}
+
+/**
+ * @brief Lookup an entry in the FWT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[64];
+ char *ptr;
+ static struct cmd_ds_fwt_access fwt_access;
+ static char out_str[128];
+ int ret;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+ lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
+ return -EINVAL;
+ }
+
+#ifdef DEBUG
+ {
+ char ethaddr1_str[18];
+ lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str);
+ eth_addr2str(fwt_access.da, ethaddr1_str);
+ lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
+ }
+#endif
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_fwt_access,
+ cmd_act_fwt_access_lookup,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access);
+
+ if (ret == 0)
+ print_route(fwt_access, out_str);
+ else
+ sprintf(out_str, "(null)");
+
+ wrq->u.data.length = strlen(out_str);
+ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Reset all entries from the FWT table
+ * @param priv A pointer to wlan_private structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_reset_ioctl(wlan_private * priv)
+{
+ lbs_pr_debug(1, "FWT: resetting\n");
+
+ return (libertas_prepare_and_send_command(priv,
+ cmd_fwt_access,
+ cmd_act_fwt_access_reset,
+ cmd_option_waitforrsp, 0, NULL));
+}
+
+/**
+ * @brief List an entry from the FWT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[8];
+ static struct cmd_ds_fwt_access fwt_access;
+ char *ptr = in_str;
+ static char out_str[128];
+ char *pbuf = out_str;
+ int ret;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+ {
+ lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str);
+ lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
+ }
+#endif
+
+ ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_list,
+ cmd_option_waitforrsp, 0, (void *)&fwt_access);
+
+ if (ret == 0)
+ print_route(fwt_access, pbuf);
+ else
+ pbuf += sprintf(pbuf, " (null)");
+
+ wrq->u.data.length = strlen(out_str);
+ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief List an entry from the FRT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[64];
+ static struct cmd_ds_fwt_access fwt_access;
+ char *ptr = in_str;
+ static char out_str[128];
+ char *pbuf = out_str;
+ int ret;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+ {
+ lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str);
+ lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
+ }
+#endif
+
+ ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_list_route,
+ cmd_option_waitforrsp, 0, (void *)&fwt_access);
+
+ if (ret == 0) {
+ pbuf += sprintf(pbuf, " ");
+ pbuf += eth_addr2str(fwt_access.da, pbuf);
+ pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric));
+ pbuf += sprintf(pbuf, " %u", fwt_access.dir);
+ /* note that the firmware returns the nid in the id field */
+ pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id));
+ pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn));
+ pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn));
+ pbuf += sprintf(pbuf, " hop %u", fwt_access.hopcount);
+ pbuf += sprintf(pbuf, " ttl %u", fwt_access.ttl);
+ pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration));
+ } else
+ pbuf += sprintf(pbuf, " (null)");
+
+ wrq->u.data.length = strlen(out_str);
+ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief List an entry from the FNT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[8];
+ static struct cmd_ds_fwt_access fwt_access;
+ char *ptr = in_str;
+ static char out_str[128];
+ char *pbuf = out_str;
+ int ret;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ memset(&fwt_access, 0, sizeof(fwt_access));
+ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+ {
+ lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str);
+ lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
+ }
+#endif
+
+ ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_list_neighbor,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access);
+
+ if (ret == 0) {
+ pbuf += sprintf(pbuf, " ra ");
+ pbuf += eth_addr2str(fwt_access.ra, pbuf);
+ pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode);
+ pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr));
+ pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references));
+ } else
+ pbuf += sprintf(pbuf, " (null)");
+
+ wrq->u.data.length = strlen(out_str);
+ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Cleans up the route (FRT) and neighbor (FNT) tables
+ * (Garbage Collection)
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ static struct cmd_ds_fwt_access fwt_access;
+ int ret;
+
+ ENTER();
+
+ lbs_pr_debug(1, "FWT: cleaning up\n");
+
+ memset(&fwt_access, 0, sizeof(fwt_access));
+
+ ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_cleanup,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access);
+
+ if (ret == 0)
+ req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
+ else
+ return -EFAULT;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Gets firmware internal time (debug purposes)
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ static struct cmd_ds_fwt_access fwt_access;
+ int ret;
+
+ ENTER();
+
+ lbs_pr_debug(1, "FWT: getting time\n");
+
+ memset(&fwt_access, 0, sizeof(fwt_access));
+
+ ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_time,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access);
+
+ if (ret == 0)
+ req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
+ else
+ return -EFAULT;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Gets mesh ttl from firmware
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
+
+ ENTER();
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+
+ ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
+ cmd_act_mesh_get_ttl,
+ cmd_option_waitforrsp, 0,
+ (void *)&mesh_access);
+
+ if (ret == 0) {
+ req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0]));
+ }
+ else
+ return -EFAULT;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Gets mesh ttl from firmware
+ * @param priv A pointer to wlan_private structure
+ * @param ttl New ttl value
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
+{
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
+
+ ENTER();
+
+ if( (ttl > 0xff) || (ttl < 0) )
+ return -EINVAL;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = ttl;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
+ cmd_act_mesh_set_ttl,
+ cmd_option_waitforrsp, 0,
+ (void *)&mesh_access);
+
+ if (ret != 0)
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd command
+ * @return 0--success, otherwise fail
+ */
+int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int subcmd = 0;
+ int idata = 0;
+ int *pdata;
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct iwreq *wrq = (struct iwreq *)req;
+
+ ENTER();
+
+ lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+ case WLANSCAN_TYPE:
+ lbs_pr_debug(1, "Scan type Ioctl\n");
+ ret = wlan_scan_type_ioctl(priv, wrq);
+ break;
+
+ case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */
+ switch (wrq->u.data.flags) {
+ case WLANDEAUTH:
+ lbs_pr_debug(1, "Deauth\n");
+ libertas_send_deauth(priv);
+ break;
+
+ case WLANADHOCSTOP:
+ lbs_pr_debug(1, "Adhoc stop\n");
+ ret = libertas_do_adhocstop_ioctl(priv);
+ break;
+
+ case WLANRADIOON:
+ wlan_radio_ioctl(priv, 1);
+ break;
+
+ case WLANRADIOOFF:
+ wlan_radio_ioctl(priv, 0);
+ break;
+ case WLANWLANIDLEON:
+ libertas_idle_on(priv);
+ break;
+ case WLANWLANIDLEOFF:
+ libertas_idle_off(priv);
+ break;
+ case WLAN_SUBCMD_BT_RESET: /* bt_reset */
+ wlan_bt_reset_ioctl(priv);
+ break;
+ case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */
+ wlan_fwt_reset_ioctl(priv);
+ break;
+ } /* End of switch */
+ break;
+
+ case WLANSETWPAIE:
+ ret = wlan_setwpaie_ioctl(priv, req);
+ break;
+ case WLAN_SETINT_GETINT:
+ /* The first 4 bytes of req->ifr_data is sub-ioctl number
+ * after 4 bytes sits the payload.
+ */
+ subcmd = (int)req->ifr_data; //from iwpriv subcmd
+ switch (subcmd) {
+ case WLANNF:
+ ret = wlan_get_nf(priv, wrq);
+ break;
+ case WLANRSSI:
+ ret = wlan_get_rssi(priv, wrq);
+ break;
+ case WLANENABLE11D:
+ ret = libertas_cmd_enable_11d(priv, wrq);
+ break;
+ case WLANADHOCGRATE:
+ ret = wlan_do_set_grate_ioctl(priv, wrq);
+ break;
+ case WLAN_SUBCMD_SET_PRESCAN:
+ ret = wlan_subcmd_setprescan_ioctl(priv, wrq);
+ break;
+ }
+ break;
+
+ case WLAN_SETONEINT_GETONEINT:
+ switch (wrq->u.data.flags) {
+ case WLAN_BEACON_INTERVAL:
+ ret = wlan_beacon_interval(priv, wrq);
+ break;
+
+ case WLAN_LISTENINTRVL:
+ if (!wrq->u.data.length) {
+ int data;
+ lbs_pr_debug(1, "Get locallisteninterval value\n");
+#define GET_ONE_INT 1
+ data = adapter->locallisteninterval;
+ if (copy_to_user(wrq->u.data.pointer,
+ &data, sizeof(int))) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+
+ wrq->u.data.length = GET_ONE_INT;
+ } else {
+ int data;
+ if (copy_from_user
+ (&data, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ lbs_pr_debug(1, "Set locallisteninterval = %d\n",
+ data);
+#define MAX_U16_VAL 65535
+ if (data > MAX_U16_VAL) {
+ lbs_pr_debug(1, "Exceeds U16 value\n");
+ return -EINVAL;
+ }
+ adapter->locallisteninterval = data;
+ }
+ break;
+ case WLAN_TXCONTROL:
+ ret = wlan_txcontrol(priv, wrq); //adds for txcontrol ioctl
+ break;
+
+ case WLAN_NULLPKTINTERVAL:
+ ret = wlan_null_pkt_interval(priv, wrq);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
+ case WLAN_SETONEINT_GETNONE:
+ /* The first 4 bytes of req->ifr_data is sub-ioctl number
+ * after 4 bytes sits the payload.
+ */
+ subcmd = wrq->u.data.flags; //from wpa_supplicant subcmd
+
+ if (!subcmd)
+ subcmd = (int)req->ifr_data; //from iwpriv subcmd
+
+ switch (subcmd) {
+ case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */
+ idata = SUBCMD_DATA(wrq);
+ ret = setrxantenna(priv, idata);
+ break;
+ case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */
+ idata = SUBCMD_DATA(wrq);
+ ret = settxantenna(priv, idata);
+ break;
+ case WLAN_SET_ATIM_WINDOW:
+ adapter->atimwindow = SUBCMD_DATA(wrq);
+ adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50);
+ break;
+ case WLANSETBCNAVG:
+ adapter->bcn_avg_factor = SUBCMD_DATA(wrq);
+ if (adapter->bcn_avg_factor == 0)
+ adapter->bcn_avg_factor =
+ DEFAULT_BCN_AVG_FACTOR;
+ if (adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR)
+ adapter->bcn_avg_factor =
+ DEFAULT_BCN_AVG_FACTOR;
+ break;
+ case WLANSETDATAAVG:
+ adapter->data_avg_factor = SUBCMD_DATA(wrq);
+ if (adapter->data_avg_factor == 0)
+ adapter->data_avg_factor =
+ DEFAULT_DATA_AVG_FACTOR;
+ if (adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR)
+ adapter->data_avg_factor =
+ DEFAULT_DATA_AVG_FACTOR;
+ break;
+ case WLANSETREGION:
+ idata = SUBCMD_DATA(wrq);
+ ret = wlan_set_region(priv, (u16) idata);
+ break;
+
+ case WLAN_SET_LISTEN_INTERVAL:
+ idata = SUBCMD_DATA(wrq);
+ adapter->listeninterval = (u16) idata;
+ break;
+
+ case WLAN_SET_MULTIPLE_DTIM:
+ ret = wlan_set_multiple_dtim_ioctl(priv, req);
+ break;
+
+ case WLANSETAUTHALG:
+ ret = wlan_setauthalg_ioctl(priv, req);
+ break;
+
+ case WLANSET8021XAUTHALG:
+ ret = wlan_set8021xauthalg_ioctl(priv, req);
+ break;
+
+ case WLANSETENCRYPTIONMODE:
+ ret = wlan_setencryptionmode_ioctl(priv, req);
+ break;
+
+ case WLAN_SET_LINKMODE:
+ ret = wlan_set_linkmode_ioctl(priv, req);
+ break;
+
+ case WLAN_SET_RADIOMODE:
+ ret = wlan_set_radiomode_ioctl(priv, req);
+ break;
+
+ case WLAN_SET_DEBUGMODE:
+ ret = wlan_set_debugmode_ioctl(priv, req);
+ break;
+
+ case WLAN_SUBCMD_MESH_SET_TTL:
+ idata = SUBCMD_DATA(wrq);
+ ret = wlan_mesh_set_ttl_ioctl(priv, idata);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ break;
+
+ case WLAN_SETNONE_GETTWELVE_CHAR: /* Get Antenna settings */
+ /*
+ * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
+ * in flags of iwreq structure, otherwise it will be in
+ * mode member of iwreq structure.
+ */
+ switch ((int)wrq->u.data.flags) {
+ case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */
+ ret = wlan_subcmd_getrxantenna_ioctl(priv, req);
+ break;
+
+ case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */
+ ret = wlan_subcmd_gettxantenna_ioctl(priv, req);
+ break;
+
+ case WLAN_GET_TSF:
+ ret = wlan_get_tsf_ioctl(priv, wrq);
+ break;
+ }
+ break;
+
+ case WLAN_SET128CHAR_GET128CHAR:
+ switch ((int)wrq->u.data.flags) {
+
+ case WLANSCAN_MODE:
+ lbs_pr_debug(1, "Scan mode Ioctl\n");
+ ret = wlan_scan_mode_ioctl(priv, wrq);
+ break;
+
+ case WLAN_GET_ADHOC_STATUS:
+ ret = wlan_get_adhoc_status_ioctl(priv, wrq);
+ break;
+ case WLAN_SUBCMD_BT_ADD:
+ ret = wlan_bt_add_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_BT_DEL:
+ ret = wlan_bt_del_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_BT_LIST:
+ ret = wlan_bt_list_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_ADD:
+ ret = wlan_fwt_add_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_DEL:
+ ret = wlan_fwt_del_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_LOOKUP:
+ ret = wlan_fwt_lookup_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_LIST_NEIGHBOR:
+ ret = wlan_fwt_list_neighbor_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_LIST:
+ ret = wlan_fwt_list_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_LIST_ROUTE:
+ ret = wlan_fwt_list_route_ioctl(priv, req);
+ break;
+ }
+ break;
+
+ case WLAN_SETNONE_GETONEINT:
+ switch ((int)req->ifr_data) {
+ case WLANGETBCNAVG:
+ pdata = (int *)wrq->u.name;
+ *pdata = (int)adapter->bcn_avg_factor;
+ break;
+
+ case WLANGETREGION:
+ pdata = (int *)wrq->u.name;
+ *pdata = (int)adapter->regioncode;
+ break;
+
+ case WLAN_GET_LISTEN_INTERVAL:
+ pdata = (int *)wrq->u.name;
+ *pdata = (int)adapter->listeninterval;
+ break;
+
+ case WLAN_GET_LINKMODE:
+ req->ifr_data = (char *)((u32) adapter->linkmode);
+ break;
+
+ case WLAN_GET_RADIOMODE:
+ req->ifr_data = (char *)((u32) adapter->radiomode);
+ break;
+
+ case WLAN_GET_DEBUGMODE:
+ req->ifr_data = (char *)((u32) adapter->debugmode);
+ break;
+
+ case WLAN_GET_MULTIPLE_DTIM:
+ pdata = (int *)wrq->u.name;
+ *pdata = (int)adapter->multipledtim;
+ break;
+ case WLAN_GET_TX_RATE:
+ ret = wlan_get_txrate_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */
+ ret = wlan_fwt_cleanup_ioctl(priv, req);
+ break;
+
+ case WLAN_SUBCMD_FWT_TIME: /* fwt_time */
+ ret = wlan_fwt_time_ioctl(priv, req);
+ break;
+
+ case WLAN_SUBCMD_MESH_GET_TTL:
+ ret = wlan_mesh_get_ttl_ioctl(priv, req);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+
+ }
+
+ break;
+
+ case WLANGETLOG:
+ ret = wlan_do_getlog_ioctl(priv, wrq);
+ break;
+
+ case WLAN_SET_GET_SIXTEEN_INT:
+ switch ((int)wrq->u.data.flags) {
+ case WLAN_TPCCFG:
+ {
+ int data[5];
+ struct cmd_ds_802_11_tpc_cfg cfg;
+ memset(&cfg, 0, sizeof(cfg));
+ if ((wrq->u.data.length > 1)
+ && (wrq->u.data.length != 5))
+ return -1;
+
+ if (wrq->u.data.length == 0) {
+ cfg.action =
+ cpu_to_le16
+ (cmd_act_get);
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer,
+ sizeof(int) * 5)) {
+ lbs_pr_debug(1,
+ "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ cfg.action =
+ cpu_to_le16
+ (cmd_act_set);
+ cfg.enable = data[0];
+ cfg.usesnr = data[1];
+ cfg.P0 = data[2];
+ cfg.P1 = data[3];
+ cfg.P2 = data[4];
+ }
+
+ ret =
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_tpc_cfg,
+ 0,
+ cmd_option_waitforrsp,
+ 0, (void *)&cfg);
+
+ data[0] = cfg.enable;
+ data[1] = cfg.usesnr;
+ data[2] = cfg.P0;
+ data[3] = cfg.P1;
+ data[4] = cfg.P2;
+ if (copy_to_user
+ (wrq->u.data.pointer, data,
+ sizeof(int) * 5)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+
+ wrq->u.data.length = 5;
+ }
+ break;
+
+ case WLAN_POWERCFG:
+ {
+ int data[4];
+ struct cmd_ds_802_11_pwr_cfg cfg;
+ memset(&cfg, 0, sizeof(cfg));
+ if ((wrq->u.data.length > 1)
+ && (wrq->u.data.length != 4))
+ return -1;
+ if (wrq->u.data.length == 0) {
+ cfg.action =
+ cpu_to_le16
+ (cmd_act_get);
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer,
+ sizeof(int) * 4)) {
+ lbs_pr_debug(1,
+ "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ cfg.action =
+ cpu_to_le16
+ (cmd_act_set);
+ cfg.enable = data[0];
+ cfg.PA_P0 = data[1];
+ cfg.PA_P1 = data[2];
+ cfg.PA_P2 = data[3];
+ }
+ ret =
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_pwr_cfg,
+ 0,
+ cmd_option_waitforrsp,
+ 0, (void *)&cfg);
+ data[0] = cfg.enable;
+ data[1] = cfg.PA_P0;
+ data[2] = cfg.PA_P1;
+ data[3] = cfg.PA_P2;
+ if (copy_to_user
+ (wrq->u.data.pointer, data,
+ sizeof(int) * 4)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+
+ wrq->u.data.length = 4;
+ }
+ break;
+ case WLAN_AUTO_FREQ_SET:
+ {
+ int data[3];
+ struct cmd_ds_802_11_afc afc;
+ memset(&afc, 0, sizeof(afc));
+ if (wrq->u.data.length != 3)
+ return -1;
+ if (copy_from_user
+ (data, wrq->u.data.pointer,
+ sizeof(int) * 3)) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+ afc.afc_auto = data[0];
+
+ if (afc.afc_auto != 0) {
+ afc.threshold = data[1];
+ afc.period = data[2];
+ } else {
+ afc.timing_offset = data[1];
+ afc.carrier_offset = data[2];
+ }
+ ret =
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_set_afc,
+ 0,
+ cmd_option_waitforrsp,
+ 0, (void *)&afc);
+ }
+ break;
+ case WLAN_AUTO_FREQ_GET:
+ {
+ int data[3];
+ struct cmd_ds_802_11_afc afc;
+ memset(&afc, 0, sizeof(afc));
+ ret =
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_get_afc,
+ 0,
+ cmd_option_waitforrsp,
+ 0, (void *)&afc);
+ data[0] = afc.afc_auto;
+ data[1] = afc.timing_offset;
+ data[2] = afc.carrier_offset;
+ if (copy_to_user
+ (wrq->u.data.pointer, data,
+ sizeof(int) * 3)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+
+ wrq->u.data.length = 3;
+ }
+ break;
+ case WLAN_SCANPROBES:
+ {
+ int data;
+ if (wrq->u.data.length > 0) {
+ if (copy_from_user
+ (&data, wrq->u.data.pointer,
+ sizeof(int))) {
+ lbs_pr_debug(1,
+ "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ adapter->scanprobes = data;
+ } else {
+ data = adapter->scanprobes;
+ if (copy_to_user
+ (wrq->u.data.pointer, &data,
+ sizeof(int))) {
+ lbs_pr_debug(1,
+ "Copy to user failed\n");
+ return -EFAULT;
+ }
+ }
+ wrq->u.data.length = 1;
+ }
+ break;
+ case WLAN_LED_GPIO_CTRL:
+ {
+ int i;
+ int data[16];
+
+ struct cmd_ds_802_11_led_ctrl ctrl;
+ struct mrvlietypes_ledgpio *gpio =
+ (struct mrvlietypes_ledgpio *) ctrl.data;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ if (wrq->u.data.length > MAX_LEDS * 2)
+ return -ENOTSUPP;
+ if ((wrq->u.data.length % 2) != 0)
+ return -ENOTSUPP;
+ if (wrq->u.data.length == 0) {
+ ctrl.action =
+ cpu_to_le16
+ (cmd_act_get);
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer,
+ sizeof(int) *
+ wrq->u.data.length)) {
+ lbs_pr_debug(1,
+ "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ ctrl.action =
+ cpu_to_le16
+ (cmd_act_set);
+ ctrl.numled = cpu_to_le16(0);
+ gpio->header.type =
+ cpu_to_le16(TLV_TYPE_LED_GPIO);
+ gpio->header.len = wrq->u.data.length;
+ for (i = 0; i < wrq->u.data.length;
+ i += 2) {
+ gpio->ledpin[i / 2].led =
+ data[i];
+ gpio->ledpin[i / 2].pin =
+ data[i + 1];
+ }
+ }
+ ret =
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_led_gpio_ctrl,
+ 0,
+ cmd_option_waitforrsp,
+ 0, (void *)&ctrl);
+ for (i = 0; i < gpio->header.len; i += 2) {
+ data[i] = gpio->ledpin[i / 2].led;
+ data[i + 1] = gpio->ledpin[i / 2].pin;
+ }
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) *
+ gpio->header.len)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+
+ wrq->u.data.length = gpio->header.len;
+ }
+ break;
+ case WLAN_ADAPT_RATESET:
+ ret = wlan_adapt_rateset(priv, wrq);
+ break;
+ case WLAN_INACTIVITY_TIMEOUT:
+ ret = wlan_inactivity_timeout(priv, wrq);
+ break;
+ case WLANSNR:
+ ret = wlan_get_snr(priv, wrq);
+ break;
+ case WLAN_GET_RXINFO:
+ ret = wlan_get_rxinfo(priv, wrq);
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
new file mode 100644
index 000000000000..11682cbe752b
--- /dev/null
+++ b/drivers/net/wireless/libertas/join.c
@@ -0,0 +1,1055 @@
+/**
+ * Functions implementing wlan infrastructure and adhoc join routines,
+ * IOCTL handlers as well as command preperation and response routines
+ * for sending adhoc start, adhoc join, and association commands
+ * to the firmware.
+ */
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "decl.h"
+#include "join.h"
+#include "dev.h"
+
+/**
+ * @brief This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates need to be taken
+ * care, either before or after calling this function
+ *
+ * @param adapter A pointer to wlan_adapter structure
+ * @param rate1 the buffer which keeps input and output
+ * @param rate1_size the size of rate1 buffer
+ * @param rate2 the buffer which keeps rate2
+ * @param rate2_size the size of rate2 buffer.
+ *
+ * @return 0 or -1
+ */
+static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
+ int rate1_size, u8 * rate2, int rate2_size)
+{
+ u8 *ptr = rate1;
+ int ret = 0;
+ u8 tmp[30];
+ int i;
+
+ memset(&tmp, 0, sizeof(tmp));
+ memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
+ memset(rate1, 0, rate1_size);
+
+ /* Mask the top bit of the original values */
+ for (i = 0; tmp[i] && i < sizeof(tmp); i++)
+ tmp[i] &= 0x7F;
+
+ for (i = 0; rate2[i] && i < rate2_size; i++) {
+ /* Check for Card Rate in tmp, excluding the top bit */
+ if (strchr(tmp, rate2[i] & 0x7F)) {
+ /* values match, so copy the Card Rate to rate1 */
+ *rate1++ = rate2[i];
+ }
+ }
+
+ lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
+ lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
+ lbs_dbg_hex("Common rates:", ptr, rate1_size);
+ lbs_pr_debug(1, "Tx datarate is set to 0x%X\n", adapter->datarate);
+
+ if (!adapter->is_datarate_auto) {
+ while (*ptr) {
+ if ((*ptr & 0x7f) == adapter->datarate) {
+ ret = 0;
+ goto done;
+ }
+ ptr++;
+ }
+ lbs_pr_alert( "Previously set fixed data rate %#x isn't "
+ "compatible with the network.\n", adapter->datarate);
+
+ ret = -1;
+ goto done;
+ }
+
+ ret = 0;
+done:
+ return ret;
+}
+
+int libertas_send_deauth(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ if (adapter->inframode == wlan802_11infrastructure &&
+ adapter->connect_status == libertas_connected)
+ ret = libertas_send_deauthentication(priv);
+ else
+ ret = -ENOTSUPP;
+
+ return ret;
+}
+
+int libertas_do_adhocstop_ioctl(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ if (adapter->inframode == wlan802_11ibss &&
+ adapter->connect_status == libertas_connected)
+ ret = libertas_stop_adhoc_network(priv);
+ else
+ ret = -ENOTSUPP;
+
+ return ret;
+}
+
+/**
+ * @brief Associate to a specific BSS discovered in a scan
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param pbssdesc Pointer to the BSS descriptor to associate with.
+ *
+ * @return 0-success, otherwise fail
+ */
+int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret;
+
+ ENTER();
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
+ 0, cmd_option_waitforrsp,
+ 0, pbssdesc->macaddress);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ /* set preamble to firmware */
+ if (adapter->capinfo.shortpreamble && pbssdesc->cap.shortpreamble)
+ adapter->preamble = cmd_type_short_preamble;
+ else
+ adapter->preamble = cmd_type_long_preamble;
+
+ libertas_set_radio_control(priv);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
+ 0, cmd_option_waitforrsp, 0, pbssdesc);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start an Adhoc Network
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param adhocssid The ssid of the Adhoc Network
+ * @return 0--success, -1--fail
+ */
+int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *adhocssid)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ adapter->adhoccreate = 1;
+
+ if (!adapter->capinfo.shortpreamble) {
+ lbs_pr_debug(1, "AdhocStart: Long preamble\n");
+ adapter->preamble = cmd_type_long_preamble;
+ } else {
+ lbs_pr_debug(1, "AdhocStart: Short preamble\n");
+ adapter->preamble = cmd_type_short_preamble;
+ }
+
+ libertas_set_radio_control(priv);
+
+ lbs_pr_debug(1, "Adhoc channel = %d\n", adapter->adhocchannel);
+ lbs_pr_debug(1, "curbssparams.channel = %d\n",
+ adapter->curbssparams.channel);
+ lbs_pr_debug(1, "curbssparams.band = %d\n", adapter->curbssparams.band);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
+ 0, cmd_option_waitforrsp, 0, adhocssid);
+
+ return ret;
+}
+
+/**
+ * @brief Join an adhoc network found in a previous scan
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param pbssdesc Pointer to a BSS descriptor found in a previous scan
+ * to attempt to join
+ *
+ * @return 0--success, -1--fail
+ */
+int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor * pbssdesc)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid =%s\n",
+ adapter->curbssparams.ssid.ssid);
+ lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid_len =%u\n",
+ adapter->curbssparams.ssid.ssidlength);
+ lbs_pr_debug(1, "libertas_join_adhoc_network: ssid =%s\n", pbssdesc->ssid.ssid);
+ lbs_pr_debug(1, "libertas_join_adhoc_network: ssid len =%u\n",
+ pbssdesc->ssid.ssidlength);
+
+ /* check if the requested SSID is already joined */
+ if (adapter->curbssparams.ssid.ssidlength
+ && !libertas_SSID_cmp(&pbssdesc->ssid, &adapter->curbssparams.ssid)
+ && (adapter->curbssparams.bssdescriptor.inframode ==
+ wlan802_11ibss)) {
+
+ lbs_pr_debug(1,
+ "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+ "not attempting to re-join");
+
+ return -1;
+ }
+
+ /*Use shortpreamble only when both creator and card supports
+ short preamble */
+ if (!pbssdesc->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
+ lbs_pr_debug(1, "AdhocJoin: Long preamble\n");
+ adapter->preamble = cmd_type_long_preamble;
+ } else {
+ lbs_pr_debug(1, "AdhocJoin: Short preamble\n");
+ adapter->preamble = cmd_type_short_preamble;
+ }
+
+ libertas_set_radio_control(priv);
+
+ lbs_pr_debug(1, "curbssparams.channel = %d\n",
+ adapter->curbssparams.channel);
+ lbs_pr_debug(1, "curbssparams.band = %c\n", adapter->curbssparams.band);
+
+ adapter->adhoccreate = 0;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
+ 0, cmd_option_waitforrsp,
+ OID_802_11_SSID, pbssdesc);
+
+ return ret;
+}
+
+int libertas_stop_adhoc_network(wlan_private * priv)
+{
+ return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
+ 0, cmd_option_waitforrsp, 0, NULL);
+}
+
+/**
+ * @brief Send Deauthentication Request
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0--success, -1--fail
+ */
+int libertas_send_deauthentication(wlan_private * priv)
+{
+ return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
+ 0, cmd_option_waitforrsp, 0, NULL);
+}
+
+/**
+ * @brief Set Idle Off
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 --success, otherwise fail
+ */
+int libertas_idle_off(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ const u8 zeromac[] = { 0, 0, 0, 0, 0, 0 };
+ int i;
+
+ ENTER();
+
+ if (adapter->connect_status == libertas_disconnected) {
+ if (adapter->inframode == wlan802_11infrastructure) {
+ if (memcmp(adapter->previousbssid, zeromac,
+ sizeof(zeromac)) != 0) {
+
+ lbs_pr_debug(1, "Previous SSID = %s\n",
+ adapter->previousssid.ssid);
+ lbs_pr_debug(1, "Previous BSSID = "
+ "%02x:%02x:%02x:%02x:%02x:%02x:\n",
+ adapter->previousbssid[0],
+ adapter->previousbssid[1],
+ adapter->previousbssid[2],
+ adapter->previousbssid[3],
+ adapter->previousbssid[4],
+ adapter->previousbssid[5]);
+
+ i = libertas_find_SSID_in_list(adapter,
+ &adapter->previousssid,
+ adapter->previousbssid,
+ adapter->inframode);
+
+ if (i < 0) {
+ libertas_send_specific_BSSID_scan(priv,
+ adapter->
+ previousbssid,
+ 1);
+ i = libertas_find_SSID_in_list(adapter,
+ &adapter->
+ previousssid,
+ adapter->
+ previousbssid,
+ adapter->
+ inframode);
+ }
+
+ if (i < 0) {
+ /* If the BSSID could not be found, try just the SSID */
+ i = libertas_find_SSID_in_list(adapter,
+ &adapter->
+ previousssid, NULL,
+ adapter->
+ inframode);
+ }
+
+ if (i < 0) {
+ libertas_send_specific_SSID_scan(priv,
+ &adapter->
+ previousssid,
+ 1);
+ i = libertas_find_SSID_in_list(adapter,
+ &adapter->
+ previousssid, NULL,
+ adapter->
+ inframode);
+ }
+
+ if (i >= 0) {
+ ret =
+ wlan_associate(priv,
+ &adapter->
+ scantable[i]);
+ }
+ }
+ } else if (adapter->inframode == wlan802_11ibss) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_ad_hoc_start,
+ 0,
+ cmd_option_waitforrsp,
+ 0, &adapter->previousssid);
+ }
+ }
+ /* else it is connected */
+
+ lbs_pr_debug(1, "\nwlanidle is off");
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Idle On
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 --success, otherwise fail
+ */
+int libertas_idle_on(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ if (adapter->connect_status == libertas_connected) {
+ if (adapter->inframode == wlan802_11infrastructure) {
+ lbs_pr_debug(1, "Previous SSID = %s\n",
+ adapter->previousssid.ssid);
+ memmove(&adapter->previousssid,
+ &adapter->curbssparams.ssid,
+ sizeof(struct WLAN_802_11_SSID));
+ libertas_send_deauth(priv);
+
+ } else if (adapter->inframode == wlan802_11ibss) {
+ ret = libertas_stop_adhoc_network(priv);
+ }
+
+ }
+
+ lbs_pr_debug(1, "\nwlanidle is on");
+
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of authenticate.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param cmd A pointer to cmd_ds_command structure
+ * @param pdata_buf Void cast of pointer to a BSSID to authenticate with
+ *
+ * @return 0 or -1
+ */
+int libertas_cmd_80211_authenticate(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_authenticate *pauthenticate =
+ &cmd->params.auth;
+ u8 *bssid = pdata_buf;
+
+ cmd->command = cpu_to_le16(cmd_802_11_authenticate);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
+ + S_DS_GEN);
+
+ pauthenticate->authtype = adapter->secinfo.authmode;
+ memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
+
+ lbs_pr_debug(1, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n",
+ bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
+
+ return 0;
+}
+
+int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
+ S_DS_GEN);
+
+ /* set AP MAC address */
+ memmove(dauth->macaddr, adapter->curbssparams.bssid,
+ ETH_ALEN);
+
+ /* Reason code 3 = Station is leaving */
+#define REASON_CODE_STA_LEAVING 3
+ dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
+
+ LEAVE();
+ return 0;
+}
+
+int libertas_cmd_80211_associate(wlan_private * priv,
+ struct cmd_ds_command *cmd, void *pdata_buf)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
+ int ret = 0;
+ struct bss_descriptor *pbssdesc;
+ u8 *card_rates;
+ u8 *pos;
+ int card_rates_size;
+ u16 tmpcap;
+ struct mrvlietypes_ssidparamset *ssid;
+ struct mrvlietypes_phyparamset *phy;
+ struct mrvlietypes_ssparamset *ss;
+ struct mrvlietypes_ratesparamset *rates;
+ struct mrvlietypes_rsnparamset *rsn;
+
+ ENTER();
+
+ pbssdesc = pdata_buf;
+ pos = (u8 *) passo;
+
+ if (!adapter) {
+ ret = -1;
+ goto done;
+ }
+
+ cmd->command = cpu_to_le16(cmd_802_11_associate);
+
+ /* Save so we know which BSS Desc to use in the response handler */
+ adapter->pattemptedbssdesc = pbssdesc;
+
+ memcpy(passo->peerstaaddr,
+ pbssdesc->macaddress, sizeof(passo->peerstaaddr));
+ pos += sizeof(passo->peerstaaddr);
+
+ /* set the listen interval */
+ passo->listeninterval = adapter->listeninterval;
+
+ pos += sizeof(passo->capinfo);
+ pos += sizeof(passo->listeninterval);
+ pos += sizeof(passo->bcnperiod);
+ pos += sizeof(passo->dtimperiod);
+
+ ssid = (struct mrvlietypes_ssidparamset *) pos;
+ ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
+ ssid->header.len = pbssdesc->ssid.ssidlength;
+ memcpy(ssid->ssid, pbssdesc->ssid.ssid, ssid->header.len);
+ pos += sizeof(ssid->header) + ssid->header.len;
+ ssid->header.len = cpu_to_le16(ssid->header.len);
+
+ phy = (struct mrvlietypes_phyparamset *) pos;
+ phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
+ phy->header.len = sizeof(phy->fh_ds.dsparamset);
+ memcpy(&phy->fh_ds.dsparamset,
+ &pbssdesc->phyparamset.dsparamset.currentchan,
+ sizeof(phy->fh_ds.dsparamset));
+ pos += sizeof(phy->header) + phy->header.len;
+ phy->header.len = cpu_to_le16(phy->header.len);
+
+ ss = (struct mrvlietypes_ssparamset *) pos;
+ ss->header.type = cpu_to_le16(TLV_TYPE_CF);
+ ss->header.len = sizeof(ss->cf_ibss.cfparamset);
+ pos += sizeof(ss->header) + ss->header.len;
+ ss->header.len = cpu_to_le16(ss->header.len);
+
+ rates = (struct mrvlietypes_ratesparamset *) pos;
+ rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
+
+ memcpy(&rates->rates, &pbssdesc->libertas_supported_rates, WLAN_SUPPORTED_RATES);
+
+ card_rates = libertas_supported_rates;
+ card_rates_size = sizeof(libertas_supported_rates);
+
+ if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
+ card_rates, card_rates_size)) {
+ ret = -1;
+ goto done;
+ }
+
+ rates->header.len = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
+ adapter->curbssparams.numofrates = rates->header.len;
+
+ pos += sizeof(rates->header) + rates->header.len;
+ rates->header.len = cpu_to_le16(rates->header.len);
+
+ if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+ rsn = (struct mrvlietypes_rsnparamset *) pos;
+ rsn->header.type = (u16) adapter->wpa_ie[0]; /* WPA_IE or WPA2_IE */
+ rsn->header.type = cpu_to_le16(rsn->header.type);
+ rsn->header.len = (u16) adapter->wpa_ie[1];
+ memcpy(rsn->rsnie, &adapter->wpa_ie[2], rsn->header.len);
+ lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
+ sizeof(rsn->header) + rsn->header.len);
+ pos += sizeof(rsn->header) + rsn->header.len;
+ rsn->header.len = cpu_to_le16(rsn->header.len);
+ }
+
+ /* update curbssparams */
+ adapter->curbssparams.channel =
+ (pbssdesc->phyparamset.dsparamset.currentchan);
+
+ /* Copy the infra. association rates into Current BSS state structure */
+ memcpy(&adapter->curbssparams.datarates, &rates->rates,
+ min_t(size_t, sizeof(adapter->curbssparams.datarates), rates->header.len));
+
+ lbs_pr_debug(1, "ASSOC_CMD: rates->header.len = %d\n", rates->header.len);
+
+ /* set IBSS field */
+ if (pbssdesc->inframode == wlan802_11infrastructure) {
+#define CAPINFO_ESS_MODE 1
+ passo->capinfo.ess = CAPINFO_ESS_MODE;
+ }
+
+ if (libertas_parse_dnld_countryinfo_11d(priv)) {
+ ret = -1;
+ goto done;
+ }
+
+ cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
+
+ /* set the capability info at last */
+ memcpy(&tmpcap, &pbssdesc->cap, sizeof(passo->capinfo));
+ tmpcap &= CAPINFO_MASK;
+ lbs_pr_debug(1, "ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+ tmpcap, CAPINFO_MASK);
+ tmpcap = cpu_to_le16(tmpcap);
+ memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+ struct cmd_ds_command *cmd, void *pssid)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
+ int ret = 0;
+ int cmdappendsize = 0;
+ int i;
+ u16 tmpcap;
+ struct bss_descriptor *pbssdesc;
+ struct WLAN_802_11_SSID *ssid = pssid;
+
+ ENTER();
+
+ if (!adapter) {
+ ret = -1;
+ goto done;
+ }
+
+ cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
+
+ pbssdesc = &adapter->curbssparams.bssdescriptor;
+ adapter->pattemptedbssdesc = pbssdesc;
+
+ /*
+ * Fill in the parameters for 2 data structures:
+ * 1. cmd_ds_802_11_ad_hoc_start command
+ * 2. adapter->scantable[i]
+ *
+ * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
+ * probe delay, and cap info.
+ *
+ * Firmware will fill up beacon period, DTIM, Basic rates
+ * and operational rates.
+ */
+
+ memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
+
+ memcpy(adhs->SSID, ssid->ssid, ssid->ssidlength);
+
+ lbs_pr_debug(1, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID);
+
+ memset(pbssdesc->ssid.ssid, 0, IW_ESSID_MAX_SIZE);
+ memcpy(pbssdesc->ssid.ssid, ssid->ssid, ssid->ssidlength);
+
+ pbssdesc->ssid.ssidlength = ssid->ssidlength;
+
+ /* set the BSS type */
+ adhs->bsstype = cmd_bss_type_ibss;
+ pbssdesc->inframode = wlan802_11ibss;
+ adhs->beaconperiod = adapter->beaconperiod;
+
+ /* set Physical param set */
+#define DS_PARA_IE_ID 3
+#define DS_PARA_IE_LEN 1
+
+ adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
+ adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
+
+ WARN_ON(!adapter->adhocchannel);
+
+ lbs_pr_debug(1, "ADHOC_S_CMD: Creating ADHOC on channel %d\n",
+ adapter->adhocchannel);
+
+ adapter->curbssparams.channel = adapter->adhocchannel;
+
+ pbssdesc->channel = adapter->adhocchannel;
+ adhs->phyparamset.dsparamset.currentchan = adapter->adhocchannel;
+
+ memcpy(&pbssdesc->phyparamset,
+ &adhs->phyparamset, sizeof(union ieeetypes_phyparamset));
+
+ /* set IBSS param set */
+#define IBSS_PARA_IE_ID 6
+#define IBSS_PARA_IE_LEN 2
+
+ adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
+ adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
+ adhs->ssparamset.ibssparamset.atimwindow = adapter->atimwindow;
+ memcpy(&pbssdesc->ssparamset,
+ &adhs->ssparamset, sizeof(union IEEEtypes_ssparamset));
+
+ /* set capability info */
+ adhs->cap.ess = 0;
+ adhs->cap.ibss = 1;
+ pbssdesc->cap.ibss = 1;
+
+ /* probedelay */
+ adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
+
+ /* set up privacy in adapter->scantable[i] */
+ if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
+
+#define AD_HOC_CAP_PRIVACY_ON 1
+ lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus set, privacy to WEP\n");
+ pbssdesc->privacy = wlan802_11privfilter8021xWEP;
+ adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ } else {
+ lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus NOT set, Setting "
+ "privacy to ACCEPT ALL\n");
+ pbssdesc->privacy = wlan802_11privfilteracceptall;
+ }
+
+ memset(adhs->datarate, 0, sizeof(adhs->datarate));
+
+ if (adapter->adhoc_grate_enabled) {
+ memcpy(adhs->datarate, libertas_adhoc_rates_g,
+ min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
+ } else {
+ memcpy(adhs->datarate, libertas_adhoc_rates_b,
+ min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
+ }
+
+ /* Find the last non zero */
+ for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
+
+ adapter->curbssparams.numofrates = i;
+
+ /* Copy the ad-hoc creating rates into Current BSS state structure */
+ memcpy(&adapter->curbssparams.datarates,
+ &adhs->datarate, adapter->curbssparams.numofrates);
+
+ lbs_pr_debug(1, "ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
+ adhs->datarate[0], adhs->datarate[1],
+ adhs->datarate[2], adhs->datarate[3]);
+
+ lbs_pr_debug(1, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+ if (libertas_create_dnld_countryinfo_11d(priv)) {
+ lbs_pr_debug(1, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+ ret = -1;
+ goto done;
+ }
+
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start)
+ + S_DS_GEN + cmdappendsize);
+
+ memcpy(&tmpcap, &adhs->cap, sizeof(u16));
+ tmpcap = cpu_to_le16(tmpcap);
+ memcpy(&adhs->cap, &tmpcap, sizeof(u16));
+
+ ret = 0;
+done:
+ LEAVE();
+ return ret;
+}
+
+int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
+ cmd->size = cpu_to_le16(S_DS_GEN);
+
+ return 0;
+}
+
+int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+ struct cmd_ds_command *cmd, void *pdata_buf)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
+ struct bss_descriptor *pbssdesc = pdata_buf;
+ int cmdappendsize = 0;
+ int ret = 0;
+ u8 *card_rates;
+ int card_rates_size;
+ u16 tmpcap;
+ int i;
+
+ ENTER();
+
+ adapter->pattemptedbssdesc = pbssdesc;
+
+ cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
+
+ padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
+
+ padhocjoin->bssdescriptor.beaconperiod = pbssdesc->beaconperiod;
+
+ memcpy(&padhocjoin->bssdescriptor.BSSID,
+ &pbssdesc->macaddress, ETH_ALEN);
+
+ memcpy(&padhocjoin->bssdescriptor.SSID,
+ &pbssdesc->ssid.ssid, pbssdesc->ssid.ssidlength);
+
+ memcpy(&padhocjoin->bssdescriptor.phyparamset,
+ &pbssdesc->phyparamset, sizeof(union ieeetypes_phyparamset));
+
+ memcpy(&padhocjoin->bssdescriptor.ssparamset,
+ &pbssdesc->ssparamset, sizeof(union IEEEtypes_ssparamset));
+
+ memcpy(&tmpcap, &pbssdesc->cap, sizeof(struct ieeetypes_capinfo));
+ tmpcap &= CAPINFO_MASK;
+
+ lbs_pr_debug(1, "ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+ tmpcap, CAPINFO_MASK);
+ memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
+ sizeof(struct ieeetypes_capinfo));
+
+ /* information on BSSID descriptor passed to FW */
+ lbs_pr_debug(1,
+ "ADHOC_J_CMD: BSSID = %2x-%2x-%2x-%2x-%2x-%2x, SSID = %s\n",
+ padhocjoin->bssdescriptor.BSSID[0],
+ padhocjoin->bssdescriptor.BSSID[1],
+ padhocjoin->bssdescriptor.BSSID[2],
+ padhocjoin->bssdescriptor.BSSID[3],
+ padhocjoin->bssdescriptor.BSSID[4],
+ padhocjoin->bssdescriptor.BSSID[5],
+ padhocjoin->bssdescriptor.SSID);
+
+ lbs_pr_debug(1, "ADHOC_J_CMD: Data Rate = %x\n",
+ (u32) padhocjoin->bssdescriptor.datarates);
+
+ /* failtimeout */
+ padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+
+ /* probedelay */
+ padhocjoin->probedelay =
+ cpu_to_le16(cmd_scan_probe_delay_time);
+
+ /* Copy Data rates from the rates recorded in scan response */
+ memset(padhocjoin->bssdescriptor.datarates, 0,
+ sizeof(padhocjoin->bssdescriptor.datarates));
+ memcpy(padhocjoin->bssdescriptor.datarates, pbssdesc->datarates,
+ min(sizeof(padhocjoin->bssdescriptor.datarates),
+ sizeof(pbssdesc->datarates)));
+
+ card_rates = libertas_supported_rates;
+ card_rates_size = sizeof(libertas_supported_rates);
+
+ adapter->curbssparams.channel = pbssdesc->channel;
+
+ if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
+ sizeof(padhocjoin->bssdescriptor.datarates),
+ card_rates, card_rates_size)) {
+ lbs_pr_debug(1, "ADHOC_J_CMD: get_common_rates returns error.\n");
+ ret = -1;
+ goto done;
+ }
+
+ /* Find the last non zero */
+ for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
+ && padhocjoin->bssdescriptor.datarates[i]; i++) ;
+
+ adapter->curbssparams.numofrates = i;
+
+ /*
+ * Copy the adhoc joining rates to Current BSS State structure
+ */
+ memcpy(adapter->curbssparams.datarates,
+ padhocjoin->bssdescriptor.datarates,
+ adapter->curbssparams.numofrates);
+
+ padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
+ cpu_to_le16(pbssdesc->atimwindow);
+
+ if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
+ padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ }
+
+ if (adapter->psmode == wlan802_11powermodemax_psp) {
+ /* wake up first */
+ enum WLAN_802_11_POWER_MODE Localpsmode;
+
+ Localpsmode = wlan802_11powermodecam;
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_ps_mode,
+ cmd_act_set,
+ 0, 0, &Localpsmode);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+ }
+
+ if (libertas_parse_dnld_countryinfo_11d(priv)) {
+ ret = -1;
+ goto done;
+ }
+
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join)
+ + S_DS_GEN + cmdappendsize);
+
+ memcpy(&tmpcap, &padhocjoin->bssdescriptor.cap,
+ sizeof(struct ieeetypes_capinfo));
+ tmpcap = cpu_to_le16(tmpcap);
+
+ memcpy(&padhocjoin->bssdescriptor.cap,
+ &tmpcap, sizeof(struct ieeetypes_capinfo));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+int libertas_ret_80211_associate(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ union iwreq_data wrqu;
+ struct ieeetypes_assocrsp *passocrsp;
+ struct bss_descriptor *pbssdesc;
+
+ ENTER();
+
+ passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
+
+ if (passocrsp->statuscode) {
+
+ libertas_mac_event_disconnected(priv);
+
+ lbs_pr_debug(1,
+ "ASSOC_RESP: Association failed, status code = %d\n",
+ passocrsp->statuscode);
+
+ ret = -1;
+ goto done;
+ }
+
+ lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
+ le16_to_cpu(resp->size) - S_DS_GEN);
+
+ /* Send a Media Connected event, according to the Spec */
+ adapter->connect_status = libertas_connected;
+
+ /* Set the attempted BSSID Index to current */
+ pbssdesc = adapter->pattemptedbssdesc;
+
+ lbs_pr_debug(1, "ASSOC_RESP: %s\n", pbssdesc->ssid.ssid);
+
+ /* Set the new SSID to current SSID */
+ memcpy(&adapter->curbssparams.ssid,
+ &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
+
+ /* Set the new BSSID (AP's MAC address) to current BSSID */
+ memcpy(adapter->curbssparams.bssid,
+ pbssdesc->macaddress, ETH_ALEN);
+
+ /* Make a copy of current BSSID descriptor */
+ memcpy(&adapter->curbssparams.bssdescriptor,
+ pbssdesc, sizeof(struct bss_descriptor));
+
+ lbs_pr_debug(1, "ASSOC_RESP: currentpacketfilter is %x\n",
+ adapter->currentpacketfilter);
+
+ adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
+ adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
+
+ memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
+ memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
+ adapter->nextSNRNF = 0;
+ adapter->numSNRNF = 0;
+
+ netif_carrier_on(priv->wlan_dev.netdev);
+ netif_wake_queue(priv->wlan_dev.netdev);
+
+ lbs_pr_debug(1, "ASSOC_RESP: Associated \n");
+
+ memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+int libertas_ret_80211_disassociate(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ ENTER();
+
+ libertas_mac_event_disconnected(priv);
+
+ LEAVE();
+ return 0;
+}
+
+int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ u16 command = le16_to_cpu(resp->command);
+ u16 result = le16_to_cpu(resp->result);
+ struct cmd_ds_802_11_ad_hoc_result *padhocresult;
+ union iwreq_data wrqu;
+ struct bss_descriptor *pbssdesc;
+
+ ENTER();
+
+ padhocresult = &resp->params.result;
+
+ lbs_pr_debug(1, "ADHOC_S_RESP: size = %d\n", le16_to_cpu(resp->size));
+ lbs_pr_debug(1, "ADHOC_S_RESP: command = %x\n", command);
+ lbs_pr_debug(1, "ADHOC_S_RESP: result = %x\n", result);
+
+ pbssdesc = adapter->pattemptedbssdesc;
+
+ /*
+ * Join result code 0 --> SUCCESS
+ */
+ if (result) {
+ lbs_pr_debug(1, "ADHOC_RESP failed\n");
+ if (adapter->connect_status == libertas_connected) {
+ libertas_mac_event_disconnected(priv);
+ }
+
+ memset(&adapter->curbssparams.bssdescriptor,
+ 0x00, sizeof(adapter->curbssparams.bssdescriptor));
+
+ LEAVE();
+ return -1;
+ }
+
+ /*
+ * Now the join cmd should be successful
+ * If BSSID has changed use SSID to compare instead of BSSID
+ */
+ lbs_pr_debug(1, "ADHOC_J_RESP %s\n", pbssdesc->ssid.ssid);
+
+ /* Send a Media Connected event, according to the Spec */
+ adapter->connect_status = libertas_connected;
+
+ if (command == cmd_ret_802_11_ad_hoc_start) {
+ /* Update the created network descriptor with the new BSSID */
+ memcpy(pbssdesc->macaddress,
+ padhocresult->BSSID, ETH_ALEN);
+ } else {
+
+ /* Make a copy of current BSSID descriptor, only needed for join since
+ * the current descriptor is already being used for adhoc start
+ */
+ memmove(&adapter->curbssparams.bssdescriptor,
+ pbssdesc, sizeof(struct bss_descriptor));
+ }
+
+ /* Set the BSSID from the joined/started descriptor */
+ memcpy(&adapter->curbssparams.bssid,
+ pbssdesc->macaddress, ETH_ALEN);
+
+ /* Set the new SSID to current SSID */
+ memcpy(&adapter->curbssparams.ssid,
+ &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
+
+ netif_carrier_on(priv->wlan_dev.netdev);
+ netif_wake_queue(priv->wlan_dev.netdev);
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+ lbs_pr_debug(1, "ADHOC_RESP: - Joined/Started Ad Hoc\n");
+ lbs_pr_debug(1, "ADHOC_RESP: channel = %d\n", adapter->adhocchannel);
+ lbs_pr_debug(1, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ padhocresult->BSSID[0], padhocresult->BSSID[1],
+ padhocresult->BSSID[2], padhocresult->BSSID[3],
+ padhocresult->BSSID[4], padhocresult->BSSID[5]);
+
+ LEAVE();
+ return ret;
+}
+
+int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ ENTER();
+
+ libertas_mac_event_disconnected(priv);
+
+ LEAVE();
+ return 0;
+}
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
new file mode 100644
index 000000000000..8efa2455af9a
--- /dev/null
+++ b/drivers/net/wireless/libertas/join.h
@@ -0,0 +1,64 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+ * Interface for the wlan infrastructure and adhoc join routines
+ *
+ * Driver interface functions and type declarations for the join module
+ * implemented in wlan_join.c. Process all start/join requests for
+ * both adhoc and infrastructure networks
+ */
+#ifndef _WLAN_JOIN_H
+#define _WLAN_JOIN_H
+
+#include "defs.h"
+
+struct cmd_ds_command;
+extern int libertas_cmd_80211_authenticate(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+ struct cmd_ds_command *cmd);
+extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pssid);
+extern int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+ struct cmd_ds_command *cmd);
+extern int libertas_cmd_80211_associate(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+
+extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+ struct cmd_ds_command *resp);
+extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+ struct cmd_ds_command *resp);
+extern int libertas_ret_80211_disassociate(wlan_private * priv,
+ struct cmd_ds_command *resp);
+extern int libertas_ret_80211_associate(wlan_private * priv,
+ struct cmd_ds_command *resp);
+
+extern int libertas_idle_on(wlan_private * priv);
+extern int libertas_idle_off(wlan_private * priv);
+
+extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+extern int libertas_reassociation_thread(void *data);
+
+struct WLAN_802_11_SSID;
+struct bss_descriptor;
+
+extern int libertas_start_adhoc_network(wlan_private * priv,
+ struct WLAN_802_11_SSID *adhocssid);
+extern int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor *pbssdesc);
+extern int libertas_stop_adhoc_network(wlan_private * priv);
+
+extern int libertas_send_deauthentication(wlan_private * priv);
+extern int libertas_send_deauth(wlan_private * priv);
+
+extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+
+int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc);
+
+#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
new file mode 100644
index 000000000000..dcbf102a057e
--- /dev/null
+++ b/drivers/net/wireless/libertas/main.c
@@ -0,0 +1,1258 @@
+/**
+ * This file contains the major functions in WLAN
+ * driver. It includes init, exit, open, close and main
+ * thread etc..
+ */
+
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "dev.h"
+#include "fw.h"
+#include "wext.h"
+#include "debugfs.h"
+#include "assoc.h"
+
+#ifdef ENABLE_PM
+static struct pm_dev *wlan_pm_dev = NULL;
+#endif
+
+#define WLAN_TX_PWR_DEFAULT 20 /*100mW */
+#define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */
+#define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */
+#define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */
+#define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */
+
+/* Format { channel, frequency (MHz), maxtxpower } */
+/* band: 'B/G', region: USA FCC/Canada IC */
+static struct chan_freq_power channel_freq_power_US_BG[] = {
+ {1, 2412, WLAN_TX_PWR_US_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_US_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_US_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_US_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_US_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_US_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_US_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_US_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_US_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_US_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_US_DEFAULT}
+};
+
+/* band: 'B/G', region: Europe ETSI */
+static struct chan_freq_power channel_freq_power_EU_BG[] = {
+ {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
+};
+
+/* band: 'B/G', region: Spain */
+static struct chan_freq_power channel_freq_power_SPN_BG[] = {
+ {10, 2457, WLAN_TX_PWR_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_DEFAULT}
+};
+
+/* band: 'B/G', region: France */
+static struct chan_freq_power channel_freq_power_FR_BG[] = {
+ {10, 2457, WLAN_TX_PWR_FR_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_FR_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_FR_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_FR_DEFAULT}
+};
+
+/* band: 'B/G', region: Japan */
+static struct chan_freq_power channel_freq_power_JPN_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_JP_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_JP_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_JP_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_JP_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_JP_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_JP_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_JP_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_JP_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_JP_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_JP_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_JP_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_JP_DEFAULT},
+ {14, 2484, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/**
+ * the structure for channel, frequency and power
+ */
+struct region_cfp_table {
+ u8 region;
+ struct chan_freq_power *cfp_BG;
+ int cfp_no_BG;
+};
+
+/**
+ * the structure for the mapping between region and CFP
+ */
+static struct region_cfp_table region_cfp_table[] = {
+ {0x10, /*US FCC */
+ channel_freq_power_US_BG,
+ sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+ {0x20, /*CANADA IC */
+ channel_freq_power_US_BG,
+ sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+ {0x30, /*EU*/ channel_freq_power_EU_BG,
+ sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+ {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
+ sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+ {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
+ sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+ {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
+ sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+/*Add new region here */
+};
+
+/**
+ * the rates supported by the card
+ */
+u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
+ { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
+
+/**
+ * the rates supported
+ */
+u8 libertas_supported_rates[G_SUPPORTED_RATES] =
+ { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0 };
+
+/**
+ * the rates supported for ad-hoc G mode
+ */
+u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] =
+ { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0 };
+
+/**
+ * the rates supported for ad-hoc B mode
+ */
+u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 };
+
+/**
+ * the global variable of a pointer to wlan_private
+ * structure variable
+ */
+static wlan_private *wlanpriv = NULL;
+
+#define MAX_DEVS 5
+static struct net_device *libertas_devs[MAX_DEVS];
+static int libertas_found = 0;
+
+/**
+ * the table to keep region code
+ */
+u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+ { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
+
+static u8 *default_fw_name = "usb8388.bin";
+
+/**
+ * Attributes exported through sysfs
+ */
+
+/**
+ * @brief Get function for sysfs attribute libertas_mpp
+ */
+static ssize_t libertas_mpp_get(struct device * dev,
+ struct device_attribute *attr, char * buf) {
+ struct cmd_ds_mesh_access mesh_access;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ libertas_prepare_and_send_command(to_net_dev(dev)->priv,
+ cmd_mesh_access,
+ cmd_act_mesh_get_mpp,
+ cmd_option_waitforrsp, 0, (void *)&mesh_access);
+
+ return snprintf(buf, 3, "%d\n", mesh_access.data[0]);
+}
+
+/**
+ * @brief Set function for sysfs attribute libertas_mpp
+ */
+static ssize_t libertas_mpp_set(struct device * dev,
+ struct device_attribute *attr, const char * buf, size_t count) {
+ struct cmd_ds_mesh_access mesh_access;
+
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ sscanf(buf, "%d", &(mesh_access.data[0]));
+ libertas_prepare_and_send_command((to_net_dev(dev))->priv,
+ cmd_mesh_access,
+ cmd_act_mesh_set_mpp,
+ cmd_option_waitforrsp, 0, (void *)&mesh_access);
+ return strlen(buf);
+}
+
+/**
+ * libertas_mpp attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/libertas-mpp)
+ */
+static DEVICE_ATTR(libertas_mpp, 0644, libertas_mpp_get,
+ libertas_mpp_set );
+
+/**
+ * @brief Check if the device can be open and wait if necessary.
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ *
+ * For USB adapter, on some systems the device open handler will be
+ * called before FW ready. Use the following flag check and wait
+ * function to work around the issue.
+ *
+ */
+static int pre_open_check(struct net_device *dev) {
+ wlan_private *priv = (wlan_private *) dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int i = 0;
+
+ while (!adapter->fw_ready && i < 20) {
+ i++;
+ msleep_interruptible(100);
+ }
+ if (!adapter->fw_ready) {
+ lbs_pr_info("FW not ready, pre_open_check() return failure\n");
+ LEAVE();
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief This function opens the device
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int wlan_dev_open(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+
+ priv->open = 1;
+
+ if (adapter->connect_status == libertas_connected) {
+ netif_carrier_on(priv->wlan_dev.netdev);
+ } else
+ netif_carrier_off(priv->wlan_dev.netdev);
+
+ LEAVE();
+ return 0;
+}
+/**
+ * @brief This function opens the mshX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int mesh_open(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) dev->priv ;
+
+ if(pre_open_check(dev) == -1)
+ return -1;
+ priv->mesh_open = 1 ;
+ netif_start_queue(priv->mesh_dev);
+ if (priv->infra_open == 0)
+ return wlan_dev_open(priv->wlan_dev.netdev) ;
+ return 0;
+}
+
+/**
+ * @brief This function opens the ethX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int wlan_open(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) dev->priv ;
+
+ if(pre_open_check(dev) == -1)
+ return -1;
+ priv->infra_open = 1 ;
+ netif_wake_queue(priv->wlan_dev.netdev);
+ if (priv->open == 0)
+ return wlan_dev_open(priv->wlan_dev.netdev) ;
+ return 0;
+}
+
+static int wlan_dev_close(struct net_device *dev)
+{
+ wlan_private *priv = dev->priv;
+
+ ENTER();
+
+ netif_carrier_off(priv->wlan_dev.netdev);
+ priv->open = 0;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function closes the mshX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int mesh_close(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) (dev->priv);
+
+ priv->mesh_open = 0;
+ netif_stop_queue(priv->mesh_dev);
+ if (priv->infra_open == 0)
+ return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
+ else
+ return 0;
+}
+
+/**
+ * @brief This function closes the ethX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int wlan_close(struct net_device *dev) {
+ wlan_private *priv = (wlan_private *) dev->priv;
+
+ netif_stop_queue(priv->wlan_dev.netdev);
+ priv->infra_open = 0;
+ if (priv->mesh_open == 0)
+ return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
+ else
+ return 0;
+}
+
+
+#ifdef ENABLE_PM
+
+/**
+ * @brief This function is a callback function. it is called by
+ * kernel to enter or exit power saving mode.
+ *
+ * @param pmdev A pointer to pm_dev
+ * @param pmreq pm_request_t
+ * @param pmdata A pointer to pmdata
+ * @return 0 or -1
+ */
+static int wlan_pm_callback(struct pm_dev *pmdev, pm_request_t pmreq,
+ void *pmdata)
+{
+ wlan_private *priv = wlanpriv;
+ wlan_adapter *adapter = priv->adapter;
+ struct net_device *dev = priv->wlan_dev.netdev;
+
+ lbs_pr_debug(1, "WPRM_PM_CALLBACK: pmreq = %d.\n", pmreq);
+
+ switch (pmreq) {
+ case PM_SUSPEND:
+ lbs_pr_debug(1, "WPRM_PM_CALLBACK: enter PM_SUSPEND.\n");
+
+ /* in associated mode */
+ if (adapter->connect_status == libertas_connected) {
+ if ((adapter->psstate != PS_STATE_SLEEP)
+ ) {
+ lbs_pr_debug(1,
+ "wlan_pm_callback: can't enter sleep mode\n");
+ return -1;
+ } else {
+
+ /*
+ * Detach the network interface
+ * if the network is running
+ */
+ if (netif_running(dev)) {
+ netif_device_detach(dev);
+ lbs_pr_debug(1,
+ "netif_device_detach().\n");
+ }
+ libertas_sbi_suspend(priv);
+ }
+ break;
+ }
+
+ /* in non associated mode */
+
+ /*
+ * Detach the network interface
+ * if the network is running
+ */
+ if (netif_running(dev))
+ netif_device_detach(dev);
+
+ /*
+ * Storing and restoring of the regs be taken care
+ * at the driver rest will be done at wlan driver
+ * this makes driver independent of the card
+ */
+
+ libertas_sbi_suspend(priv);
+
+ break;
+
+ case PM_RESUME:
+ /* in associated mode */
+ if (adapter->connect_status == libertas_connected) {
+ {
+ /*
+ * Bring the inteface up first
+ * This case should not happen still ...
+ */
+ libertas_sbi_resume(priv);
+
+ /*
+ * Attach the network interface
+ * if the network is running
+ */
+ if (netif_running(dev)) {
+ netif_device_attach(dev);
+ lbs_pr_debug(1,
+ "after netif_device_attach().\n");
+ }
+ lbs_pr_debug(1,
+ "After netif attach, in associated mode.\n");
+ }
+ break;
+ }
+
+ /* in non associated mode */
+
+ /*
+ * Bring the inteface up first
+ * This case should not happen still ...
+ */
+
+ libertas_sbi_resume(priv);
+
+ if (netif_running(dev))
+ netif_device_attach(dev);
+
+ lbs_pr_debug(1, "after netif attach, in NON associated mode.\n");
+ break;
+ }
+
+ return 0;
+}
+#endif /* ENABLE_PM */
+
+static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+
+ ENTER();
+
+ if (priv->wlan_dev.dnld_sent || priv->adapter->TxLockFlag) {
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+
+ netif_stop_queue(priv->wlan_dev.netdev);
+
+ if (libertas_process_tx(priv, skb) == 0)
+ dev->trans_start = jiffies;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Mark mesh packets and handover them to wlan_hard_start_xmit
+ *
+ */
+static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ wlan_private *priv = dev->priv;
+ ENTER();
+ SET_MESH_FRAME(skb);
+ LEAVE();
+
+ return wlan_hard_start_xmit(skb, priv->wlan_dev.netdev);
+}
+
+/**
+ * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
+ *
+ */
+static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+ ENTER();
+ UNSET_MESH_FRAME(skb);
+ LEAVE();
+ return wlan_hard_start_xmit(skb, dev);
+}
+
+static void wlan_tx_timeout(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) dev->priv;
+
+ ENTER();
+
+ lbs_pr_err("tx watch dog timeout!\n");
+
+ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+ dev->trans_start = jiffies;
+
+ if (priv->adapter->currenttxskb) {
+ if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+ /* If we are here, we have not received feedback from
+ the previous packet. Assume TX_FAIL and move on. */
+ priv->adapter->eventcause = 0x01000000;
+ libertas_send_tx_feedback(priv);
+ } else
+ wake_up_interruptible(&priv->mainthread.waitq);
+ } else if (priv->adapter->connect_status == libertas_connected)
+ netif_wake_queue(priv->wlan_dev.netdev);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function returns the network statistics
+ *
+ * @param dev A pointer to wlan_private structure
+ * @return A pointer to net_device_stats structure
+ */
+static struct net_device_stats *wlan_get_stats(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) dev->priv;
+
+ return &priv->stats;
+}
+
+static int wlan_set_mac_address(struct net_device *dev, void *addr)
+{
+ int ret = 0;
+ wlan_private *priv = (wlan_private *) dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct sockaddr *phwaddr = addr;
+
+ ENTER();
+
+ memset(adapter->current_addr, 0, ETH_ALEN);
+
+ /* dev->dev_addr is 8 bytes */
+ lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+ lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+ memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ lbs_pr_debug(1, "set mac address failed.\n");
+ ret = -1;
+ goto done;
+ }
+
+ lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+ memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
+ memcpy(((wlan_private *) dev->priv)->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+static int wlan_copy_multicast_address(wlan_adapter * adapter,
+ struct net_device *dev)
+{
+ int i = 0;
+ struct dev_mc_list *mcptr = dev->mc_list;
+
+ for (i = 0; i < dev->mc_count; i++) {
+ memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
+ mcptr = mcptr->next;
+ }
+
+ return i;
+
+}
+
+static void wlan_set_multicast_list(struct net_device *dev)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int oldpacketfilter;
+
+ ENTER();
+
+ oldpacketfilter = adapter->currentpacketfilter;
+
+ if (dev->flags & IFF_PROMISC) {
+ lbs_pr_debug(1, "enable Promiscuous mode\n");
+ adapter->currentpacketfilter |=
+ cmd_act_mac_promiscuous_enable;
+ adapter->currentpacketfilter &=
+ ~(cmd_act_mac_all_multicast_enable |
+ cmd_act_mac_multicast_enable);
+ } else {
+ /* Multicast */
+ adapter->currentpacketfilter &=
+ ~cmd_act_mac_promiscuous_enable;
+
+ if (dev->flags & IFF_ALLMULTI || dev->mc_count >
+ MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+ lbs_pr_debug(1, "Enabling All Multicast!\n");
+ adapter->currentpacketfilter |=
+ cmd_act_mac_all_multicast_enable;
+ adapter->currentpacketfilter &=
+ ~cmd_act_mac_multicast_enable;
+ } else {
+ adapter->currentpacketfilter &=
+ ~cmd_act_mac_all_multicast_enable;
+
+ if (!dev->mc_count) {
+ lbs_pr_debug(1, "No multicast addresses - "
+ "disabling multicast!\n");
+ adapter->currentpacketfilter &=
+ ~cmd_act_mac_multicast_enable;
+ } else {
+ int i;
+
+ adapter->currentpacketfilter |=
+ cmd_act_mac_multicast_enable;
+
+ adapter->nr_of_multicastmacaddr =
+ wlan_copy_multicast_address(adapter, dev);
+
+ lbs_pr_debug(1, "Multicast addresses: %d\n",
+ dev->mc_count);
+
+ for (i = 0; i < dev->mc_count; i++) {
+ lbs_pr_debug(1, "Multicast address %d:"
+ "%x %x %x %x %x %x\n", i,
+ adapter->multicastlist[i][0],
+ adapter->multicastlist[i][1],
+ adapter->multicastlist[i][2],
+ adapter->multicastlist[i][3],
+ adapter->multicastlist[i][4],
+ adapter->multicastlist[i][5]);
+ }
+ /* set multicast addresses to firmware */
+ libertas_prepare_and_send_command(priv,
+ cmd_mac_multicast_adr,
+ cmd_act_set, 0, 0,
+ NULL);
+ }
+ }
+ }
+
+ if (adapter->currentpacketfilter != oldpacketfilter) {
+ libertas_set_mac_packet_filter(priv);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function hanldes the major job in WLAN driver.
+ * it handles the event generated by firmware, rx data received
+ * from firmware and tx data sent from kernel.
+ *
+ * @param data A pointer to wlan_thread structure
+ * @return 0
+ */
+static int wlan_service_main_thread(void *data)
+{
+ struct wlan_thread *thread = data;
+ wlan_private *priv = thread->priv;
+ wlan_adapter *adapter = priv->adapter;
+ wait_queue_t wait;
+ u8 ireg = 0;
+
+ ENTER();
+
+ wlan_activate_thread(thread);
+
+ init_waitqueue_entry(&wait, current);
+
+ for (;;) {
+ lbs_pr_debug(1, "main-thread 111: intcounter=%d "
+ "currenttxskb=%p dnld_sent=%d\n",
+ adapter->intcounter,
+ adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+ add_wait_queue(&thread->waitq, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irq(&adapter->driver_lock);
+ if ((adapter->psstate == PS_STATE_SLEEP) ||
+ (!adapter->intcounter
+ && (priv->wlan_dev.dnld_sent || adapter->cur_cmd ||
+ list_empty(&adapter->cmdpendingq)))) {
+ lbs_pr_debug(1,
+ "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
+ adapter->connect_status, adapter->intcounter,
+ adapter->psmode, adapter->psstate);
+ spin_unlock_irq(&adapter->driver_lock);
+ schedule();
+ } else
+ spin_unlock_irq(&adapter->driver_lock);
+
+
+ lbs_pr_debug(1,
+ "main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
+ "dnld_sent=%d\n", adapter->intcounter,
+ adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&thread->waitq, &wait);
+ try_to_freeze();
+
+ lbs_pr_debug(1, "main-thread 333: intcounter=%d currenttxskb=%p "
+ "dnld_sent=%d\n",
+ adapter->intcounter,
+ adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+ if (kthread_should_stop()
+ || adapter->surpriseremoved) {
+ lbs_pr_debug(1,
+ "main-thread: break from main thread: surpriseremoved=0x%x\n",
+ adapter->surpriseremoved);
+ break;
+ }
+
+
+ spin_lock_irq(&adapter->driver_lock);
+ if (adapter->intcounter) {
+ u8 int_status;
+ adapter->intcounter = 0;
+ int_status = libertas_sbi_get_int_status(priv, &ireg);
+
+ if (int_status) {
+ lbs_pr_debug(1,
+ "main-thread: reading HOST_INT_STATUS_REG failed\n");
+ spin_unlock_irq(&adapter->driver_lock);
+ continue;
+ }
+ adapter->hisregcpy |= ireg;
+ }
+
+ lbs_pr_debug(1, "main-thread 444: intcounter=%d currenttxskb=%p "
+ "dnld_sent=%d\n",
+ adapter->intcounter,
+ adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+ /* command response? */
+ if (adapter->hisregcpy & his_cmdupldrdy) {
+ lbs_pr_debug(1, "main-thread: cmd response ready.\n");
+
+ adapter->hisregcpy &= ~his_cmdupldrdy;
+ spin_unlock_irq(&adapter->driver_lock);
+ libertas_process_rx_command(priv);
+ spin_lock_irq(&adapter->driver_lock);
+ }
+
+ /* Any Card Event */
+ if (adapter->hisregcpy & his_cardevent) {
+ lbs_pr_debug(1, "main-thread: Card Event Activity.\n");
+
+ adapter->hisregcpy &= ~his_cardevent;
+
+ if (libertas_sbi_read_event_cause(priv)) {
+ lbs_pr_alert(
+ "main-thread: libertas_sbi_read_event_cause failed.\n");
+ spin_unlock_irq(&adapter->driver_lock);
+ continue;
+ }
+ spin_unlock_irq(&adapter->driver_lock);
+ libertas_process_event(priv);
+ } else
+ spin_unlock_irq(&adapter->driver_lock);
+
+ /* Check if we need to confirm Sleep Request received previously */
+ if (adapter->psstate == PS_STATE_PRE_SLEEP) {
+ if (!priv->wlan_dev.dnld_sent && !adapter->cur_cmd) {
+ if (adapter->connect_status ==
+ libertas_connected) {
+ lbs_pr_debug(1,
+ "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
+ "dnld_sent=%d cur_cmd=%p, confirm now\n",
+ adapter->intcounter,
+ adapter->currenttxskb,
+ priv->wlan_dev.dnld_sent,
+ adapter->cur_cmd);
+
+ libertas_ps_confirm_sleep(priv,
+ (u16) adapter->psmode);
+ } else {
+ /* workaround for firmware sending
+ * deauth/linkloss event immediately
+ * after sleep request, remove this
+ * after firmware fixes it
+ */
+ adapter->psstate = PS_STATE_AWAKE;
+ lbs_pr_alert(
+ "main-thread: ignore PS_SleepConfirm in non-connected state\n");
+ }
+ }
+ }
+
+ /* The PS state is changed during processing of Sleep Request
+ * event above
+ */
+ if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
+ (priv->adapter->psstate == PS_STATE_PRE_SLEEP))
+ continue;
+
+ /* Execute the next command */
+ if (!priv->wlan_dev.dnld_sent && !priv->adapter->cur_cmd)
+ libertas_execute_next_command(priv);
+
+ /* Wake-up command waiters which can't sleep in
+ * libertas_prepare_and_send_command
+ */
+ if (!adapter->nr_cmd_pending)
+ wake_up_all(&adapter->cmd_pending);
+
+ libertas_tx_runqueue(priv);
+ }
+
+ del_timer(&adapter->command_timer);
+ adapter->nr_cmd_pending = 0;
+ wake_up_all(&adapter->cmd_pending);
+ wlan_deactivate_thread(thread);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the wlan_priv and initialize the device.
+ *
+ * @param card A pointer to card
+ * @return A pointer to wlan_private structure
+ */
+wlan_private *wlan_add_card(void *card)
+{
+ struct net_device *dev = NULL;
+ struct net_device *mesh_dev = NULL;
+ wlan_private *priv = NULL;
+
+ ENTER();
+
+ /* Allocate an Ethernet device and register it */
+ if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
+ lbs_pr_alert( "Init ethernet device failed!\n");
+ return NULL;
+ }
+
+ priv = dev->priv;
+
+ /* allocate buffer for wlan_adapter */
+ if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
+ lbs_pr_alert( "Allocate buffer for wlan_adapter failed!\n");
+ goto err_kmalloc;
+ }
+
+ /* Allocate a virtual mesh device */
+ if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) {
+ lbs_pr_debug(1, "Init ethernet device failed!\n");
+ return NULL;
+ }
+
+ /* Both intervaces share the priv structure */
+ mesh_dev->priv = priv;
+
+ /* init wlan_adapter */
+ memset(priv->adapter, 0, sizeof(wlan_adapter));
+
+ priv->wlan_dev.netdev = dev;
+ priv->wlan_dev.card = card;
+ priv->mesh_open = 0;
+ priv->infra_open = 0;
+ priv->mesh_dev = mesh_dev;
+ wlanpriv = priv;
+
+ SET_MODULE_OWNER(dev);
+ SET_MODULE_OWNER(mesh_dev);
+
+ /* Setup the OS Interface to our functions */
+ dev->open = wlan_open;
+ dev->hard_start_xmit = wlan_pre_start_xmit;
+ dev->stop = wlan_close;
+ dev->do_ioctl = libertas_do_ioctl;
+ dev->set_mac_address = wlan_set_mac_address;
+ mesh_dev->open = mesh_open;
+ mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
+ mesh_dev->stop = mesh_close;
+ mesh_dev->do_ioctl = libertas_do_ioctl;
+ memcpy(mesh_dev->dev_addr, wlanpriv->wlan_dev.netdev->dev_addr,
+ sizeof(wlanpriv->wlan_dev.netdev->dev_addr));
+
+#define WLAN_WATCHDOG_TIMEOUT (5 * HZ)
+
+ dev->tx_timeout = wlan_tx_timeout;
+ dev->get_stats = wlan_get_stats;
+ dev->watchdog_timeo = WLAN_WATCHDOG_TIMEOUT;
+ dev->ethtool_ops = &libertas_ethtool_ops;
+ mesh_dev->get_stats = wlan_get_stats;
+ mesh_dev->ethtool_ops = &libertas_ethtool_ops;
+
+#ifdef WIRELESS_EXT
+ dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
+ mesh_dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
+#endif
+#define NETIF_F_DYNALLOC 16
+ dev->features |= NETIF_F_DYNALLOC;
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+ dev->set_multicast_list = wlan_set_multicast_list;
+
+ INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
+ INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
+
+ spin_lock_init(&priv->adapter->driver_lock);
+ init_waitqueue_head(&priv->adapter->cmd_pending);
+ priv->adapter->nr_cmd_pending = 0;
+
+ lbs_pr_debug(1, "Starting kthread...\n");
+ priv->mainthread.priv = priv;
+ wlan_create_thread(wlan_service_main_thread,
+ &priv->mainthread, "wlan_main_service");
+
+ priv->assoc_thread =
+ create_singlethread_workqueue("libertas_assoc");
+ INIT_DELAYED_WORK(&priv->assoc_work, wlan_association_worker);
+
+ /*
+ * Register the device. Fillup the private data structure with
+ * relevant information from the card and request for the required
+ * IRQ.
+ */
+ if (libertas_sbi_register_dev(priv) < 0) {
+ lbs_pr_info("failed to register wlan device!\n");
+ goto err_registerdev;
+ }
+
+ /* init FW and HW */
+ if (libertas_init_fw(priv)) {
+ lbs_pr_debug(1, "Firmware Init failed\n");
+ goto err_registerdev;
+ }
+
+ if (register_netdev(dev)) {
+ lbs_pr_err("Cannot register network device!\n");
+ goto err_init_fw;
+ }
+
+ /* Register virtual mesh interface */
+ if (register_netdev(mesh_dev)) {
+ lbs_pr_info("Cannot register mesh virtual interface!\n");
+ goto err_init_fw;
+ }
+
+ lbs_pr_info("%s: Marvell Wlan 802.11 adapter ", dev->name);
+
+ libertas_debugfs_init_one(priv, dev);
+
+ if (libertas_found == MAX_DEVS)
+ goto err_init_fw;
+ libertas_devs[libertas_found] = dev;
+ libertas_found++;
+#ifdef ENABLE_PM
+ if (!(wlan_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, wlan_pm_callback)))
+ lbs_pr_alert( "failed to register PM callback\n");
+#endif
+ if (device_create_file(&(mesh_dev->dev), &dev_attr_libertas_mpp))
+ goto err_create_file;
+
+ LEAVE();
+ return priv;
+
+err_create_file:
+ device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp);
+err_init_fw:
+ libertas_sbi_unregister_dev(priv);
+err_registerdev:
+ destroy_workqueue(priv->assoc_thread);
+ /* Stop the thread servicing the interrupts */
+ wake_up_interruptible(&priv->mainthread.waitq);
+ wlan_terminate_thread(&priv->mainthread);
+ kfree(priv->adapter);
+err_kmalloc:
+ free_netdev(dev);
+ free_netdev(mesh_dev);
+ wlanpriv = NULL;
+
+ LEAVE();
+ return NULL;
+}
+
+static void wake_pending_cmdnodes(wlan_private *priv)
+{
+ struct cmd_ctrl_node *cmdnode;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+ list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+ cmdnode->cmdwaitqwoken = 1;
+ wake_up_interruptible(&cmdnode->cmdwait_q);
+ }
+ spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+}
+
+
+int wlan_remove_card(void *card)
+{
+ wlan_private *priv = libertas_sbi_get_priv(card);
+ wlan_adapter *adapter;
+ struct net_device *dev;
+ struct net_device *mesh_dev;
+ union iwreq_data wrqu;
+ int i;
+
+ ENTER();
+
+ if (!priv) {
+ LEAVE();
+ return 0;
+ }
+
+ adapter = priv->adapter;
+
+ if (!adapter) {
+ LEAVE();
+ return 0;
+ }
+
+ dev = priv->wlan_dev.netdev;
+ mesh_dev = priv->mesh_dev;
+
+ netif_stop_queue(mesh_dev);
+ netif_stop_queue(priv->wlan_dev.netdev);
+ netif_carrier_off(priv->wlan_dev.netdev);
+
+ wake_pending_cmdnodes(priv);
+
+ device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp);
+ unregister_netdev(mesh_dev);
+ unregister_netdev(dev);
+
+ cancel_delayed_work(&priv->assoc_work);
+ destroy_workqueue(priv->assoc_thread);
+
+ if (adapter->psmode == wlan802_11powermodemax_psp) {
+ adapter->psmode = wlan802_11powermodecam;
+ libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+ }
+
+ memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+#ifdef ENABLE_PM
+ pm_unregister(wlan_pm_dev);
+#endif
+
+ adapter->surpriseremoved = 1;
+
+ /* Stop the thread servicing the interrupts */
+ wlan_terminate_thread(&priv->mainthread);
+
+ libertas_debugfs_remove_one(priv);
+
+ lbs_pr_debug(1, "Free adapter\n");
+ libertas_free_adapter(priv);
+
+ for (i = 0; i<libertas_found; i++) {
+ if (libertas_devs[i]==priv->wlan_dev.netdev) {
+ libertas_devs[i] = libertas_devs[--libertas_found];
+ libertas_devs[libertas_found] = NULL ;
+ break ;
+ }
+ }
+
+ lbs_pr_debug(1, "Unregister finish\n");
+
+ priv->wlan_dev.netdev = NULL;
+ priv->mesh_dev = NULL ;
+ free_netdev(mesh_dev);
+ free_netdev(dev);
+ wlanpriv = NULL;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function finds the CFP in
+ * region_cfp_table based on region and band parameter.
+ *
+ * @param region The region code
+ * @param band The band
+ * @param cfp_no A pointer to CFP number
+ * @return A pointer to CFP
+ */
+struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
+{
+ int i, end;
+
+ ENTER();
+
+ end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table);
+
+ for (i = 0; i < end ; i++) {
+ lbs_pr_debug(1, "region_cfp_table[i].region=%d\n",
+ region_cfp_table[i].region);
+ if (region_cfp_table[i].region == region) {
+ *cfp_no = region_cfp_table[i].cfp_no_BG;
+ LEAVE();
+ return region_cfp_table[i].cfp_BG;
+ }
+ }
+
+ LEAVE();
+ return NULL;
+}
+
+int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i = 0;
+
+ struct chan_freq_power *cfp;
+ int cfp_no;
+
+ ENTER();
+
+ memset(adapter->region_channel, 0, sizeof(adapter->region_channel));
+
+ {
+ cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
+ if (cfp != NULL) {
+ adapter->region_channel[i].nrcfp = cfp_no;
+ adapter->region_channel[i].CFP = cfp;
+ } else {
+ lbs_pr_debug(1, "wrong region code %#x in band B-G\n",
+ region);
+ return -1;
+ }
+ adapter->region_channel[i].valid = 1;
+ adapter->region_channel[i].region = region;
+ adapter->region_channel[i].band = band;
+ i++;
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function handles the interrupt. it will change PS
+ * state if applicable. it will wake up main_thread to handle
+ * the interrupt event as well.
+ *
+ * @param dev A pointer to net_device structure
+ * @return n/a
+ */
+void libertas_interrupt(struct net_device *dev)
+{
+ wlan_private *priv = dev->priv;
+
+ ENTER();
+
+ lbs_pr_debug(1, "libertas_interrupt: intcounter=%d\n",
+ priv->adapter->intcounter);
+
+ priv->adapter->intcounter++;
+
+ if (priv->adapter->psstate == PS_STATE_SLEEP) {
+ priv->adapter->psstate = PS_STATE_AWAKE;
+ netif_wake_queue(dev);
+ }
+
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ LEAVE();
+}
+
+static int wlan_init_module(void)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (libertas_fw_name == NULL) {
+ libertas_fw_name = default_fw_name;
+ }
+
+ libertas_debugfs_init();
+
+ if (libertas_sbi_register()) {
+ ret = -1;
+ libertas_debugfs_remove();
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+static void wlan_cleanup_module(void)
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i<libertas_found; i++) {
+ wlan_private *priv = libertas_devs[i]->priv;
+ reset_device(priv);
+ }
+
+ libertas_sbi_unregister();
+ libertas_debugfs_remove();
+
+ LEAVE();
+}
+
+module_init(wlan_init_module);
+module_exit(wlan_cleanup_module);
+
+MODULE_DESCRIPTION("M-WLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
new file mode 100644
index 000000000000..5d118f40cfbc
--- /dev/null
+++ b/drivers/net/wireless/libertas/radiotap.h
@@ -0,0 +1,57 @@
+#include <net/ieee80211_radiotap.h>
+
+struct tx_radiotap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 rate;
+ u8 txpower;
+ u8 rts_retries;
+ u8 data_retries;
+#if 0
+ u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12];
+#endif
+} __attribute__ ((packed));
+
+#define TX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
+ (1 << IEEE80211_RADIOTAP_RTS_RETRIES) | \
+ (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \
+ 0)
+
+#define IEEE80211_FC_VERSION_MASK 0x0003
+#define IEEE80211_FC_TYPE_MASK 0x000c
+#define IEEE80211_FC_TYPE_MGT 0x0000
+#define IEEE80211_FC_TYPE_CTL 0x0004
+#define IEEE80211_FC_TYPE_DATA 0x0008
+#define IEEE80211_FC_SUBTYPE_MASK 0x00f0
+#define IEEE80211_FC_TOFROMDS_MASK 0x0300
+#define IEEE80211_FC_TODS_MASK 0x0100
+#define IEEE80211_FC_FROMDS_MASK 0x0200
+#define IEEE80211_FC_NODS 0x0000
+#define IEEE80211_FC_TODS 0x0100
+#define IEEE80211_FC_FROMDS 0x0200
+#define IEEE80211_FC_DSTODS 0x0300
+
+struct rx_radiotap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 flags;
+ u8 rate;
+ u16 chan_freq;
+ u16 chan_flags;
+ u8 antenna;
+ u8 antsignal;
+ u16 rx_flags;
+#if 0
+ u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18];
+#endif
+} __attribute__ ((packed));
+
+#define RX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_ANTENNA) | \
+ (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\
+ (1 << IEEE80211_RADIOTAP_RX_FLAGS) | \
+ 0)
+
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
new file mode 100644
index 000000000000..7e3f78f092dc
--- /dev/null
+++ b/drivers/net/wireless/libertas/rx.c
@@ -0,0 +1,459 @@
+/**
+ * This file contains the handling of RX in wlan driver.
+ */
+#include <linux/etherdevice.h>
+#include <linux/types.h>
+
+#include "hostcmd.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "dev.h"
+#include "wext.h"
+
+struct eth803hdr {
+ u8 dest_addr[6];
+ u8 src_addr[6];
+ u16 h803_len;
+} __attribute__ ((packed));
+
+struct rfc1042hdr {
+ u8 llc_dsap;
+ u8 llc_ssap;
+ u8 llc_ctrl;
+ u8 snap_oui[3];
+ u16 snap_type;
+} __attribute__ ((packed));
+
+struct rxpackethdr {
+ struct rxpd rx_pd;
+ struct eth803hdr eth803_hdr;
+ struct rfc1042hdr rfc1042_hdr;
+} __attribute__ ((packed));
+
+struct rx80211packethdr {
+ struct rxpd rx_pd;
+ void *eth80211_hdr;
+} __attribute__ ((packed));
+
+static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb);
+
+/**
+ * @brief This function computes the avgSNR .
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return avgSNR
+ */
+static u8 wlan_getavgsnr(wlan_private * priv)
+{
+ u8 i;
+ u16 temp = 0;
+ wlan_adapter *adapter = priv->adapter;
+ if (adapter->numSNRNF == 0)
+ return 0;
+ for (i = 0; i < adapter->numSNRNF; i++)
+ temp += adapter->rawSNR[i];
+ return (u8) (temp / adapter->numSNRNF);
+
+}
+
+/**
+ * @brief This function computes the AvgNF
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return AvgNF
+ */
+static u8 wlan_getavgnf(wlan_private * priv)
+{
+ u8 i;
+ u16 temp = 0;
+ wlan_adapter *adapter = priv->adapter;
+ if (adapter->numSNRNF == 0)
+ return 0;
+ for (i = 0; i < adapter->numSNRNF; i++)
+ temp += adapter->rawNF[i];
+ return (u8) (temp / adapter->numSNRNF);
+
+}
+
+/**
+ * @brief This function save the raw SNR/NF to our internel buffer
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param prxpd A pointer to rxpd structure of received packet
+ * @return n/a
+ */
+static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
+{
+ wlan_adapter *adapter = priv->adapter;
+ if (adapter->numSNRNF < adapter->data_avg_factor)
+ adapter->numSNRNF++;
+ adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
+ adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
+ adapter->nextSNRNF++;
+ if (adapter->nextSNRNF >= adapter->data_avg_factor)
+ adapter->nextSNRNF = 0;
+ return;
+}
+
+/**
+ * @brief This function computes the RSSI in received packet.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param prxpd A pointer to rxpd structure of received packet
+ * @return n/a
+ */
+static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ lbs_pr_debug(1, "rxpd: SNR = %d, NF = %d\n", p_rx_pd->snr, p_rx_pd->nf);
+ lbs_pr_debug(1, "Before computing SNR: SNR- avg = %d, NF-avg = %d\n",
+ adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+ adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+ adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
+ adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
+ wlan_save_rawSNRNF(priv, p_rx_pd);
+
+ adapter->rxpd_rate = p_rx_pd->rx_rate;
+
+ adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
+ adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
+ lbs_pr_debug(1, "After computing SNR: SNR-avg = %d, NF-avg = %d\n",
+ adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+ adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+ adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
+ CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+ adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+
+ adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
+ CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+ adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+ LEAVE();
+}
+
+int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
+{
+ lbs_pr_debug(1, "skb->data=%p\n", skb->data);
+
+ if(IS_MESH_FRAME(skb))
+ skb->dev = priv->mesh_dev;
+ else
+ skb->dev = priv->wlan_dev.netdev;
+ skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ netif_rx(skb);
+
+ return 0;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param priv A pointer to wlan_private
+ * @param skb A pointer to skb which includes the received packet
+ * @return 0 or -1
+ */
+int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ struct rxpackethdr *p_rx_pkt;
+ struct rxpd *p_rx_pd;
+
+ int hdrchop;
+ struct ethhdr *p_ethhdr;
+
+ const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+ ENTER();
+
+ if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
+ lbs_dbg_hex("RX packet: ", skb->data,
+ min_t(unsigned int, skb->len, 100));
+
+ if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+ return process_rxed_802_11_packet(priv, skb);
+
+ p_rx_pkt = (struct rxpackethdr *) skb->data;
+ p_rx_pd = &p_rx_pkt->rx_pd;
+ if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
+ SET_MESH_FRAME(skb);
+ else
+ UNSET_MESH_FRAME(skb);
+
+ lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
+ min_t(unsigned int, skb->len, 100));
+
+ if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+ lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
+ priv->stats.rx_length_errors++;
+ ret = 0;
+ goto done;
+ }
+
+ /*
+ * Check rxpd status and update 802.3 stat,
+ */
+ if (!(p_rx_pd->status & MRVDRV_RXPD_STATUS_OK)) {
+ lbs_pr_debug(1, "RX error: frame received with bad status\n");
+ lbs_pr_alert("rxpd Not OK\n");
+ priv->stats.rx_errors++;
+ ret = 0;
+ goto done;
+ }
+
+ lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
+ skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+ lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
+ sizeof(p_rx_pkt->eth803_hdr.dest_addr));
+ lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
+ sizeof(p_rx_pkt->eth803_hdr.src_addr));
+
+ if (memcmp(&p_rx_pkt->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+ /*
+ * Replace the 803 header and rfc1042 header (llc/snap) with an
+ * EthernetII header, keep the src/dst and snap_type (ethertype)
+ *
+ * The firmware only passes up SNAP frames converting
+ * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+ *
+ * To create the Ethernet II, just move the src, dst address right
+ * before the snap_type.
+ */
+ p_ethhdr = (struct ethhdr *)
+ ((u8 *) & p_rx_pkt->eth803_hdr
+ + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
+ - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
+ - sizeof(p_rx_pkt->eth803_hdr.src_addr)
+ - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
+
+ memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
+ sizeof(p_ethhdr->h_source));
+ memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
+ sizeof(p_ethhdr->h_dest));
+
+ /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
+ * that was removed
+ */
+ hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
+ } else {
+ lbs_dbg_hex("RX Data: LLC/SNAP",
+ (u8 *) & p_rx_pkt->rfc1042_hdr,
+ sizeof(p_rx_pkt->rfc1042_hdr));
+
+ /* Chop off the rxpd */
+ hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt;
+ }
+
+ /* Chop off the leading header bytes so the skb points to the start of
+ * either the reconstructed EthII frame or the 802.2/llc/snap frame
+ */
+ skb_pull(skb, hdrchop);
+
+ /* Take the data rate from the rxpd structure
+ * only if the rate is auto
+ */
+ if (adapter->is_datarate_auto)
+ adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate);
+
+ wlan_compute_rssi(priv, p_rx_pd);
+
+ lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
+ if (libertas_upload_rx_packet(priv, skb)) {
+ lbs_pr_debug(1, "RX error: libertas_upload_rx_packet"
+ " returns failure\n");
+ ret = -1;
+ goto done;
+ }
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+
+ ret = 0;
+done:
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function converts Tx/Rx rates from the Marvell WLAN format
+ * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
+ *
+ * @param rate Input rate
+ * @return Output Rate (0 if invalid)
+ */
+static u8 convert_mv_rate_to_radiotap(u8 rate)
+{
+ switch (rate) {
+ case 0: /* 1 Mbps */
+ return 2;
+ case 1: /* 2 Mbps */
+ return 4;
+ case 2: /* 5.5 Mbps */
+ return 11;
+ case 3: /* 11 Mbps */
+ return 22;
+ case 4: /* 6 Mbps */
+ return 12;
+ case 5: /* 9 Mbps */
+ return 18;
+ case 6: /* 12 Mbps */
+ return 24;
+ case 7: /* 18 Mbps */
+ return 36;
+ case 8: /* 24 Mbps */
+ return 48;
+ case 9: /* 36 Mbps */
+ return 72;
+ case 10: /* 48 Mbps */
+ return 96;
+ case 11: /* 54 Mbps */
+ return 108;
+ }
+ lbs_pr_alert( "Invalid Marvell WLAN rate (%i)\n", rate);
+ return 0;
+}
+
+/**
+ * @brief This function processes a received 802.11 packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param priv A pointer to wlan_private
+ * @param skb A pointer to skb which includes the received packet
+ * @return 0 or -1
+ */
+static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ struct rx80211packethdr *p_rx_pkt;
+ struct rxpd *prxpd;
+ struct rx_radiotap_hdr radiotap_hdr;
+ struct rx_radiotap_hdr *pradiotap_hdr;
+
+ ENTER();
+
+ p_rx_pkt = (struct rx80211packethdr *) skb->data;
+ prxpd = &p_rx_pkt->rx_pd;
+
+ // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
+
+ if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+ lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
+ priv->stats.rx_length_errors++;
+ ret = 0;
+ goto done;
+ }
+
+ /*
+ * Check rxpd status and update 802.3 stat,
+ */
+ if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) {
+ //lbs_pr_debug(1, "RX error: frame received with bad status\n");
+ priv->stats.rx_errors++;
+ }
+
+ lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
+ skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+ /* create the exported radio header */
+ switch (priv->adapter->radiomode) {
+ case WLAN_RADIOMODE_NONE:
+ /* no radio header */
+ /* chop the rxpd */
+ skb_pull(skb, sizeof(struct rxpd));
+ break;
+
+ case WLAN_RADIOMODE_RADIOTAP:
+ /* radiotap header */
+ radiotap_hdr.hdr.it_version = 0;
+ /* XXX must check this value for pad */
+ radiotap_hdr.hdr.it_pad = 0;
+ radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr);
+ radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT;
+ /* unknown values */
+ radiotap_hdr.flags = 0;
+ radiotap_hdr.chan_freq = 0;
+ radiotap_hdr.chan_flags = 0;
+ radiotap_hdr.antenna = 0;
+ /* known values */
+ radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
+ /* XXX must check no carryout */
+ radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
+ radiotap_hdr.rx_flags = 0;
+ if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK))
+ radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
+ //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
+
+ // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100));
+
+ /* chop the rxpd */
+ skb_pull(skb, sizeof(struct rxpd));
+
+ /* add space for the new radio header */
+ if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
+ pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0,
+ GFP_ATOMIC)) {
+ lbs_pr_alert( "%s: couldn't pskb_expand_head\n",
+ __func__);
+ }
+
+ pradiotap_hdr =
+ (struct rx_radiotap_hdr *)skb_push(skb,
+ sizeof(struct
+ rx_radiotap_hdr));
+ memcpy(pradiotap_hdr, &radiotap_hdr,
+ sizeof(struct rx_radiotap_hdr));
+ //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
+ break;
+
+ default:
+ /* unknown header */
+ lbs_pr_alert( "Unknown radiomode (%i)\n",
+ priv->adapter->radiomode);
+ /* don't export any header */
+ /* chop the rxpd */
+ skb_pull(skb, sizeof(struct rxpd));
+ break;
+ }
+
+ /* Take the data rate from the rxpd structure
+ * only if the rate is auto
+ */
+ if (adapter->is_datarate_auto) {
+ adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate);
+ }
+
+ wlan_compute_rssi(priv, prxpd);
+
+ lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
+
+ if (libertas_upload_rx_packet(priv, skb)) {
+ lbs_pr_debug(1, "RX error: libertas_upload_rx_packet "
+ "returns failure\n");
+ ret = -1;
+ goto done;
+ }
+
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+
+ ret = 0;
+done:
+ LEAVE();
+
+ skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */
+
+ return (ret);
+}
diff --git a/drivers/net/wireless/libertas/sbi.h b/drivers/net/wireless/libertas/sbi.h
new file mode 100644
index 000000000000..59d3a59ccef0
--- /dev/null
+++ b/drivers/net/wireless/libertas/sbi.h
@@ -0,0 +1,40 @@
+/**
+ * This file contains IF layer definitions.
+ */
+
+#ifndef _SBI_H_
+#define _SBI_H_
+
+#include <linux/interrupt.h>
+
+#include "defs.h"
+
+/** INT status Bit Definition*/
+#define his_cmddnldrdy 0x01
+#define his_cardevent 0x02
+#define his_cmdupldrdy 0x04
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+#define SBI_EVENT_CAUSE_SHIFT 3
+
+/* Probe and Check if the card is present*/
+int libertas_sbi_register_dev(wlan_private * priv);
+int libertas_sbi_unregister_dev(wlan_private *);
+int libertas_sbi_get_int_status(wlan_private * priv, u8 *);
+int libertas_sbi_register(void);
+void libertas_sbi_unregister(void);
+int libertas_sbi_prog_firmware(wlan_private *);
+
+int libertas_sbi_read_event_cause(wlan_private *);
+int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
+wlan_private *libertas_sbi_get_priv(void *card);
+
+#ifdef ENABLE_PM
+int libertas_sbi_suspend(wlan_private *);
+int libertas_sbi_resume(wlan_private *);
+#endif
+
+#endif /* _SBI_H */
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
new file mode 100644
index 000000000000..e18706238951
--- /dev/null
+++ b/drivers/net/wireless/libertas/scan.c
@@ -0,0 +1,2044 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+ * Functions implementing wlan scan IOCTL and firmware command APIs
+ *
+ * IOCTL handlers as well as command preperation and response routines
+ * for sending scan commands to the firmware.
+ */
+#include <linux/ctype.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+
+#include <net/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "decl.h"
+#include "dev.h"
+#include "scan.h"
+
+//! Approximate amount of data needed to pass a scan result back to iwlist
+#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
+ + IW_ESSID_MAX_SIZE \
+ + IW_EV_UINT_LEN \
+ + IW_EV_FREQ_LEN \
+ + IW_EV_QUAL_LEN \
+ + IW_ESSID_MAX_SIZE \
+ + IW_EV_PARAM_LEN \
+ + 40) /* 40 for WPAIE */
+
+//! Memory needed to store a max sized channel List TLV for a firmware scan
+#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvlietypesheader) \
+ + (MRVDRV_MAX_CHANNELS_PER_SCAN \
+ * sizeof(struct chanscanparamset)))
+
+//! Memory needed to store a max number/size SSID TLV for a firmware scan
+#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset))
+
+//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
+#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config) \
+ + sizeof(struct mrvlietypes_numprobes) \
+ + CHAN_TLV_MAX_SIZE \
+ + SSID_TLV_MAX_SIZE)
+
+//! The maximum number of channels the firmware can scan per command
+#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
+
+/**
+ * @brief Number of channels to scan per firmware scan command issuance.
+ *
+ * Number restricted to prevent hitting the limit on the amount of scan data
+ * returned in a single firmware scan command.
+ */
+#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
+
+//! Scan time specified in the channel TLV for each channel for passive scans
+#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100
+
+//! Scan time specified in the channel TLV for each channel for active scans
+#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100
+
+//! Macro to enable/disable SSID checking before storing a scan table
+#ifdef DISCARD_BAD_SSID
+#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.ssid)
+#else
+#define CHECK_SSID_IS_VALID(x) 1
+#endif
+
+/**
+ * @brief Check if a scanned network compatible with the driver settings
+ *
+ * WEP WPA WPA2 ad-hoc encrypt Network
+ * enabled enabled enabled AES mode privacy WPA WPA2 Compatible
+ * 0 0 0 0 NONE 0 0 0 yes No security
+ * 1 0 0 0 NONE 1 0 0 yes Static WEP
+ * 0 1 0 0 x 1x 1 x yes WPA
+ * 0 0 1 0 x 1x x 1 yes WPA2
+ * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
+ * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
+ *
+ *
+ * @param adapter A pointer to wlan_adapter
+ * @param index Index in scantable to check against current driver settings
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return Index in scantable, or error code if negative
+ */
+static int is_network_compatible(wlan_adapter * adapter, int index, int mode)
+{
+ ENTER();
+
+ if (adapter->scantable[index].inframode == mode) {
+ if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+ && !adapter->secinfo.WPAenabled
+ && !adapter->secinfo.WPA2enabled
+ && adapter->scantable[index].wpa_supplicant.wpa_ie[0] !=
+ WPA_IE
+ && adapter->scantable[index].wpa2_supplicant.wpa_ie[0] !=
+ WPA2_IE && adapter->secinfo.Encryptionmode == CIPHER_NONE
+ && !adapter->scantable[index].privacy) {
+ /* no security */
+ LEAVE();
+ return index;
+ } else if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled
+ && !adapter->secinfo.WPAenabled
+ && !adapter->secinfo.WPA2enabled
+ && adapter->scantable[index].privacy) {
+ /* static WEP enabled */
+ LEAVE();
+ return index;
+ } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+ && adapter->secinfo.WPAenabled
+ && !adapter->secinfo.WPA2enabled
+ && (adapter->scantable[index].wpa_supplicant.
+ wpa_ie[0]
+ == WPA_IE)
+ /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+ && adapter->scantable[index].privacy */
+ ) {
+ /* WPA enabled */
+ lbs_pr_debug(1,
+ "is_network_compatible() WPA: index=%d wpa_ie=%#x "
+ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
+ "privacy=%#x\n", index,
+ adapter->scantable[index].wpa_supplicant.
+ wpa_ie[0],
+ adapter->scantable[index].wpa2_supplicant.
+ wpa_ie[0],
+ (adapter->secinfo.WEPstatus ==
+ wlan802_11WEPenabled) ? "e" : "d",
+ (adapter->secinfo.WPAenabled) ? "e" : "d",
+ (adapter->secinfo.WPA2enabled) ? "e" : "d",
+ adapter->secinfo.Encryptionmode,
+ adapter->scantable[index].privacy);
+ LEAVE();
+ return index;
+ } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+ && !adapter->secinfo.WPAenabled
+ && adapter->secinfo.WPA2enabled
+ && (adapter->scantable[index].wpa2_supplicant.
+ wpa_ie[0]
+ == WPA2_IE)
+ /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+ && adapter->scantable[index].privacy */
+ ) {
+ /* WPA2 enabled */
+ lbs_pr_debug(1,
+ "is_network_compatible() WPA2: index=%d wpa_ie=%#x "
+ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
+ "privacy=%#x\n", index,
+ adapter->scantable[index].wpa_supplicant.
+ wpa_ie[0],
+ adapter->scantable[index].wpa2_supplicant.
+ wpa_ie[0],
+ (adapter->secinfo.WEPstatus ==
+ wlan802_11WEPenabled) ? "e" : "d",
+ (adapter->secinfo.WPAenabled) ? "e" : "d",
+ (adapter->secinfo.WPA2enabled) ? "e" : "d",
+ adapter->secinfo.Encryptionmode,
+ adapter->scantable[index].privacy);
+ LEAVE();
+ return index;
+ } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+ && !adapter->secinfo.WPAenabled
+ && !adapter->secinfo.WPA2enabled
+ && (adapter->scantable[index].wpa_supplicant.
+ wpa_ie[0]
+ != WPA_IE)
+ && (adapter->scantable[index].wpa2_supplicant.
+ wpa_ie[0]
+ != WPA2_IE)
+ && adapter->secinfo.Encryptionmode != CIPHER_NONE
+ && adapter->scantable[index].privacy) {
+ /* dynamic WEP enabled */
+ lbs_pr_debug(1,
+ "is_network_compatible() dynamic WEP: index=%d "
+ "wpa_ie=%#x wpa2_ie=%#x Encmode=%#x privacy=%#x\n",
+ index,
+ adapter->scantable[index].wpa_supplicant.
+ wpa_ie[0],
+ adapter->scantable[index].wpa2_supplicant.
+ wpa_ie[0], adapter->secinfo.Encryptionmode,
+ adapter->scantable[index].privacy);
+ LEAVE();
+ return index;
+ }
+
+ /* security doesn't match */
+ lbs_pr_debug(1,
+ "is_network_compatible() FAILED: index=%d wpa_ie=%#x "
+ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x privacy=%#x\n",
+ index,
+ adapter->scantable[index].wpa_supplicant.wpa_ie[0],
+ adapter->scantable[index].wpa2_supplicant.wpa_ie[0],
+ (adapter->secinfo.WEPstatus ==
+ wlan802_11WEPenabled) ? "e" : "d",
+ (adapter->secinfo.WPAenabled) ? "e" : "d",
+ (adapter->secinfo.WPA2enabled) ? "e" : "d",
+ adapter->secinfo.Encryptionmode,
+ adapter->scantable[index].privacy);
+ LEAVE();
+ return -ECONNREFUSED;
+ }
+
+ /* mode doesn't match */
+ LEAVE();
+ return -ENETUNREACH;
+}
+
+/**
+ * @brief This function validates a SSID as being able to be printed
+ *
+ * @param pssid SSID structure to validate
+ *
+ * @return TRUE or FALSE
+ */
+static u8 ssid_valid(struct WLAN_802_11_SSID *pssid)
+{
+ int ssididx;
+
+ for (ssididx = 0; ssididx < pssid->ssidlength; ssididx++) {
+ if (!isprint(pssid->ssid[ssididx])) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * @brief Post process the scan table after a new scan command has completed
+ *
+ * Inspect each entry of the scan table and try to find an entry that
+ * matches our current associated/joined network from the scan. If
+ * one is found, update the stored copy of the bssdescriptor for our
+ * current network.
+ *
+ * Debug dump the current scan table contents if compiled accordingly.
+ *
+ * @param priv A pointer to wlan_private structure
+ *
+ * @return void
+ */
+static void wlan_scan_process_results(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int foundcurrent;
+ int i;
+
+ foundcurrent = 0;
+
+ if (adapter->connect_status == libertas_connected) {
+ /* try to find the current BSSID in the new scan list */
+ for (i = 0; i < adapter->numinscantable; i++) {
+ if (!libertas_SSID_cmp(&adapter->scantable[i].ssid,
+ &adapter->curbssparams.ssid) &&
+ !memcmp(adapter->curbssparams.bssid,
+ adapter->scantable[i].macaddress,
+ ETH_ALEN)) {
+ foundcurrent = 1;
+ }
+ }
+
+ if (foundcurrent) {
+ /* Make a copy of current BSSID descriptor */
+ memcpy(&adapter->curbssparams.bssdescriptor,
+ &adapter->scantable[i],
+ sizeof(adapter->curbssparams.bssdescriptor));
+ }
+ }
+
+ for (i = 0; i < adapter->numinscantable; i++) {
+ lbs_pr_debug(1, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
+ "RSSI[%03d], SSID[%s]\n",
+ i,
+ adapter->scantable[i].macaddress[0],
+ adapter->scantable[i].macaddress[1],
+ adapter->scantable[i].macaddress[2],
+ adapter->scantable[i].macaddress[3],
+ adapter->scantable[i].macaddress[4],
+ adapter->scantable[i].macaddress[5],
+ (s32) adapter->scantable[i].rssi,
+ adapter->scantable[i].ssid.ssid);
+ }
+}
+
+/**
+ * @brief Create a channel list for the driver to scan based on region info
+ *
+ * Use the driver region/band information to construct a comprehensive list
+ * of channels to scan. This routine is used for any scan that is not
+ * provided a specific channel list to scan.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param scanchanlist Output parameter: resulting channel list to scan
+ * @param filteredscan Flag indicating whether or not a BSSID or SSID filter
+ * is being sent in the command to firmware. Used to
+ * increase the number of channels sent in a scan
+ * command and to disable the firmware channel scan
+ * filter.
+ *
+ * @return void
+ */
+static void wlan_scan_create_channel_list(wlan_private * priv,
+ struct chanscanparamset * scanchanlist,
+ u8 filteredscan)
+{
+
+ wlan_adapter *adapter = priv->adapter;
+ struct region_channel *scanregion;
+ struct chan_freq_power *cfp;
+ int rgnidx;
+ int chanidx;
+ int nextchan;
+ u8 scantype;
+
+ chanidx = 0;
+
+ /* Set the default scan type to the user specified type, will later
+ * be changed to passive on a per channel basis if restricted by
+ * regulatory requirements (11d or 11h)
+ */
+ scantype = adapter->scantype;
+
+ for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
+ if (priv->adapter->enable11d &&
+ adapter->connect_status != libertas_connected) {
+ /* Scan all the supported chan for the first scan */
+ if (!adapter->universal_channel[rgnidx].valid)
+ continue;
+ scanregion = &adapter->universal_channel[rgnidx];
+
+ /* clear the parsed_region_chan for the first scan */
+ memset(&adapter->parsed_region_chan, 0x00,
+ sizeof(adapter->parsed_region_chan));
+ } else {
+ if (!adapter->region_channel[rgnidx].valid)
+ continue;
+ scanregion = &adapter->region_channel[rgnidx];
+ }
+
+ for (nextchan = 0;
+ nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
+
+ cfp = scanregion->CFP + nextchan;
+
+ if (priv->adapter->enable11d) {
+ scantype =
+ libertas_get_scan_type_11d(cfp->channel,
+ &adapter->
+ parsed_region_chan);
+ }
+
+ switch (scanregion->band) {
+ case BAND_B:
+ case BAND_G:
+ default:
+ scanchanlist[chanidx].radiotype =
+ cmd_scan_radio_type_bg;
+ break;
+ }
+
+ if (scantype == cmd_scan_type_passive) {
+ scanchanlist[chanidx].maxscantime =
+ cpu_to_le16
+ (MRVDRV_PASSIVE_SCAN_CHAN_TIME);
+ scanchanlist[chanidx].chanscanmode.passivescan =
+ 1;
+ } else {
+ scanchanlist[chanidx].maxscantime =
+ cpu_to_le16
+ (MRVDRV_ACTIVE_SCAN_CHAN_TIME);
+ scanchanlist[chanidx].chanscanmode.passivescan =
+ 0;
+ }
+
+ scanchanlist[chanidx].channumber = cfp->channel;
+
+ if (filteredscan) {
+ scanchanlist[chanidx].chanscanmode.
+ disablechanfilt = 1;
+ }
+ }
+ }
+}
+
+/**
+ * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
+ *
+ * Application layer or other functions can invoke wlan_scan_networks
+ * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+ * This structure is used as the basis of one or many wlan_scan_cmd_config
+ * commands that are sent to the command processing module and sent to
+ * firmware.
+ *
+ * Create a wlan_scan_cmd_config based on the following user supplied
+ * parameters (if present):
+ * - SSID filter
+ * - BSSID filter
+ * - Number of Probes to be sent
+ * - channel list
+ *
+ * If the SSID or BSSID filter is not present, disable/clear the filter.
+ * If the number of probes is not set, use the adapter default setting
+ * Qualify the channel
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param puserscanin NULL or pointer to scan configuration parameters
+ * @param ppchantlvout Output parameter: Pointer to the start of the
+ * channel TLV portion of the output scan config
+ * @param pscanchanlist Output parameter: Pointer to the resulting channel
+ * list to scan
+ * @param pmaxchanperscan Output parameter: Number of channels to scan for
+ * each issuance of the firmware scan command
+ * @param pfilteredscan Output parameter: Flag indicating whether or not
+ * a BSSID or SSID filter is being sent in the
+ * command to firmware. Used to increase the number
+ * of channels sent in a scan command and to
+ * disable the firmware channel scan filter.
+ * @param pscancurrentonly Output parameter: Flag indicating whether or not
+ * we are only scanning our current active channel
+ *
+ * @return resulting scan configuration
+ */
+static struct wlan_scan_cmd_config *
+wlan_scan_setup_scan_config(wlan_private * priv,
+ const struct wlan_ioctl_user_scan_cfg * puserscanin,
+ struct mrvlietypes_chanlistparamset ** ppchantlvout,
+ struct chanscanparamset * pscanchanlist,
+ int *pmaxchanperscan,
+ u8 * pfilteredscan,
+ u8 * pscancurrentonly)
+{
+ wlan_adapter *adapter = priv->adapter;
+ const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ struct mrvlietypes_numprobes *pnumprobestlv;
+ struct mrvlietypes_ssidparamset *pssidtlv;
+ struct wlan_scan_cmd_config * pscancfgout = NULL;
+ u8 *ptlvpos;
+ u16 numprobes;
+ u16 ssidlen;
+ int chanidx;
+ int scantype;
+ int scandur;
+ int channel;
+ int radiotype;
+
+ pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
+ if (pscancfgout == NULL)
+ goto out;
+
+ /* The tlvbufferlen is calculated for each scan command. The TLVs added
+ * in this routine will be preserved since the routine that sends
+ * the command will append channelTLVs at *ppchantlvout. The difference
+ * between the *ppchantlvout and the tlvbuffer start will be used
+ * to calculate the size of anything we add in this routine.
+ */
+ pscancfgout->tlvbufferlen = 0;
+
+ /* Running tlv pointer. Assigned to ppchantlvout at end of function
+ * so later routines know where channels can be added to the command buf
+ */
+ ptlvpos = pscancfgout->tlvbuffer;
+
+ /*
+ * Set the initial scan paramters for progressive scanning. If a specific
+ * BSSID or SSID is used, the number of channels in the scan command
+ * will be increased to the absolute maximum
+ */
+ *pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
+
+ /* Initialize the scan as un-filtered by firmware, set to TRUE below if
+ * a SSID or BSSID filter is sent in the command
+ */
+ *pfilteredscan = 0;
+
+ /* Initialize the scan as not being only on the current channel. If
+ * the channel list is customized, only contains one channel, and
+ * is the active channel, this is set true and data flow is not halted.
+ */
+ *pscancurrentonly = 0;
+
+ if (puserscanin) {
+
+ /* Set the bss type scan filter, use adapter setting if unset */
+ pscancfgout->bsstype =
+ (puserscanin->bsstype ? puserscanin->bsstype : adapter->
+ scanmode);
+
+ /* Set the number of probes to send, use adapter setting if unset */
+ numprobes = (puserscanin->numprobes ? puserscanin->numprobes :
+ adapter->scanprobes);
+
+ /*
+ * Set the BSSID filter to the incoming configuration,
+ * if non-zero. If not set, it will remain disabled (all zeros).
+ */
+ memcpy(pscancfgout->specificBSSID,
+ puserscanin->specificBSSID,
+ sizeof(pscancfgout->specificBSSID));
+
+ ssidlen = strlen(puserscanin->specificSSID);
+
+ if (ssidlen) {
+ pssidtlv =
+ (struct mrvlietypes_ssidparamset *) pscancfgout->
+ tlvbuffer;
+ pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+ pssidtlv->header.len = cpu_to_le16(ssidlen);
+ memcpy(pssidtlv->ssid, puserscanin->specificSSID,
+ ssidlen);
+ ptlvpos += sizeof(pssidtlv->header) + ssidlen;
+ }
+
+ /*
+ * The default number of channels sent in the command is low to
+ * ensure the response buffer from the firmware does not truncate
+ * scan results. That is not an issue with an SSID or BSSID
+ * filter applied to the scan results in the firmware.
+ */
+ if (ssidlen || (memcmp(pscancfgout->specificBSSID,
+ &zeromac, sizeof(zeromac)) != 0)) {
+ *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
+ *pfilteredscan = 1;
+ }
+ } else {
+ pscancfgout->bsstype = adapter->scanmode;
+ numprobes = adapter->scanprobes;
+ }
+
+ /* If the input config or adapter has the number of Probes set, add tlv */
+ if (numprobes) {
+ pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos;
+ pnumprobestlv->header.type =
+ cpu_to_le16(TLV_TYPE_NUMPROBES);
+ pnumprobestlv->header.len = sizeof(pnumprobestlv->numprobes);
+ pnumprobestlv->numprobes = cpu_to_le16(numprobes);
+
+ ptlvpos +=
+ sizeof(pnumprobestlv->header) + pnumprobestlv->header.len;
+
+ pnumprobestlv->header.len =
+ cpu_to_le16(pnumprobestlv->header.len);
+ }
+
+ /*
+ * Set the output for the channel TLV to the address in the tlv buffer
+ * past any TLVs that were added in this fuction (SSID, numprobes).
+ * channel TLVs will be added past this for each scan command, preserving
+ * the TLVs that were previously added.
+ */
+ *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
+
+ if (puserscanin && puserscanin->chanlist[0].channumber) {
+
+ lbs_pr_debug(1, "Scan: Using supplied channel list\n");
+
+ for (chanidx = 0;
+ chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+ && puserscanin->chanlist[chanidx].channumber; chanidx++) {
+
+ channel = puserscanin->chanlist[chanidx].channumber;
+ (pscanchanlist + chanidx)->channumber = channel;
+
+ radiotype = puserscanin->chanlist[chanidx].radiotype;
+ (pscanchanlist + chanidx)->radiotype = radiotype;
+
+ scantype = puserscanin->chanlist[chanidx].scantype;
+
+ if (scantype == cmd_scan_type_passive) {
+ (pscanchanlist +
+ chanidx)->chanscanmode.passivescan = 1;
+ } else {
+ (pscanchanlist +
+ chanidx)->chanscanmode.passivescan = 0;
+ }
+
+ if (puserscanin->chanlist[chanidx].scantime) {
+ scandur =
+ puserscanin->chanlist[chanidx].scantime;
+ } else {
+ if (scantype == cmd_scan_type_passive) {
+ scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+ } else {
+ scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+ }
+ }
+
+ (pscanchanlist + chanidx)->minscantime =
+ cpu_to_le16(scandur);
+ (pscanchanlist + chanidx)->maxscantime =
+ cpu_to_le16(scandur);
+ }
+
+ /* Check if we are only scanning the current channel */
+ if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
+ ==
+ priv->adapter->curbssparams.channel)) {
+ *pscancurrentonly = 1;
+ lbs_pr_debug(1, "Scan: Scanning current channel only");
+ }
+
+ } else {
+ lbs_pr_debug(1, "Scan: Creating full region channel list\n");
+ wlan_scan_create_channel_list(priv, pscanchanlist,
+ *pfilteredscan);
+ }
+
+out:
+ return pscancfgout;
+}
+
+/**
+ * @brief Construct and send multiple scan config commands to the firmware
+ *
+ * Previous routines have created a wlan_scan_cmd_config with any requested
+ * TLVs. This function splits the channel TLV into maxchanperscan lists
+ * and sends the portion of the channel TLV along with the other TLVs
+ * to the wlan_cmd routines for execution in the firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param maxchanperscan Maximum number channels to be included in each
+ * scan command sent to firmware
+ * @param filteredscan Flag indicating whether or not a BSSID or SSID
+ * filter is being used for the firmware command
+ * scan command sent to firmware
+ * @param pscancfgout Scan configuration used for this scan.
+ * @param pchantlvout Pointer in the pscancfgout where the channel TLV
+ * should start. This is past any other TLVs that
+ * must be sent down in each firmware command.
+ * @param pscanchanlist List of channels to scan in maxchanperscan segments
+ *
+ * @return 0 or error return otherwise
+ */
+static int wlan_scan_channel_list(wlan_private * priv,
+ int maxchanperscan,
+ u8 filteredscan,
+ struct wlan_scan_cmd_config * pscancfgout,
+ struct mrvlietypes_chanlistparamset * pchantlvout,
+ struct chanscanparamset * pscanchanlist)
+{
+ struct chanscanparamset *ptmpchan;
+ struct chanscanparamset *pstartchan;
+ u8 scanband;
+ int doneearly;
+ int tlvidx;
+ int ret = 0;
+
+ ENTER();
+
+ if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
+ lbs_pr_debug(1, "Scan: Null detect: %p, %p, %p\n",
+ pscancfgout, pchantlvout, pscanchanlist);
+ return -1;
+ }
+
+ pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+
+ /* Set the temp channel struct pointer to the start of the desired list */
+ ptmpchan = pscanchanlist;
+
+ /* Loop through the desired channel list, sending a new firmware scan
+ * commands for each maxchanperscan channels (or for 1,6,11 individually
+ * if configured accordingly)
+ */
+ while (ptmpchan->channumber) {
+
+ tlvidx = 0;
+ pchantlvout->header.len = 0;
+ scanband = ptmpchan->radiotype;
+ pstartchan = ptmpchan;
+ doneearly = 0;
+
+ /* Construct the channel TLV for the scan command. Continue to
+ * insert channel TLVs until:
+ * - the tlvidx hits the maximum configured per scan command
+ * - the next channel to insert is 0 (end of desired channel list)
+ * - doneearly is set (controlling individual scanning of 1,6,11)
+ */
+ while (tlvidx < maxchanperscan && ptmpchan->channumber
+ && !doneearly) {
+
+ lbs_pr_debug(1,
+ "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
+ ptmpchan->channumber, ptmpchan->radiotype,
+ ptmpchan->chanscanmode.passivescan,
+ ptmpchan->chanscanmode.disablechanfilt,
+ ptmpchan->maxscantime);
+
+ /* Copy the current channel TLV to the command being prepared */
+ memcpy(pchantlvout->chanscanparam + tlvidx,
+ ptmpchan, sizeof(pchantlvout->chanscanparam));
+
+ /* Increment the TLV header length by the size appended */
+ pchantlvout->header.len +=
+ sizeof(pchantlvout->chanscanparam);
+
+ /*
+ * The tlv buffer length is set to the number of bytes of the
+ * between the channel tlv pointer and the start of the
+ * tlv buffer. This compensates for any TLVs that were appended
+ * before the channel list.
+ */
+ pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
+ - pscancfgout->tlvbuffer);
+
+ /* Add the size of the channel tlv header and the data length */
+ pscancfgout->tlvbufferlen +=
+ (sizeof(pchantlvout->header)
+ + pchantlvout->header.len);
+
+ /* Increment the index to the channel tlv we are constructing */
+ tlvidx++;
+
+ doneearly = 0;
+
+ /* Stop the loop if the *current* channel is in the 1,6,11 set
+ * and we are not filtering on a BSSID or SSID.
+ */
+ if (!filteredscan && (ptmpchan->channumber == 1
+ || ptmpchan->channumber == 6
+ || ptmpchan->channumber == 11)) {
+ doneearly = 1;
+ }
+
+ /* Increment the tmp pointer to the next channel to be scanned */
+ ptmpchan++;
+
+ /* Stop the loop if the *next* channel is in the 1,6,11 set.
+ * This will cause it to be the only channel scanned on the next
+ * interation
+ */
+ if (!filteredscan && (ptmpchan->channumber == 1
+ || ptmpchan->channumber == 6
+ || ptmpchan->channumber == 11)) {
+ doneearly = 1;
+ }
+ }
+
+ /* Send the scan command to the firmware with the specified cfg */
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0,
+ 0, 0, pscancfgout);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Internal function used to start a scan based on an input config
+ *
+ * Use the input user scan configuration information when provided in
+ * order to send the appropriate scan commands to firmware to populate or
+ * update the internal driver scan table
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param puserscanin Pointer to the input configuration for the requested
+ * scan.
+ *
+ * @return 0 or < 0 if error
+ */
+int wlan_scan_networks(wlan_private * priv,
+ const struct wlan_ioctl_user_scan_cfg * puserscanin)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct mrvlietypes_chanlistparamset *pchantlvout;
+ struct chanscanparamset * scan_chan_list = NULL;
+ struct wlan_scan_cmd_config * scan_cfg = NULL;
+ u8 keeppreviousscan;
+ u8 filteredscan;
+ u8 scancurrentchanonly;
+ int maxchanperscan;
+ int ret;
+
+ ENTER();
+
+ scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
+ WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
+ if (scan_chan_list == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ scan_cfg = wlan_scan_setup_scan_config(priv,
+ puserscanin,
+ &pchantlvout,
+ scan_chan_list,
+ &maxchanperscan,
+ &filteredscan,
+ &scancurrentchanonly);
+ if (scan_cfg == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ keeppreviousscan = 0;
+
+ if (puserscanin) {
+ keeppreviousscan = puserscanin->keeppreviousscan;
+ }
+
+ if (!keeppreviousscan) {
+ memset(adapter->scantable, 0x00,
+ sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST);
+ adapter->numinscantable = 0;
+ }
+
+ /* Keep the data path active if we are only scanning our current channel */
+ if (!scancurrentchanonly) {
+ netif_stop_queue(priv->wlan_dev.netdev);
+ netif_carrier_off(priv->wlan_dev.netdev);
+ }
+
+ ret = wlan_scan_channel_list(priv,
+ maxchanperscan,
+ filteredscan,
+ scan_cfg,
+ pchantlvout,
+ scan_chan_list);
+
+ /* Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ wlan_scan_process_results(priv);
+
+ if (priv->adapter->connect_status == libertas_connected) {
+ netif_carrier_on(priv->wlan_dev.netdev);
+ netif_wake_queue(priv->wlan_dev.netdev);
+ }
+
+out:
+ if (scan_cfg)
+ kfree(scan_cfg);
+
+ if (scan_chan_list)
+ kfree(scan_chan_list);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Inspect the scan response buffer for pointers to expected TLVs
+ *
+ * TLVs can be included at the end of the scan response BSS information.
+ * Parse the data in the buffer for pointers to TLVs that can potentially
+ * be passed back in the response
+ *
+ * @param ptlv Pointer to the start of the TLV buffer to parse
+ * @param tlvbufsize size of the TLV buffer
+ * @param ptsftlv Output parameter: Pointer to the TSF TLV if found
+ *
+ * @return void
+ */
+static
+void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
+ int tlvbufsize,
+ struct mrvlietypes_tsftimestamp ** ptsftlv)
+{
+ struct mrvlietypes_data *pcurrenttlv;
+ int tlvbufleft;
+ u16 tlvtype;
+ u16 tlvlen;
+
+ pcurrenttlv = ptlv;
+ tlvbufleft = tlvbufsize;
+ *ptsftlv = NULL;
+
+ lbs_pr_debug(1, "SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
+ lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
+
+ while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
+ tlvtype = le16_to_cpu(pcurrenttlv->header.type);
+ tlvlen = le16_to_cpu(pcurrenttlv->header.len);
+
+ switch (tlvtype) {
+ case TLV_TYPE_TSFTIMESTAMP:
+ *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
+ break;
+
+ default:
+ lbs_pr_debug(1, "SCAN_RESP: Unhandled TLV = %d\n",
+ tlvtype);
+ /* Give up, this seems corrupted */
+ return;
+ } /* switch */
+
+ tlvbufleft -= (sizeof(ptlv->header) + tlvlen);
+ pcurrenttlv =
+ (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen);
+ } /* while */
+}
+
+/**
+ * @brief Interpret a BSS scan response returned from the firmware
+ *
+ * Parse the various fixed fields and IEs passed back for a a BSS probe
+ * response or beacon from the scan command. Record information as needed
+ * in the scan table struct bss_descriptor for that entry.
+ *
+ * @param pBSSIDEntry Output parameter: Pointer to the BSS Entry
+ *
+ * @return 0 or -1
+ */
+static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry,
+ u8 ** pbeaconinfo, int *bytesleft)
+{
+ enum ieeetypes_elementid elemID;
+ struct ieeetypes_fhparamset *pFH;
+ struct ieeetypes_dsparamset *pDS;
+ struct ieeetypes_cfparamset *pCF;
+ struct ieeetypes_ibssparamset *pibss;
+ struct ieeetypes_capinfo *pcap;
+ struct WLAN_802_11_FIXED_IEs fixedie;
+ u8 *pcurrentptr;
+ u8 *pRate;
+ u8 elemlen;
+ u8 bytestocopy;
+ u8 ratesize;
+ u16 beaconsize;
+ u8 founddatarateie;
+ int bytesleftforcurrentbeacon;
+
+ struct WPA_SUPPLICANT *pwpa_supplicant;
+ struct WPA_SUPPLICANT *pwpa2_supplicant;
+ struct IE_WPA *pIe;
+ const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 };
+
+ struct ieeetypes_countryinfoset *pcountryinfo;
+
+ ENTER();
+
+ founddatarateie = 0;
+ ratesize = 0;
+ beaconsize = 0;
+
+ if (*bytesleft >= sizeof(beaconsize)) {
+ /* Extract & convert beacon size from the command buffer */
+ memcpy(&beaconsize, *pbeaconinfo, sizeof(beaconsize));
+ beaconsize = le16_to_cpu(beaconsize);
+ *bytesleft -= sizeof(beaconsize);
+ *pbeaconinfo += sizeof(beaconsize);
+ }
+
+ if (beaconsize == 0 || beaconsize > *bytesleft) {
+
+ *pbeaconinfo += *bytesleft;
+ *bytesleft = 0;
+
+ return -1;
+ }
+
+ /* Initialize the current working beacon pointer for this BSS iteration */
+ pcurrentptr = *pbeaconinfo;
+
+ /* Advance the return beacon pointer past the current beacon */
+ *pbeaconinfo += beaconsize;
+ *bytesleft -= beaconsize;
+
+ bytesleftforcurrentbeacon = beaconsize;
+
+ pwpa_supplicant = &pBSSEntry->wpa_supplicant;
+ pwpa2_supplicant = &pBSSEntry->wpa2_supplicant;
+
+ memcpy(pBSSEntry->macaddress, pcurrentptr, ETH_ALEN);
+ lbs_pr_debug(1, "InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n",
+ pBSSEntry->macaddress[0], pBSSEntry->macaddress[1],
+ pBSSEntry->macaddress[2], pBSSEntry->macaddress[3],
+ pBSSEntry->macaddress[4], pBSSEntry->macaddress[5]);
+
+ pcurrentptr += ETH_ALEN;
+ bytesleftforcurrentbeacon -= ETH_ALEN;
+
+ if (bytesleftforcurrentbeacon < 12) {
+ lbs_pr_debug(1, "InterpretIE: Not enough bytes left\n");
+ return -1;
+ }
+
+ /*
+ * next 4 fields are RSSI, time stamp, beacon interval,
+ * and capability information
+ */
+
+ /* RSSI is 1 byte long */
+ pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr));
+ lbs_pr_debug(1, "InterpretIE: RSSI=%02X\n", *pcurrentptr);
+ pcurrentptr += 1;
+ bytesleftforcurrentbeacon -= 1;
+
+ /* time stamp is 8 bytes long */
+ memcpy(fixedie.timestamp, pcurrentptr, 8);
+ memcpy(pBSSEntry->timestamp, pcurrentptr, 8);
+ pcurrentptr += 8;
+ bytesleftforcurrentbeacon -= 8;
+
+ /* beacon interval is 2 bytes long */
+ memcpy(&fixedie.beaconinterval, pcurrentptr, 2);
+ pBSSEntry->beaconperiod = le16_to_cpu(fixedie.beaconinterval);
+ pcurrentptr += 2;
+ bytesleftforcurrentbeacon -= 2;
+
+ /* capability information is 2 bytes long */
+ memcpy(&fixedie.capabilities, pcurrentptr, 2);
+ lbs_pr_debug(1, "InterpretIE: fixedie.capabilities=0x%X\n",
+ fixedie.capabilities);
+ fixedie.capabilities = le16_to_cpu(fixedie.capabilities);
+ pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities;
+ memcpy(&pBSSEntry->cap, pcap, sizeof(struct ieeetypes_capinfo));
+ pcurrentptr += 2;
+ bytesleftforcurrentbeacon -= 2;
+
+ /* rest of the current buffer are IE's */
+ lbs_pr_debug(1, "InterpretIE: IElength for this AP = %d\n",
+ bytesleftforcurrentbeacon);
+
+ lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr,
+ bytesleftforcurrentbeacon);
+
+ if (pcap->privacy) {
+ lbs_pr_debug(1, "InterpretIE: AP WEP enabled\n");
+ pBSSEntry->privacy = wlan802_11privfilter8021xWEP;
+ } else {
+ pBSSEntry->privacy = wlan802_11privfilteracceptall;
+ }
+
+ if (pcap->ibss == 1) {
+ pBSSEntry->inframode = wlan802_11ibss;
+ } else {
+ pBSSEntry->inframode = wlan802_11infrastructure;
+ }
+
+ /* process variable IE */
+ while (bytesleftforcurrentbeacon >= 2) {
+ elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
+ elemlen = *((u8 *) pcurrentptr + 1);
+
+ if (bytesleftforcurrentbeacon < elemlen) {
+ lbs_pr_debug(1, "InterpretIE: error in processing IE, "
+ "bytes left < IE length\n");
+ bytesleftforcurrentbeacon = 0;
+ continue;
+ }
+
+ switch (elemID) {
+
+ case SSID:
+ pBSSEntry->ssid.ssidlength = elemlen;
+ memcpy(pBSSEntry->ssid.ssid, (pcurrentptr + 2),
+ elemlen);
+ lbs_pr_debug(1, "ssid: %32s", pBSSEntry->ssid.ssid);
+ break;
+
+ case SUPPORTED_RATES:
+ memcpy(pBSSEntry->datarates, (pcurrentptr + 2),
+ elemlen);
+ memmove(pBSSEntry->libertas_supported_rates, (pcurrentptr + 2),
+ elemlen);
+ ratesize = elemlen;
+ founddatarateie = 1;
+ break;
+
+ case EXTRA_IE:
+ lbs_pr_debug(1, "InterpretIE: EXTRA_IE Found!\n");
+ pBSSEntry->extra_ie = 1;
+ break;
+
+ case FH_PARAM_SET:
+ pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
+ memmove(&pBSSEntry->phyparamset.fhparamset, pFH,
+ sizeof(struct ieeetypes_fhparamset));
+ pBSSEntry->phyparamset.fhparamset.dwelltime
+ =
+ le16_to_cpu(pBSSEntry->phyparamset.fhparamset.
+ dwelltime);
+ break;
+
+ case DS_PARAM_SET:
+ pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
+
+ pBSSEntry->channel = pDS->currentchan;
+
+ memcpy(&pBSSEntry->phyparamset.dsparamset, pDS,
+ sizeof(struct ieeetypes_dsparamset));
+ break;
+
+ case CF_PARAM_SET:
+ pCF = (struct ieeetypes_cfparamset *) pcurrentptr;
+
+ memcpy(&pBSSEntry->ssparamset.cfparamset, pCF,
+ sizeof(struct ieeetypes_cfparamset));
+ break;
+
+ case IBSS_PARAM_SET:
+ pibss = (struct ieeetypes_ibssparamset *) pcurrentptr;
+ pBSSEntry->atimwindow =
+ le32_to_cpu(pibss->atimwindow);
+
+ memmove(&pBSSEntry->ssparamset.ibssparamset, pibss,
+ sizeof(struct ieeetypes_ibssparamset));
+
+ pBSSEntry->ssparamset.ibssparamset.atimwindow
+ =
+ le16_to_cpu(pBSSEntry->ssparamset.ibssparamset.
+ atimwindow);
+ break;
+
+ /* Handle Country Info IE */
+ case COUNTRY_INFO:
+ pcountryinfo =
+ (struct ieeetypes_countryinfoset *) pcurrentptr;
+
+ if (pcountryinfo->len <
+ sizeof(pcountryinfo->countrycode)
+ || pcountryinfo->len > 254) {
+ lbs_pr_debug(1, "InterpretIE: 11D- Err "
+ "CountryInfo len =%d min=%d max=254\n",
+ pcountryinfo->len,
+ sizeof(pcountryinfo->countrycode));
+ LEAVE();
+ return -1;
+ }
+
+ memcpy(&pBSSEntry->countryinfo,
+ pcountryinfo, pcountryinfo->len + 2);
+ lbs_dbg_hex("InterpretIE: 11D- CountryInfo:",
+ (u8 *) pcountryinfo,
+ (u32) (pcountryinfo->len + 2));
+ break;
+
+ case EXTENDED_SUPPORTED_RATES:
+ /*
+ * only process extended supported rate
+ * if data rate is already found.
+ * data rate IE should come before
+ * extended supported rate IE
+ */
+ if (founddatarateie) {
+ if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) {
+ bytestocopy =
+ (WLAN_SUPPORTED_RATES - ratesize);
+ } else {
+ bytestocopy = elemlen;
+ }
+
+ pRate = (u8 *) pBSSEntry->datarates;
+ pRate += ratesize;
+ memmove(pRate, (pcurrentptr + 2), bytestocopy);
+
+ pRate = (u8 *) pBSSEntry->libertas_supported_rates;
+
+ pRate += ratesize;
+ memmove(pRate, (pcurrentptr + 2), bytestocopy);
+ }
+ break;
+
+ case VENDOR_SPECIFIC_221:
+#define IE_ID_LEN_FIELDS_BYTES 2
+ pIe = (struct IE_WPA *)pcurrentptr;
+
+ if (!memcmp(pIe->oui, oui01, sizeof(oui01))) {
+ pwpa_supplicant->wpa_ie_len
+ = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES,
+ sizeof(pwpa_supplicant->wpa_ie));
+ memcpy(pwpa_supplicant->wpa_ie,
+ pcurrentptr,
+ pwpa_supplicant->wpa_ie_len);
+ lbs_dbg_hex("InterpretIE: Resp WPA_IE",
+ pwpa_supplicant->wpa_ie, elemlen);
+ }
+ break;
+ case WPA2_IE:
+ pIe = (struct IE_WPA *)pcurrentptr;
+ pwpa2_supplicant->wpa_ie_len
+ = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES,
+ sizeof(pwpa2_supplicant->wpa_ie));
+ memcpy(pwpa2_supplicant->wpa_ie,
+ pcurrentptr, pwpa2_supplicant->wpa_ie_len);
+
+ lbs_dbg_hex("InterpretIE: Resp WPA2_IE",
+ pwpa2_supplicant->wpa_ie, elemlen);
+ break;
+ case TIM:
+ break;
+
+ case CHALLENGE_TEXT:
+ break;
+ }
+
+ pcurrentptr += elemlen + 2;
+
+ /* need to account for IE ID and IE len */
+ bytesleftforcurrentbeacon -= (elemlen + 2);
+
+ } /* while (bytesleftforcurrentbeacon > 2) */
+
+ return 0;
+}
+
+/**
+ * @brief Compare two SSIDs
+ *
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *ssid2)
+{
+ if (!ssid1 || !ssid2)
+ return -1;
+
+ if (ssid1->ssidlength != ssid2->ssidlength)
+ return -1;
+
+ return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssidlength);
+}
+
+/**
+ * @brief This function finds a specific compatible BSSID in the scan list
+ *
+ * @param adapter A pointer to wlan_adapter
+ * @param bssid BSSID to find in the scan list
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list, or error return code (< 0)
+ */
+int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode)
+{
+ int ret = -ENETUNREACH;
+ int i;
+
+ if (!bssid)
+ return -EFAULT;
+
+ lbs_pr_debug(1, "FindBSSID: Num of BSSIDs = %d\n",
+ adapter->numinscantable);
+
+ /* Look through the scan table for a compatible match. The ret return
+ * variable will be equal to the index in the scan table (greater
+ * than zero) if the network is compatible. The loop will continue
+ * past a matched bssid that is not compatible in case there is an
+ * AP with multiple SSIDs assigned to the same BSSID
+ */
+ for (i = 0; ret < 0 && i < adapter->numinscantable; i++) {
+ if (!memcmp(adapter->scantable[i].macaddress, bssid, ETH_ALEN)) {
+ switch (mode) {
+ case wlan802_11infrastructure:
+ case wlan802_11ibss:
+ ret = is_network_compatible(adapter, i, mode);
+ break;
+ default:
+ ret = i;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * @brief This function finds ssid in ssid list.
+ *
+ * @param adapter A pointer to wlan_adapter
+ * @param ssid SSID to find in the list
+ * @param bssid BSSID to qualify the SSID selection (if provided)
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list
+ */
+int libertas_find_SSID_in_list(wlan_adapter * adapter,
+ struct WLAN_802_11_SSID *ssid, u8 * bssid, int mode)
+{
+ int net = -ENETUNREACH;
+ u8 bestrssi = 0;
+ int i;
+ int j;
+
+ lbs_pr_debug(1, "Num of Entries in Table = %d\n", adapter->numinscantable);
+
+ for (i = 0; i < adapter->numinscantable; i++) {
+ if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, ssid) &&
+ (!bssid ||
+ !memcmp(adapter->scantable[i].
+ macaddress, bssid, ETH_ALEN))) {
+ switch (mode) {
+ case wlan802_11infrastructure:
+ case wlan802_11ibss:
+ j = is_network_compatible(adapter, i, mode);
+
+ if (j >= 0) {
+ if (bssid) {
+ return i;
+ }
+
+ if (SCAN_RSSI
+ (adapter->scantable[i].rssi)
+ > bestrssi) {
+ bestrssi =
+ SCAN_RSSI(adapter->
+ scantable[i].
+ rssi);
+ net = i;
+ }
+ } else {
+ if (net == -ENETUNREACH) {
+ net = j;
+ }
+ }
+ break;
+ case wlan802_11autounknown:
+ default:
+ if (SCAN_RSSI(adapter->scantable[i].rssi)
+ > bestrssi) {
+ bestrssi =
+ SCAN_RSSI(adapter->scantable[i].
+ rssi);
+ net = i;
+ }
+ break;
+ }
+ }
+ }
+
+ return net;
+}
+
+/**
+ * @brief This function finds the best SSID in the Scan List
+ *
+ * Search the scan table for the best SSID that also matches the current
+ * adapter network preference (infrastructure or adhoc)
+ *
+ * @param adapter A pointer to wlan_adapter
+ *
+ * @return index in BSSID list
+ */
+int libertas_find_best_SSID_in_list(wlan_adapter * adapter,
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode)
+{
+ int bestnet = -ENETUNREACH;
+ u8 bestrssi = 0;
+ int i;
+
+ ENTER();
+
+ lbs_pr_debug(1, "Num of BSSIDs = %d\n", adapter->numinscantable);
+
+ for (i = 0; i < adapter->numinscantable; i++) {
+ switch (mode) {
+ case wlan802_11infrastructure:
+ case wlan802_11ibss:
+ if (is_network_compatible(adapter, i, mode) >= 0) {
+ if (SCAN_RSSI(adapter->scantable[i].rssi) >
+ bestrssi) {
+ bestrssi =
+ SCAN_RSSI(adapter->scantable[i].
+ rssi);
+ bestnet = i;
+ }
+ }
+ break;
+ case wlan802_11autounknown:
+ default:
+ if (SCAN_RSSI(adapter->scantable[i].rssi) > bestrssi) {
+ bestrssi =
+ SCAN_RSSI(adapter->scantable[i].rssi);
+ bestnet = i;
+ }
+ break;
+ }
+ }
+
+ LEAVE();
+ return bestnet;
+}
+
+/**
+ * @brief Find the AP with specific ssid in the scan list
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param pSSID A pointer to AP's ssid
+ *
+ * @return 0--success, otherwise--fail
+ */
+int libertas_find_best_network_SSID(wlan_private * priv,
+ struct WLAN_802_11_SSID *pSSID,
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct bss_descriptor *preqbssid;
+ int i;
+
+ ENTER();
+
+ memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID));
+
+ wlan_scan_networks(priv, NULL);
+ if (adapter->surpriseremoved)
+ return -1;
+ wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
+
+ i = libertas_find_best_SSID_in_list(adapter, preferred_mode);
+ if (i < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ preqbssid = &adapter->scantable[i];
+ memcpy(pSSID, &preqbssid->ssid,
+ sizeof(struct WLAN_802_11_SSID));
+ *out_mode = preqbssid->inframode;
+
+ if (!pSSID->ssidlength) {
+ ret = -1;
+ }
+
+out:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Scan Network
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ union iwreq_data wrqu;
+
+ ENTER();
+
+ if (!wlan_scan_networks(priv, NULL)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+ NULL);
+ }
+
+ if (adapter->surpriseremoved)
+ return -1;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Send a scan command for all available channels filtered on a spec
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param prequestedssid A pointer to AP's ssid
+ * @param keeppreviousscan Flag used to save/clear scan table before scan
+ *
+ * @return 0-success, otherwise fail
+ */
+int libertas_send_specific_SSID_scan(wlan_private * priv,
+ struct WLAN_802_11_SSID *prequestedssid,
+ u8 keeppreviousscan)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_ioctl_user_scan_cfg scancfg;
+
+ ENTER();
+
+ if (prequestedssid == NULL) {
+ return -1;
+ }
+
+ memset(&scancfg, 0x00, sizeof(scancfg));
+
+ memcpy(scancfg.specificSSID, prequestedssid->ssid,
+ prequestedssid->ssidlength);
+ scancfg.keeppreviousscan = keeppreviousscan;
+
+ wlan_scan_networks(priv, &scancfg);
+ if (adapter->surpriseremoved)
+ return -1;
+ wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief scan an AP with specific BSSID
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param bssid A pointer to AP's bssid
+ * @param keeppreviousscan Flag used to save/clear scan table before scan
+ *
+ * @return 0-success, otherwise fail
+ */
+int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppreviousscan)
+{
+ struct wlan_ioctl_user_scan_cfg scancfg;
+
+ ENTER();
+
+ if (bssid == NULL) {
+ return -1;
+ }
+
+ memset(&scancfg, 0x00, sizeof(scancfg));
+ memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID));
+ scancfg.keeppreviousscan = keeppreviousscan;
+
+ wlan_scan_networks(priv, &scancfg);
+ if (priv->adapter->surpriseremoved)
+ return -1;
+ wait_event_interruptible(priv->adapter->cmd_pending,
+ !priv->adapter->nr_cmd_pending);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Retrieve the scan table entries via wireless tools IOCTL call
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ char *current_ev = extra;
+ char *end_buf = extra + IW_SCAN_MAX_DATA;
+ struct chan_freq_power *cfp;
+ struct bss_descriptor *pscantable;
+ char *current_val; /* For rates */
+ struct iw_event iwe; /* Temporary buffer */
+ int i;
+ int j;
+ int rate;
+#define PERFECT_RSSI ((u8)50)
+#define WORST_RSSI ((u8)0)
+#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI))
+ u8 rssi;
+
+ u8 buf[16 + 256 * 2];
+ u8 *ptr;
+
+ ENTER();
+
+ /*
+ * if there's either commands in the queue or one being
+ * processed return -EAGAIN for iwlist to retry later.
+ */
+ if (adapter->nr_cmd_pending)
+ return -EAGAIN;
+
+ if (adapter->connect_status == libertas_connected)
+ lbs_pr_debug(1, "Current ssid: %32s\n",
+ adapter->curbssparams.ssid.ssid);
+
+ lbs_pr_debug(1, "Scan: Get: numinscantable = %d\n",
+ adapter->numinscantable);
+
+ /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP.
+ * The new API using SIOCGIWSCAN is only limited by buffer size
+ * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes
+ * which is 4096.
+ */
+ for (i = 0; i < adapter->numinscantable; i++) {
+ if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
+ lbs_pr_debug(1, "i=%d break out: current_ev=%p end_buf=%p "
+ "MAX_SCAN_CELL_SIZE=%d\n",
+ i, current_ev, end_buf, MAX_SCAN_CELL_SIZE);
+ break;
+ }
+
+ pscantable = &adapter->scantable[i];
+
+ lbs_pr_debug(1, "i=%d ssid: %32s\n", i, pscantable->ssid.ssid);
+
+ cfp =
+ libertas_find_cfp_by_band_and_channel(adapter, 0,
+ pscantable->channel);
+ if (!cfp) {
+ lbs_pr_debug(1, "Invalid channel number %d\n",
+ pscantable->channel);
+ continue;
+ }
+
+ if (!ssid_valid(&adapter->scantable[i].ssid)) {
+ continue;
+ }
+
+ /* First entry *MUST* be the AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data,
+ &adapter->scantable[i].macaddress, ETH_ALEN);
+
+ iwe.len = IW_EV_ADDR_LEN;
+ current_ev =
+ iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+ //Add the ESSID
+ iwe.u.data.length = adapter->scantable[i].ssid.ssidlength;
+
+ if (iwe.u.data.length > 32) {
+ iwe.u.data.length = 32;
+ }
+
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.flags = 1;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ adapter->scantable[i].ssid.
+ ssid);
+
+ //Add mode
+ iwe.cmd = SIOCGIWMODE;
+ iwe.u.mode = adapter->scantable[i].inframode + 1;
+ iwe.len = IW_EV_UINT_LEN;
+ current_ev =
+ iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+ //frequency
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = (long)cfp->freq * 100000;
+ iwe.u.freq.e = 1;
+ iwe.len = IW_EV_FREQ_LEN;
+ current_ev =
+ iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+ /* Add quality statistics */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
+ iwe.u.qual.level = SCAN_RSSI(adapter->scantable[i].rssi);
+
+ rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ iwe.u.qual.qual =
+ (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
+ (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
+ (RSSI_DIFF * RSSI_DIFF);
+ if (iwe.u.qual.qual > 100)
+ iwe.u.qual.qual = 100;
+ else if (iwe.u.qual.qual < 1)
+ iwe.u.qual.qual = 0;
+
+ if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+ iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ } else {
+ iwe.u.qual.noise =
+ CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+ }
+ if ((adapter->inframode == wlan802_11ibss) &&
+ !libertas_SSID_cmp(&adapter->curbssparams.ssid,
+ &adapter->scantable[i].ssid)
+ && adapter->adhoccreate) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rssi,
+ 0,
+ cmd_option_waitforrsp,
+ 0, NULL);
+
+ if (!ret) {
+ iwe.u.qual.level =
+ CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] /
+ AVG_SCALE,
+ adapter->NF[TYPE_RXPD][TYPE_AVG] /
+ AVG_SCALE);
+ }
+ }
+ iwe.len = IW_EV_QUAL_LEN;
+ current_ev =
+ iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (adapter->scantable[i].privacy) {
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ } else {
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ }
+ iwe.u.data.length = 0;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ adapter->scantable->ssid.
+ ssid);
+
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ iwe.cmd = SIOCGIWRATE;
+
+ iwe.u.bitrate.fixed = 0;
+ iwe.u.bitrate.disabled = 0;
+ iwe.u.bitrate.value = 0;
+
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ for (j = 0; j < sizeof(adapter->scantable[i].libertas_supported_rates);
+ j++) {
+ if (adapter->scantable[i].libertas_supported_rates[j] == 0) {
+ break;
+ }
+ rate =
+ (adapter->scantable[i].libertas_supported_rates[j] & 0x7F) *
+ 500000;
+ if (rate > iwe.u.bitrate.value) {
+ iwe.u.bitrate.value = rate;
+ }
+
+ iwe.u.bitrate.value =
+ (adapter->scantable[i].libertas_supported_rates[j]
+ & 0x7f) * 500000;
+ iwe.len = IW_EV_PARAM_LEN;
+ current_ev =
+ iwe_stream_add_value(current_ev, current_val,
+ end_buf, &iwe, iwe.len);
+
+ }
+ if ((adapter->scantable[i].inframode == wlan802_11ibss)
+ && !libertas_SSID_cmp(&adapter->curbssparams.ssid,
+ &adapter->scantable[i].ssid)
+ && adapter->adhoccreate) {
+ iwe.u.bitrate.value = 22 * 500000;
+ }
+ iwe.len = IW_EV_PARAM_LEN;
+ current_ev =
+ iwe_stream_add_value(current_ev, current_val, end_buf, &iwe,
+ iwe.len);
+
+ /* Add new value to event */
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ if (adapter->scantable[i].wpa2_supplicant.wpa_ie[0] == WPA2_IE) {
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, adapter->scantable[i].
+ wpa2_supplicant.wpa_ie,
+ adapter->scantable[i].wpa2_supplicant.
+ wpa_ie_len);
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = adapter->scantable[i].
+ wpa2_supplicant.wpa_ie_len;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ }
+ if (adapter->scantable[i].wpa_supplicant.wpa_ie[0] == WPA_IE) {
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, adapter->scantable[i].
+ wpa_supplicant.wpa_ie,
+ adapter->scantable[i].wpa_supplicant.
+ wpa_ie_len);
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = adapter->scantable[i].
+ wpa_supplicant.wpa_ie_len;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ }
+
+
+ if (adapter->scantable[i].extra_ie != 0) {
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ ptr += sprintf(ptr, "extra_ie");
+ iwe.u.data.length = strlen(buf);
+
+ lbs_pr_debug(1, "iwe.u.data.length %d\n",
+ iwe.u.data.length);
+ lbs_pr_debug(1, "BUF: %s \n", buf);
+
+ iwe.cmd = IWEVCUSTOM;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ iwe_stream_add_point(current_ev, end_buf, &iwe,
+ buf);
+ }
+
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ /*
+ * Check if we added any event
+ */
+ if ((current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
+ }
+
+ dwrq->length = (current_ev - extra);
+ dwrq->flags = 0;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Prepare a scan command to be sent to the firmware
+ *
+ * Use the wlan_scan_cmd_config sent to the command processing module in
+ * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command
+ * struct to send to firmware.
+ *
+ * The fixed fields specifying the BSS type and BSSID filters as well as a
+ * variable number/length of TLVs are sent in the command to firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param cmd A pointer to cmd_ds_command structure to be sent to
+ * firmware with the cmd_DS_801_11_SCAN structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return 0 or -1
+ *
+ * @sa wlan_scan_create_channel_list
+ */
+int libertas_cmd_80211_scan(wlan_private * priv,
+ struct cmd_ds_command *cmd, void *pdata_buf)
+{
+ struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
+ struct wlan_scan_cmd_config *pscancfg;
+
+ ENTER();
+
+ pscancfg = pdata_buf;
+
+ /* Set fixed field variables in scan command */
+ pscan->bsstype = pscancfg->bsstype;
+ memcpy(pscan->BSSID, pscancfg->specificBSSID, sizeof(pscan->BSSID));
+ memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
+
+ cmd->command = cpu_to_le16(cmd_802_11_scan);
+
+ /* size is equal to the sizeof(fixed portions) + the TLV len + header */
+ cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
+ + sizeof(pscan->BSSID)
+ + pscancfg->tlvbufferlen + S_DS_GEN);
+
+ lbs_pr_debug(1, "SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
+ cmd->command, cmd->size, cmd->seqnum);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function handles the command response of scan
+ *
+ * The response buffer for the scan command has the following
+ * memory layout:
+ *
+ * .-----------------------------------------------------------.
+ * | header (4 * sizeof(u16)): Standard command response hdr |
+ * .-----------------------------------------------------------.
+ * | bufsize (u16) : sizeof the BSS Description data |
+ * .-----------------------------------------------------------.
+ * | NumOfSet (u8) : Number of BSS Descs returned |
+ * .-----------------------------------------------------------.
+ * | BSSDescription data (variable, size given in bufsize) |
+ * .-----------------------------------------------------------.
+ * | TLV data (variable, size calculated using header->size, |
+ * | bufsize and sizeof the fixed fields above) |
+ * .-----------------------------------------------------------.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param resp A pointer to cmd_ds_command
+ *
+ * @return 0 or -1
+ */
+int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_scan_rsp *pscan;
+ struct bss_descriptor newbssentry;
+ struct mrvlietypes_data *ptlv;
+ struct mrvlietypes_tsftimestamp *ptsftlv;
+ u8 *pbssinfo;
+ u16 scanrespsize;
+ int bytesleft;
+ int numintable;
+ int bssIdx;
+ int idx;
+ int tlvbufsize;
+ u64 tsfval;
+
+ ENTER();
+
+ pscan = &resp->params.scanresp;
+
+ if (pscan->nr_sets > MRVDRV_MAX_BSSID_LIST) {
+ lbs_pr_debug(1,
+ "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+ pscan->nr_sets);
+ LEAVE();
+ return -1;
+ }
+
+ bytesleft = le16_to_cpu(pscan->bssdescriptsize);
+ lbs_pr_debug(1, "SCAN_RESP: bssdescriptsize %d\n", bytesleft);
+
+ scanrespsize = le16_to_cpu(resp->size);
+ lbs_pr_debug(1, "SCAN_RESP: returned %d AP before parsing\n",
+ pscan->nr_sets);
+
+ numintable = adapter->numinscantable;
+ pbssinfo = pscan->bssdesc_and_tlvbuffer;
+
+ /* The size of the TLV buffer is equal to the entire command response
+ * size (scanrespsize) minus the fixed fields (sizeof()'s), the
+ * BSS Descriptions (bssdescriptsize as bytesLef) and the command
+ * response header (S_DS_GEN)
+ */
+ tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize)
+ + sizeof(pscan->nr_sets)
+ + S_DS_GEN);
+
+ ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft);
+
+ /* Search the TLV buffer space in the scan response for any valid TLVs */
+ wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv);
+
+ /*
+ * Process each scan response returned (pscan->nr_sets). Save
+ * the information in the newbssentry and then insert into the
+ * driver scan table either as an update to an existing entry
+ * or as an addition at the end of the table
+ */
+ for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) {
+ /* Zero out the newbssentry we are about to store info in */
+ memset(&newbssentry, 0x00, sizeof(newbssentry));
+
+ /* Process the data fields and IEs returned for this BSS */
+ if ((InterpretBSSDescriptionWithIE(&newbssentry,
+ &pbssinfo,
+ &bytesleft) ==
+ 0)
+ && CHECK_SSID_IS_VALID(&newbssentry.ssid)) {
+
+ lbs_pr_debug(1,
+ "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ newbssentry.macaddress[0],
+ newbssentry.macaddress[1],
+ newbssentry.macaddress[2],
+ newbssentry.macaddress[3],
+ newbssentry.macaddress[4],
+ newbssentry.macaddress[5]);
+
+ /*
+ * Search the scan table for the same bssid
+ */
+ for (bssIdx = 0; bssIdx < numintable; bssIdx++) {
+ if (memcmp(newbssentry.macaddress,
+ adapter->scantable[bssIdx].
+ macaddress,
+ sizeof(newbssentry.macaddress)) ==
+ 0) {
+ /*
+ * If the SSID matches as well, it is a duplicate of
+ * this entry. Keep the bssIdx set to this
+ * entry so we replace the old contents in the table
+ */
+ if ((newbssentry.ssid.ssidlength ==
+ adapter->scantable[bssIdx].ssid.
+ ssidlength)
+ &&
+ (memcmp
+ (newbssentry.ssid.ssid,
+ adapter->scantable[bssIdx].ssid.
+ ssid,
+ newbssentry.ssid.ssidlength) ==
+ 0)) {
+ lbs_pr_debug(1,
+ "SCAN_RESP: Duplicate of index: %d\n",
+ bssIdx);
+ break;
+ }
+ }
+ }
+ /*
+ * If the bssIdx is equal to the number of entries in the table,
+ * the new entry was not a duplicate; append it to the scan
+ * table
+ */
+ if (bssIdx == numintable) {
+ /* Range check the bssIdx, keep it limited to the last entry */
+ if (bssIdx == MRVDRV_MAX_BSSID_LIST) {
+ bssIdx--;
+ } else {
+ numintable++;
+ }
+ }
+
+ /*
+ * If the TSF TLV was appended to the scan results, save the
+ * this entries TSF value in the networktsf field. The
+ * networktsf is the firmware's TSF value at the time the
+ * beacon or probe response was received.
+ */
+ if (ptsftlv) {
+ memcpy(&tsfval, &ptsftlv->tsftable[idx],
+ sizeof(tsfval));
+ tsfval = le64_to_cpu(tsfval);
+
+ memcpy(&newbssentry.networktsf,
+ &tsfval, sizeof(newbssentry.networktsf));
+ }
+
+ /* Copy the locally created newbssentry to the scan table */
+ memcpy(&adapter->scantable[bssIdx],
+ &newbssentry,
+ sizeof(adapter->scantable[bssIdx]));
+
+ } else {
+
+ /* error parsing/interpreting the scan response, skipped */
+ lbs_pr_debug(1, "SCAN_RESP: "
+ "InterpretBSSDescriptionWithIE returned ERROR\n");
+ }
+ }
+
+ lbs_pr_debug(1, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+ pscan->nr_sets, numintable - adapter->numinscantable,
+ numintable);
+
+ /* Update the total number of BSSIDs in the scan table */
+ adapter->numinscantable = numintable;
+
+ LEAVE();
+ return 0;
+}
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
new file mode 100644
index 000000000000..d93aa7fa44fd
--- /dev/null
+++ b/drivers/net/wireless/libertas/scan.h
@@ -0,0 +1,216 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+ * Interface for the wlan network scan routines
+ *
+ * Driver interface functions and type declarations for the scan module
+ * implemented in wlan_scan.c.
+ */
+#ifndef _WLAN_SCAN_H
+#define _WLAN_SCAN_H
+
+#include "hostcmd.h"
+
+/**
+ * @brief Maximum number of channels that can be sent in a setuserscan ioctl
+ *
+ * @sa wlan_ioctl_user_scan_cfg
+ */
+#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50
+
+//! Infrastructure BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_BSS 1
+
+//! Adhoc BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_IBSS 2
+
+//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter
+#define WLAN_SCAN_BSS_TYPE_ANY 3
+
+/**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command processing module to configure the firmware
+ * scan command prepared by libertas_cmd_80211_scan.
+ *
+ * @sa wlan_scan_networks
+ *
+ */
+struct wlan_scan_cmd_config {
+ /**
+ * @brief BSS type to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. valid settings are:
+ *
+ * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure)
+ * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+ * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ u8 bsstype;
+
+ /**
+ * @brief Specific BSSID used to filter scan results in the firmware
+ */
+ u8 specificBSSID[ETH_ALEN];
+
+ /**
+ * @brief length of TLVs sent in command starting at tlvBuffer
+ */
+ int tlvbufferlen;
+
+ /**
+ * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+ *
+ * @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t
+ * @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t
+ */
+ u8 tlvbuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here
+};
+
+/**
+ * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Multiple instances of this structure are included in the IOCTL command
+ * to configure a instance of a scan on the specific channel.
+ */
+struct wlan_ioctl_user_scan_chan {
+ u8 channumber; //!< channel Number to scan
+ u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1
+ u8 scantype; //!< Scan type: Active = 0, Passive = 1
+ u16 scantime; //!< Scan duration in milliseconds; if 0 default used
+};
+
+/**
+ * @brief IOCTL input structure to configure an immediate scan cmd to firmware
+ *
+ * Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl. Specifies
+ * a number of parameters to be used in general for the scan as well
+ * as a channel list (wlan_ioctl_user_scan_chan) for each scan period
+ * desired.
+ *
+ * @sa libertas_set_user_scan_ioctl
+ */
+struct wlan_ioctl_user_scan_cfg {
+
+ /**
+ * @brief Flag set to keep the previous scan table intact
+ *
+ * If set, the scan results will accumulate, replacing any previous
+ * matched entries for a BSS with the new scan data
+ */
+ u8 keeppreviousscan; //!< Do not erase the existing scan results
+
+ /**
+ * @brief BSS type to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. valid settings are:
+ *
+ * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure)
+ * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+ * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ u8 bsstype;
+
+ /**
+ * @brief Configure the number of probe requests for active chan scans
+ */
+ u8 numprobes;
+
+ /**
+ * @brief BSSID filter sent in the firmware command to limit the results
+ */
+ u8 specificBSSID[ETH_ALEN];
+
+ /**
+ * @brief SSID filter sent in the firmware command to limit the results
+ */
+ char specificSSID[IW_ESSID_MAX_SIZE + 1];
+
+ /**
+ * @brief Variable number (fixed maximum) of channels to scan up
+ */
+ struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+};
+
+/**
+ * @brief Structure used to store information for each beacon/probe response
+ */
+struct bss_descriptor {
+ u8 macaddress[ETH_ALEN];
+
+ struct WLAN_802_11_SSID ssid;
+
+ /* WEP encryption requirement */
+ u32 privacy;
+
+ /* receive signal strength in dBm */
+ long rssi;
+
+ u32 channel;
+
+ u16 beaconperiod;
+
+ u32 atimwindow;
+
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
+ u8 libertas_supported_rates[WLAN_SUPPORTED_RATES];
+
+ int extra_ie;
+
+ u8 timestamp[8]; //!< TSF value included in the beacon/probe response
+ union ieeetypes_phyparamset phyparamset;
+ union IEEEtypes_ssparamset ssparamset;
+ struct ieeetypes_capinfo cap;
+ u8 datarates[WLAN_SUPPORTED_RATES];
+
+ __le64 networktsf; //!< TSF timestamp from the current firmware TSF
+
+ struct ieeetypes_countryinfofullset countryinfo;
+
+ struct WPA_SUPPLICANT wpa_supplicant;
+ struct WPA_SUPPLICANT wpa2_supplicant;
+
+};
+
+extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1,
+ struct WLAN_802_11_SSID *ssid2);
+extern int libertas_find_SSID_in_list(wlan_adapter * adapter, struct WLAN_802_11_SSID *ssid,
+ u8 * bssid, int mode);
+int libertas_find_best_SSID_in_list(wlan_adapter * adapter, enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode);
+extern int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode);
+
+int libertas_find_best_network_SSID(wlan_private * priv,
+ struct WLAN_802_11_SSID *pSSID,
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode);
+
+extern int libertas_send_specific_SSID_scan(wlan_private * priv,
+ struct WLAN_802_11_SSID *prequestedssid,
+ u8 keeppreviousscan);
+extern int libertas_send_specific_BSSID_scan(wlan_private * priv,
+ u8 * bssid, u8 keeppreviousscan);
+
+extern int libertas_cmd_80211_scan(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+
+extern int libertas_ret_80211_scan(wlan_private * priv,
+ struct cmd_ds_command *resp);
+
+int wlan_scan_networks(wlan_private * priv,
+ const struct wlan_ioctl_user_scan_cfg * puserscanin);
+
+struct ifreq;
+
+struct iw_point;
+struct iw_param;
+struct iw_request_info;
+extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra);
+extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra);
+
+#endif /* _WLAN_SCAN_H */
diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h
new file mode 100644
index 000000000000..207b8a6cc33d
--- /dev/null
+++ b/drivers/net/wireless/libertas/thread.h
@@ -0,0 +1,52 @@
+#ifndef __WLAN_THREAD_H_
+#define __WLAN_THREAD_H_
+
+#include <linux/kthread.h>
+
+struct wlan_thread {
+ struct task_struct *task;
+ wait_queue_head_t waitq;
+ pid_t pid;
+ void *priv;
+};
+
+static inline void wlan_activate_thread(struct wlan_thread * thr)
+{
+ /** Record the thread pid */
+ thr->pid = current->pid;
+
+ /** Initialize the wait queue */
+ init_waitqueue_head(&thr->waitq);
+}
+
+static inline void wlan_deactivate_thread(struct wlan_thread * thr)
+{
+ ENTER();
+
+ thr->pid = 0;
+
+ LEAVE();
+}
+
+static inline void wlan_create_thread(int (*wlanfunc) (void *),
+ struct wlan_thread * thr, char *name)
+{
+ thr->task = kthread_run(wlanfunc, thr, "%s", name);
+}
+
+static inline int wlan_terminate_thread(struct wlan_thread * thr)
+{
+ ENTER();
+
+ /* Check if the thread is active or not */
+ if (!thr->pid) {
+ printk(KERN_ERR "Thread does not exist\n");
+ return -1;
+ }
+ kthread_stop(thr->task);
+
+ LEAVE();
+ return 0;
+}
+
+#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
new file mode 100644
index 000000000000..82d06223043e
--- /dev/null
+++ b/drivers/net/wireless/libertas/tx.c
@@ -0,0 +1,285 @@
+/**
+ * This file contains the handling of TX in wlan driver.
+ */
+#include <linux/netdevice.h>
+
+#include "hostcmd.h"
+#include "radiotap.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "wext.h"
+
+/**
+ * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
+ * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
+ *
+ * @param rate Input rate
+ * @return Output Rate (0 if invalid)
+ */
+static u32 convert_radiotap_rate_to_mv(u8 rate)
+{
+ switch (rate) {
+ case 2: /* 1 Mbps */
+ return 0 | (1 << 4);
+ case 4: /* 2 Mbps */
+ return 1 | (1 << 4);
+ case 11: /* 5.5 Mbps */
+ return 2 | (1 << 4);
+ case 22: /* 11 Mbps */
+ return 3 | (1 << 4);
+ case 12: /* 6 Mbps */
+ return 4 | (1 << 4);
+ case 18: /* 9 Mbps */
+ return 5 | (1 << 4);
+ case 24: /* 12 Mbps */
+ return 6 | (1 << 4);
+ case 36: /* 18 Mbps */
+ return 7 | (1 << 4);
+ case 48: /* 24 Mbps */
+ return 8 | (1 << 4);
+ case 72: /* 36 Mbps */
+ return 9 | (1 << 4);
+ case 96: /* 48 Mbps */
+ return 10 | (1 << 4);
+ case 108: /* 54 Mbps */
+ return 11 | (1 << 4);
+ }
+ return 0;
+}
+
+/**
+ * @brief This function processes a single packet and sends
+ * to IF layer
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param skb A pointer to skb which includes TX packet
+ * @return 0 or -1
+ */
+static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct txpd localtxpd;
+ struct txpd *plocaltxpd = &localtxpd;
+ u8 *p802x_hdr;
+ struct tx_radiotap_hdr *pradiotap_hdr;
+ u32 new_rate;
+ u8 *ptr = priv->adapter->tmptxbuf;
+
+ ENTER();
+
+ if (priv->adapter->surpriseremoved)
+ return -1;
+
+ if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+ lbs_dbg_hex("TX packet: ", skb->data,
+ min_t(unsigned int, skb->len, 100));
+
+ if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
+ lbs_pr_debug(1, "Tx error: Bad skb length %d : %d\n",
+ skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
+ ret = -1;
+ goto done;
+ }
+
+ memset(plocaltxpd, 0, sizeof(struct txpd));
+
+ plocaltxpd->tx_packet_length = skb->len;
+
+ /* offset of actual data */
+ plocaltxpd->tx_packet_location = sizeof(struct txpd);
+
+ /* TxCtrl set by user or default */
+ plocaltxpd->tx_control = adapter->pkttxctrl;
+
+ p802x_hdr = skb->data;
+ if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+
+ /* locate radiotap header */
+ pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
+
+ /* set txpd fields from the radiotap header */
+ new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
+ if (new_rate != 0) {
+ /* erase tx_control[4:0] */
+ plocaltxpd->tx_control &= ~0x1f;
+ /* write new tx_control[4:0] */
+ plocaltxpd->tx_control |= new_rate;
+ }
+
+ /* skip the radiotap header */
+ p802x_hdr += sizeof(struct tx_radiotap_hdr);
+ plocaltxpd->tx_packet_length -= sizeof(struct tx_radiotap_hdr);
+
+ }
+ /* copy destination address from 802.3 or 802.11 header */
+ if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+ memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
+ else
+ memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
+
+ lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
+
+ if (IS_MESH_FRAME(skb)) {
+ plocaltxpd->tx_control |= TxPD_MESH_FRAME;
+ }
+
+ memcpy(ptr, plocaltxpd, sizeof(struct txpd));
+
+ ptr += sizeof(struct txpd);
+
+ lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, plocaltxpd->tx_packet_length);
+ memcpy(ptr, p802x_hdr, plocaltxpd->tx_packet_length);
+ ret = libertas_sbi_host_to_card(priv, MVMS_DAT,
+ priv->adapter->tmptxbuf,
+ plocaltxpd->tx_packet_length +
+ sizeof(struct txpd));
+
+ if (ret) {
+ lbs_pr_debug(1, "Tx error: libertas_sbi_host_to_card failed: 0x%X\n", ret);
+ goto done;
+ }
+
+ lbs_pr_debug(1, "SendSinglePacket succeeds\n");
+
+ done:
+ if (!ret) {
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ } else {
+ priv->stats.tx_dropped++;
+ priv->stats.tx_errors++;
+ }
+
+ if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+ /* Keep the skb to echo it back once Tx feedback is
+ received from FW */
+ skb_orphan(skb);
+ /* stop processing outgoing pkts */
+ netif_stop_queue(priv->wlan_dev.netdev);
+ /* freeze any packets already in our queues */
+ priv->adapter->TxLockFlag = 1;
+ } else {
+ dev_kfree_skb_any(skb);
+ priv->adapter->currenttxskb = NULL;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+
+void libertas_tx_runqueue(wlan_private *priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i;
+
+ spin_lock(&adapter->txqueue_lock);
+ for (i = 0; i < adapter->tx_queue_idx; i++) {
+ struct sk_buff *skb = adapter->tx_queue_ps[i];
+ spin_unlock(&adapter->txqueue_lock);
+ SendSinglePacket(priv, skb);
+ spin_lock(&adapter->txqueue_lock);
+ }
+ adapter->tx_queue_idx = 0;
+ spin_unlock(&adapter->txqueue_lock);
+}
+
+static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ spin_lock(&adapter->txqueue_lock);
+
+ WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE);
+ adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb;
+ if (adapter->tx_queue_idx == NR_TX_QUEUE)
+ netif_stop_queue(priv->wlan_dev.netdev);
+ else
+ netif_start_queue(priv->wlan_dev.netdev);
+
+ spin_unlock(&adapter->txqueue_lock);
+}
+
+/**
+ * @brief This function checks the conditions and sends packet to IF
+ * layer if everything is ok.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return n/a
+ */
+int libertas_process_tx(wlan_private * priv, struct sk_buff *skb)
+{
+ int ret = -1;
+
+ ENTER();
+
+ lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+
+ if (priv->wlan_dev.dnld_sent) {
+ lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
+ priv->wlan_dev.dnld_sent);
+ goto done;
+ }
+
+ if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
+ (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) {
+ wlan_tx_queue(priv, skb);
+ return ret;
+ }
+
+ priv->adapter->currenttxskb = skb;
+
+ ret = SendSinglePacket(priv, skb);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends to the host the last transmitted packet,
+ * filling the radiotap headers with transmission information.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param status A 32 bit value containing transmission status.
+ *
+ * @returns void
+ */
+void libertas_send_tx_feedback(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct tx_radiotap_hdr *radiotap_hdr;
+ u32 status = adapter->eventcause;
+ int txfail;
+ int try_count;
+
+ if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP ||
+ adapter->currenttxskb == NULL)
+ return;
+
+ radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
+
+ if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+ lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr,
+ min_t(unsigned int, adapter->currenttxskb->len, 100));
+
+ txfail = (status >> 24);
+
+#if 0
+ /* The version of roofnet that we've tested does not use this yet
+ * But it may be used in the future.
+ */
+ if (txfail)
+ radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL;
+#endif
+ try_count = (status >> 16) & 0xff;
+ radiotap_hdr->data_retries = (try_count) ?
+ (1 + adapter->txretrycount - try_count) : 0;
+ libertas_upload_rx_packet(priv, adapter->currenttxskb);
+ adapter->currenttxskb = NULL;
+ priv->adapter->TxLockFlag = 0;
+ if (priv->adapter->connect_status == libertas_connected)
+ netif_wake_queue(priv->wlan_dev.netdev);
+}
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
new file mode 100644
index 000000000000..09d62f8b1a16
--- /dev/null
+++ b/drivers/net/wireless/libertas/types.h
@@ -0,0 +1,289 @@
+/**
+ * This header file contains definition for global types
+ */
+#ifndef _WLAN_TYPES_
+#define _WLAN_TYPES_
+
+#include <linux/if_ether.h>
+
+/** IEEE type definitions */
+enum ieeetypes_elementid {
+ SSID = 0,
+ SUPPORTED_RATES,
+ FH_PARAM_SET,
+ DS_PARAM_SET,
+ CF_PARAM_SET,
+ TIM,
+ IBSS_PARAM_SET,
+ COUNTRY_INFO = 7,
+
+ CHALLENGE_TEXT = 16,
+
+ EXTENDED_SUPPORTED_RATES = 50,
+
+ VENDOR_SPECIFIC_221 = 221,
+
+ WPA_IE = 221,
+ WPA2_IE = 48,
+
+ EXTRA_IE = 133,
+} __attribute__ ((packed));
+
+#define CAPINFO_MASK (~(0xda00))
+
+struct ieeetypes_capinfo {
+ u8 ess:1;
+ u8 ibss:1;
+ u8 cfpollable:1;
+ u8 cfpollrqst:1;
+ u8 privacy:1;
+ u8 shortpreamble:1;
+ u8 pbcc:1;
+ u8 chanagility:1;
+ u8 spectrummgmt:1;
+ u8 rsrvd3:1;
+ u8 shortslottime:1;
+ u8 apsd:1;
+ u8 rsvrd2:1;
+ u8 dsssofdm:1;
+ u8 rsrvd1:2;
+} __attribute__ ((packed));
+
+struct ieeetypes_cfparamset {
+ u8 elementid;
+ u8 len;
+ u8 cfpcnt;
+ u8 cfpperiod;
+ u16 cfpmaxduration;
+ u16 cfpdurationremaining;
+} __attribute__ ((packed));
+
+
+struct ieeetypes_ibssparamset {
+ u8 elementid;
+ u8 len;
+ u16 atimwindow;
+} __attribute__ ((packed));
+
+union IEEEtypes_ssparamset {
+ struct ieeetypes_cfparamset cfparamset;
+ struct ieeetypes_ibssparamset ibssparamset;
+} __attribute__ ((packed));
+
+struct ieeetypes_fhparamset {
+ u8 elementid;
+ u8 len;
+ u16 dwelltime;
+ u8 hopset;
+ u8 hoppattern;
+ u8 hopindex;
+} __attribute__ ((packed));
+
+struct ieeetypes_dsparamset {
+ u8 elementid;
+ u8 len;
+ u8 currentchan;
+} __attribute__ ((packed));
+
+union ieeetypes_phyparamset {
+ struct ieeetypes_fhparamset fhparamset;
+ struct ieeetypes_dsparamset dsparamset;
+} __attribute__ ((packed));
+
+struct ieeetypes_assocrsp {
+ struct ieeetypes_capinfo capability;
+ u16 statuscode;
+ u16 aid;
+ u8 iebuffer[1];
+} __attribute__ ((packed));
+
+/** TLV type ID definition */
+#define PROPRIETARY_TLV_BASE_ID 0x0100
+
+/* Terminating TLV type */
+#define MRVL_TERMINATE_TLV_ID 0xffff
+
+#define TLV_TYPE_SSID 0x0000
+#define TLV_TYPE_RATES 0x0001
+#define TLV_TYPE_PHY_FH 0x0002
+#define TLV_TYPE_PHY_DS 0x0003
+#define TLV_TYPE_CF 0x0004
+#define TLV_TYPE_IBSS 0x0006
+
+#define TLV_TYPE_DOMAIN 0x0007
+
+#define TLV_TYPE_POWER_CAPABILITY 0x0021
+
+#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
+#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
+#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2)
+#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4)
+#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5)
+#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6)
+#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7)
+#define TLV_TYPE_LED_GPIO (PROPRIETARY_TLV_BASE_ID + 8)
+#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9)
+#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10)
+#define TLV_TYPE_REASSOCAP (PROPRIETARY_TLV_BASE_ID + 11)
+#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12)
+#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13)
+#define TLV_TYPE_BCASTPROBE (PROPRIETARY_TLV_BASE_ID + 14)
+#define TLV_TYPE_NUMSSID_PROBE (PROPRIETARY_TLV_BASE_ID + 15)
+#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16)
+#define TLV_TYPE_CRYPTO_DATA (PROPRIETARY_TLV_BASE_ID + 17)
+#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
+#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
+#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
+#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
+
+/** TLV related data structures*/
+struct mrvlietypesheader {
+ u16 type;
+ u16 len;
+} __attribute__ ((packed));
+
+struct mrvlietypes_data {
+ struct mrvlietypesheader header;
+ u8 Data[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_ratesparamset {
+ struct mrvlietypesheader header;
+ u8 rates[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_ssidparamset {
+ struct mrvlietypesheader header;
+ u8 ssid[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_wildcardssidparamset {
+ struct mrvlietypesheader header;
+ u8 MaxSsidlength;
+ u8 ssid[1];
+} __attribute__ ((packed));
+
+struct chanscanmode {
+ u8 passivescan:1;
+ u8 disablechanfilt:1;
+ u8 reserved_2_7:6;
+} __attribute__ ((packed));
+
+struct chanscanparamset {
+ u8 radiotype;
+ u8 channumber;
+ struct chanscanmode chanscanmode;
+ u16 minscantime;
+ u16 maxscantime;
+} __attribute__ ((packed));
+
+struct mrvlietypes_chanlistparamset {
+ struct mrvlietypesheader header;
+ struct chanscanparamset chanscanparam[1];
+} __attribute__ ((packed));
+
+struct cfparamset {
+ u8 cfpcnt;
+ u8 cfpperiod;
+ u16 cfpmaxduration;
+ u16 cfpdurationremaining;
+} __attribute__ ((packed));
+
+struct ibssparamset {
+ u16 atimwindow;
+} __attribute__ ((packed));
+
+struct mrvlietypes_ssparamset {
+ struct mrvlietypesheader header;
+ union {
+ struct cfparamset cfparamset[1];
+ struct ibssparamset ibssparamset[1];
+ } cf_ibss;
+} __attribute__ ((packed));
+
+struct fhparamset {
+ u16 dwelltime;
+ u8 hopset;
+ u8 hoppattern;
+ u8 hopindex;
+} __attribute__ ((packed));
+
+struct dsparamset {
+ u8 currentchan;
+} __attribute__ ((packed));
+
+struct mrvlietypes_phyparamset {
+ struct mrvlietypesheader header;
+ union {
+ struct fhparamset fhparamset[1];
+ struct dsparamset dsparamset[1];
+ } fh_ds;
+} __attribute__ ((packed));
+
+struct mrvlietypes_rsnparamset {
+ struct mrvlietypesheader header;
+ u8 rsnie[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_tsftimestamp {
+ struct mrvlietypesheader header;
+ __le64 tsftable[1];
+} __attribute__ ((packed));
+
+/** Local Power capability */
+struct mrvlietypes_powercapability {
+ struct mrvlietypesheader header;
+ s8 minpower;
+ s8 maxpower;
+} __attribute__ ((packed));
+
+struct mrvlietypes_rssithreshold {
+ struct mrvlietypesheader header;
+ u8 rssivalue;
+ u8 rssifreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_snrthreshold {
+ struct mrvlietypesheader header;
+ u8 snrvalue;
+ u8 snrfreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_failurecount {
+ struct mrvlietypesheader header;
+ u8 failvalue;
+ u8 Failfreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_beaconsmissed {
+ struct mrvlietypesheader header;
+ u8 beaconmissed;
+ u8 reserved;
+} __attribute__ ((packed));
+
+struct mrvlietypes_numprobes {
+ struct mrvlietypesheader header;
+ u16 numprobes;
+} __attribute__ ((packed));
+
+struct mrvlietypes_bcastprobe {
+ struct mrvlietypesheader header;
+ u16 bcastprobe;
+} __attribute__ ((packed));
+
+struct mrvlietypes_numssidprobe {
+ struct mrvlietypesheader header;
+ u16 numssidprobe;
+} __attribute__ ((packed));
+
+struct led_pin {
+ u8 led;
+ u8 pin;
+} __attribute__ ((packed));
+
+struct mrvlietypes_ledgpio {
+ struct mrvlietypesheader header;
+ struct led_pin ledpin[1];
+} __attribute__ ((packed));
+
+#endif /* _WLAN_TYPES_ */
diff --git a/drivers/net/wireless/libertas/version.h b/drivers/net/wireless/libertas/version.h
new file mode 100644
index 000000000000..e86f65ae79b8
--- /dev/null
+++ b/drivers/net/wireless/libertas/version.h
@@ -0,0 +1,8 @@
+#define DRIVER_RELEASE_VERSION "320.p0"
+const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
+#ifdef DEBUG
+ "-dbg"
+#endif
+ "";
+
+
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
new file mode 100644
index 000000000000..4a52336bc0f6
--- /dev/null
+++ b/drivers/net/wireless/libertas/wext.c
@@ -0,0 +1,2769 @@
+/**
+ * This file contains ioctl functions
+ */
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/bitops.h>
+
+#include <net/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "version.h"
+#include "wext.h"
+#include "assoc.h"
+
+
+/**
+ * @brief Convert mw value to dbm value
+ *
+ * @param mw the value of mw
+ * @return the value of dbm
+ */
+static int mw_to_dbm(int mw)
+{
+ if (mw < 2)
+ return 0;
+ else if (mw < 3)
+ return 3;
+ else if (mw < 4)
+ return 5;
+ else if (mw < 6)
+ return 7;
+ else if (mw < 7)
+ return 8;
+ else if (mw < 8)
+ return 9;
+ else if (mw < 10)
+ return 10;
+ else if (mw < 13)
+ return 11;
+ else if (mw < 16)
+ return 12;
+ else if (mw < 20)
+ return 13;
+ else if (mw < 25)
+ return 14;
+ else if (mw < 32)
+ return 15;
+ else if (mw < 40)
+ return 16;
+ else if (mw < 50)
+ return 17;
+ else if (mw < 63)
+ return 18;
+ else if (mw < 79)
+ return 19;
+ else if (mw < 100)
+ return 20;
+ else
+ return 21;
+}
+
+/**
+ * @brief Find the channel frequency power info with specific channel
+ *
+ * @param adapter A pointer to wlan_adapter structure
+ * @param band it can be BAND_A, BAND_G or BAND_B
+ * @param channel the channel for looking
+ * @return A pointer to struct chan_freq_power structure or NULL if not find.
+ */
+struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
+ u8 band, u16 channel)
+{
+ struct chan_freq_power *cfp = NULL;
+ struct region_channel *rc;
+ int count = sizeof(adapter->region_channel) /
+ sizeof(adapter->region_channel[0]);
+ int i, j;
+
+ for (j = 0; !cfp && (j < count); j++) {
+ rc = &adapter->region_channel[j];
+
+ if (adapter->enable11d)
+ rc = &adapter->universal_channel[j];
+ if (!rc->valid || !rc->CFP)
+ continue;
+ if (rc->band != band)
+ continue;
+ for (i = 0; i < rc->nrcfp; i++) {
+ if (rc->CFP[i].channel == channel) {
+ cfp = &rc->CFP[i];
+ break;
+ }
+ }
+ }
+
+ if (!cfp && channel)
+ lbs_pr_debug(1, "libertas_find_cfp_by_band_and_channel(): cannot find "
+ "cfp by band %d & channel %d\n", band, channel);
+
+ return cfp;
+}
+
+/**
+ * @brief Find the channel frequency power info with specific frequency
+ *
+ * @param adapter A pointer to wlan_adapter structure
+ * @param band it can be BAND_A, BAND_G or BAND_B
+ * @param freq the frequency for looking
+ * @return A pointer to struct chan_freq_power structure or NULL if not find.
+ */
+static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
+ u8 band, u32 freq)
+{
+ struct chan_freq_power *cfp = NULL;
+ struct region_channel *rc;
+ int count = sizeof(adapter->region_channel) /
+ sizeof(adapter->region_channel[0]);
+ int i, j;
+
+ for (j = 0; !cfp && (j < count); j++) {
+ rc = &adapter->region_channel[j];
+
+ if (adapter->enable11d)
+ rc = &adapter->universal_channel[j];
+ if (!rc->valid || !rc->CFP)
+ continue;
+ if (rc->band != band)
+ continue;
+ for (i = 0; i < rc->nrcfp; i++) {
+ if (rc->CFP[i].freq == freq) {
+ cfp = &rc->CFP[i];
+ break;
+ }
+ }
+ }
+
+ if (!cfp && freq)
+ lbs_pr_debug(1, "find_cfp_by_band_and_freql(): cannot find cfp by "
+ "band %d & freq %d\n", band, freq);
+
+ return cfp;
+}
+
+static int updatecurrentchannel(wlan_private * priv)
+{
+ int ret;
+
+ /*
+ ** the channel in f/w could be out of sync, get the current channel
+ */
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+ cmd_opt_802_11_rf_channel_get,
+ cmd_option_waitforrsp, 0, NULL);
+
+ lbs_pr_debug(1, "Current channel = %d\n",
+ priv->adapter->curbssparams.channel);
+
+ return ret;
+}
+
+static int setcurrentchannel(wlan_private * priv, int channel)
+{
+ lbs_pr_debug(1, "Set channel = %d\n", channel);
+
+ /*
+ ** Current channel is not set to adhocchannel requested, set channel
+ */
+ return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+ cmd_opt_802_11_rf_channel_set,
+ cmd_option_waitforrsp, 0, &channel));
+}
+
+static int changeadhocchannel(wlan_private * priv, int channel)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ adapter->adhocchannel = channel;
+
+ updatecurrentchannel(priv);
+
+ if (adapter->curbssparams.channel == adapter->adhocchannel) {
+ /* adhocchannel is set to the current channel already */
+ LEAVE();
+ return 0;
+ }
+
+ lbs_pr_debug(1, "Updating channel from %d to %d\n",
+ adapter->curbssparams.channel, adapter->adhocchannel);
+
+ setcurrentchannel(priv, adapter->adhocchannel);
+
+ updatecurrentchannel(priv);
+
+ if (adapter->curbssparams.channel != adapter->adhocchannel) {
+ lbs_pr_debug(1, "failed to updated channel to %d, channel = %d\n",
+ adapter->adhocchannel, adapter->curbssparams.channel);
+ LEAVE();
+ return -1;
+ }
+
+ if (adapter->connect_status == libertas_connected) {
+ int i;
+ struct WLAN_802_11_SSID curadhocssid;
+
+ lbs_pr_debug(1, "channel Changed while in an IBSS\n");
+
+ /* Copy the current ssid */
+ memcpy(&curadhocssid, &adapter->curbssparams.ssid,
+ sizeof(struct WLAN_802_11_SSID));
+
+ /* Exit Adhoc mode */
+ lbs_pr_debug(1, "In changeadhocchannel(): Sending Adhoc Stop\n");
+ ret = libertas_stop_adhoc_network(priv);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ /* Scan for the network, do not save previous results. Stale
+ * scan data will cause us to join a non-existant adhoc network
+ */
+ libertas_send_specific_SSID_scan(priv, &curadhocssid, 0);
+
+ // find out the BSSID that matches the current SSID
+ i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
+ wlan802_11ibss);
+
+ if (i >= 0) {
+ lbs_pr_debug(1, "SSID found at %d in List,"
+ "so join\n", i);
+ libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+ } else {
+ // else send START command
+ lbs_pr_debug(1, "SSID not found in list, "
+ "so creating adhoc with ssid = %s\n",
+ curadhocssid.ssid);
+ libertas_start_adhoc_network(priv, &curadhocssid);
+ } // end of else (START command)
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set Radio On/OFF
+ *
+ * @param priv A pointer to wlan_private structure
+ * @option Radio Option
+ * @return 0 --success, otherwise fail
+ */
+int wlan_radio_ioctl(wlan_private * priv, u8 option)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (adapter->radioon != option) {
+ lbs_pr_debug(1, "Switching %s the Radio\n", option ? "On" : "Off");
+ adapter->radioon = option;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_radio_control,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Copy rates
+ *
+ * @param dest A pointer to Dest Buf
+ * @param src A pointer to Src Buf
+ * @param len The len of Src Buf
+ * @return Number of rates copyed
+ */
+static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
+ break;
+ dest[pos] = src[i];
+ }
+
+ return pos;
+}
+
+/**
+ * @brief Get active data rates
+ *
+ * @param adapter A pointer to wlan_adapter structure
+ * @param rate The buf to return the active rates
+ * @return The number of rates
+ */
+static int get_active_data_rates(wlan_adapter * adapter,
+ u8* rates)
+{
+ int k = 0;
+
+ ENTER();
+
+ if (adapter->connect_status != libertas_connected) {
+ if (adapter->inframode == wlan802_11infrastructure) {
+ //Infra. mode
+ lbs_pr_debug(1, "Infra\n");
+ k = copyrates(rates, k, libertas_supported_rates,
+ sizeof(libertas_supported_rates));
+ } else {
+ //ad-hoc mode
+ lbs_pr_debug(1, "Adhoc G\n");
+ k = copyrates(rates, k, libertas_adhoc_rates_g,
+ sizeof(libertas_adhoc_rates_g));
+ }
+ } else {
+ k = copyrates(rates, 0, adapter->curbssparams.datarates,
+ adapter->curbssparams.numofrates);
+ }
+
+ LEAVE();
+
+ return k;
+}
+
+static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
+ char *cwrq, char *extra)
+{
+ const char *cp;
+ char comm[6] = { "COMM-" };
+ char mrvl[6] = { "MRVL-" };
+ int cnt;
+
+ ENTER();
+
+ strcpy(cwrq, mrvl);
+
+ cp = strstr(libertas_driver_version, comm);
+ if (cp == libertas_driver_version) //skip leading "COMM-"
+ cp = libertas_driver_version + strlen(comm);
+ else
+ cp = libertas_driver_version;
+
+ cnt = strlen(mrvl);
+ cwrq += cnt;
+ while (cnt < 16 && (*cp != '-')) {
+ *cwrq++ = toupper(*cp++);
+ cnt++;
+ }
+ *cwrq = '\0';
+
+ LEAVE();
+
+ return 0;
+}
+
+static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct chan_freq_power *cfp;
+
+ ENTER();
+
+ cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
+ adapter->curbssparams.channel);
+
+ if (!cfp) {
+ if (adapter->curbssparams.channel)
+ lbs_pr_debug(1, "Invalid channel=%d\n",
+ adapter->curbssparams.channel);
+ return -EINVAL;
+ }
+
+ fwrq->m = (long)cfp->freq * 100000;
+ fwrq->e = 1;
+
+ lbs_pr_debug(1, "freq=%u\n", fwrq->m);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (adapter->connect_status == libertas_connected) {
+ memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+ } else {
+ memset(awrq->sa_data, 0, ETH_ALEN);
+ }
+ awrq->sa_family = ARPHRD_ETHER;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /*
+ * Check the size of the string
+ */
+
+ if (dwrq->length > 16) {
+ return -E2BIG;
+ }
+
+ mutex_lock(&adapter->lock);
+ memset(adapter->nodename, 0, sizeof(adapter->nodename));
+ memcpy(adapter->nodename, extra, dwrq->length);
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /*
+ * Get the Nick Name saved
+ */
+
+ mutex_lock(&adapter->lock);
+ strncpy(extra, adapter->nodename, 16);
+ mutex_unlock(&adapter->lock);
+
+ extra[16] = '\0';
+
+ /*
+ * If none, we may want to get the one that was set
+ */
+
+ /*
+ * Push it out !
+ */
+ dwrq->length = strlen(extra) + 1;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int rthr = vwrq->value;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
+ } else {
+ if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
+ return -EINVAL;
+ adapter->rtsthsd = rthr;
+ }
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+ cmd_act_set, cmd_option_waitforrsp,
+ OID_802_11_RTS_THRESHOLD, &rthr);
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ adapter->rtsthsd = 0;
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+ cmd_act_get, cmd_option_waitforrsp,
+ OID_802_11_RTS_THRESHOLD, NULL);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ vwrq->value = adapter->rtsthsd;
+ vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
+ || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
+ vwrq->fixed = 1;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ int fthr = vwrq->value;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
+ } else {
+ if (fthr < MRVDRV_FRAG_MIN_VALUE
+ || fthr > MRVDRV_FRAG_MAX_VALUE)
+ return -EINVAL;
+ adapter->fragthsd = fthr;
+ }
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+ cmd_act_set, cmd_option_waitforrsp,
+ OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ adapter->fragthsd = 0;
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_snmp_mib,
+ cmd_act_get, cmd_option_waitforrsp,
+ OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ vwrq->value = adapter->fragthsd;
+ vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
+ || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
+ vwrq->fixed = 1;
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_mode(struct net_device *dev,
+ struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ switch (adapter->inframode) {
+ case wlan802_11ibss:
+ *uwrq = IW_MODE_ADHOC;
+ break;
+
+ case wlan802_11infrastructure:
+ *uwrq = IW_MODE_INFRA;
+ break;
+
+ default:
+ case wlan802_11autounknown:
+ *uwrq = IW_MODE_AUTO;
+ break;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_txpow(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rf_tx_power,
+ cmd_act_tx_power_opt_get,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ lbs_pr_debug(1, "TXPOWER GET %d dbm.\n", adapter->txpowerlevel);
+ vwrq->value = adapter->txpowerlevel;
+ vwrq->fixed = 1;
+ if (adapter->radioon) {
+ vwrq->disabled = 0;
+ vwrq->flags = IW_TXPOW_DBM;
+ } else {
+ vwrq->disabled = 1;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (vwrq->flags == IW_RETRY_LIMIT) {
+ /* The MAC has a 4-bit Total_Tx_Count register
+ Total_Tx_Count = 1 + Tx_Retry_Count */
+#define TX_RETRY_MIN 0
+#define TX_RETRY_MAX 14
+ if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
+ return -EINVAL;
+
+ /* Adding 1 to convert retry count to try count */
+ adapter->txretrycount = vwrq->value + 1;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+ cmd_act_set,
+ cmd_option_waitforrsp,
+ OID_802_11_TX_RETRYCOUNT, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ } else {
+ return -EOPNOTSUPP;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+ adapter->txretrycount = 0;
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_snmp_mib,
+ cmd_act_get, cmd_option_waitforrsp,
+ OID_802_11_TX_RETRYCOUNT, NULL);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ vwrq->disabled = 0;
+ if (!vwrq->flags) {
+ vwrq->flags = IW_RETRY_LIMIT;
+ /* Subtract 1 to convert try count to retry count */
+ vwrq->value = adapter->txretrycount - 1;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static inline void sort_channels(struct iw_freq *freq, int num)
+{
+ int i, j;
+ struct iw_freq temp;
+
+ for (i = 0; i < num; i++)
+ for (j = i + 1; j < num; j++)
+ if (freq[i].i > freq[j].i) {
+ temp.i = freq[i].i;
+ temp.m = freq[i].m;
+
+ freq[i].i = freq[j].i;
+ freq[i].m = freq[j].m;
+
+ freq[j].i = temp.i;
+ freq[j].m = temp.m;
+ }
+}
+
+/* data rate listing
+ MULTI_BANDS:
+ abg a b b/g
+ Infra G(12) A(8) B(4) G(12)
+ Adhoc A+B(12) A(8) B(4) B(4)
+
+ non-MULTI_BANDS:
+ b b/g
+ Infra B(4) G(12)
+ Adhoc B(4) B(4)
+ */
+/**
+ * @brief Get Range Info
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int i, j;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct iw_range *range = (struct iw_range *)extra;
+ struct chan_freq_power *cfp;
+ u8 rates[WLAN_SUPPORTED_RATES];
+
+ u8 flag = 0;
+
+ ENTER();
+
+ dwrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->min_nwid = 0;
+ range->max_nwid = 0;
+
+ memset(rates, 0, sizeof(rates));
+ range->num_bitrates = get_active_data_rates(adapter, rates);
+
+ for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
+ i++) {
+ range->bitrate[i] = (rates[i] & 0x7f) * 500000;
+ }
+ range->num_bitrates = i;
+ lbs_pr_debug(1, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+ range->num_bitrates);
+
+ range->num_frequency = 0;
+ if (priv->adapter->enable11d &&
+ adapter->connect_status == libertas_connected) {
+ u8 chan_no;
+ u8 band;
+
+ struct parsed_region_chan_11d *parsed_region_chan =
+ &adapter->parsed_region_chan;
+
+ if (parsed_region_chan == NULL) {
+ lbs_pr_debug(1, "11D:parsed_region_chan is NULL\n");
+ LEAVE();
+ return 0;
+ }
+ band = parsed_region_chan->band;
+ lbs_pr_debug(1, "band=%d NoOfChan=%d\n", band,
+ parsed_region_chan->nr_chan);
+
+ for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+ && (i < parsed_region_chan->nr_chan); i++) {
+ chan_no = parsed_region_chan->chanpwr[i].chan;
+ lbs_pr_debug(1, "chan_no=%d\n", chan_no);
+ range->freq[range->num_frequency].i = (long)chan_no;
+ range->freq[range->num_frequency].m =
+ (long)libertas_chan_2_freq(chan_no, band) * 100000;
+ range->freq[range->num_frequency].e = 1;
+ range->num_frequency++;
+ }
+ flag = 1;
+ }
+ if (!flag) {
+ for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+ && (j < sizeof(adapter->region_channel)
+ / sizeof(adapter->region_channel[0])); j++) {
+ cfp = adapter->region_channel[j].CFP;
+ for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+ && adapter->region_channel[j].valid
+ && cfp
+ && (i < adapter->region_channel[j].nrcfp); i++) {
+ range->freq[range->num_frequency].i =
+ (long)cfp->channel;
+ range->freq[range->num_frequency].m =
+ (long)cfp->freq * 100000;
+ range->freq[range->num_frequency].e = 1;
+ cfp++;
+ range->num_frequency++;
+ }
+ }
+ }
+
+ lbs_pr_debug(1, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+ IW_MAX_FREQUENCIES, range->num_frequency);
+
+ range->num_channels = range->num_frequency;
+
+ sort_channels(&range->freq[0], range->num_frequency);
+
+ /*
+ * Set an indication of the max TCP throughput in bit/s that we can
+ * expect using this interface
+ */
+ if (i > 2)
+ range->throughput = 5000 * 1000;
+ else
+ range->throughput = 1500 * 1000;
+
+ range->min_rts = MRVDRV_RTS_MIN_VALUE;
+ range->max_rts = MRVDRV_RTS_MAX_VALUE;
+ range->min_frag = MRVDRV_FRAG_MIN_VALUE;
+ range->max_frag = MRVDRV_FRAG_MAX_VALUE;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = 4;
+
+ range->min_pmp = 1000000;
+ range->max_pmp = 120000000;
+ range->min_pmt = 1000;
+ range->max_pmt = 1000000;
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+ /*
+ * Minimum version we recommend
+ */
+ range->we_version_source = 15;
+
+ /*
+ * Version we are compiled with
+ */
+ range->we_version_compiled = WIRELESS_EXT;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+ range->min_retry = TX_RETRY_MIN;
+ range->max_retry = TX_RETRY_MAX;
+
+ /*
+ * Set the qual, level and noise range values
+ */
+ range->max_qual.qual = 100;
+ range->max_qual.level = 0;
+ range->max_qual.noise = 0;
+ range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+
+ range->avg_qual.qual = 70;
+ /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
+ range->avg_qual.level = 0;
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+
+ range->sensitivity = 0;
+
+ /*
+ * Setup the supported power level ranges
+ */
+ memset(range->txpower, 0, sizeof(range->txpower));
+ range->txpower[0] = 5;
+ range->txpower[1] = 7;
+ range->txpower[2] = 9;
+ range->txpower[3] = 11;
+ range->txpower[4] = 13;
+ range->txpower[5] = 15;
+ range->txpower[6] = 17;
+ range->txpower[7] = 19;
+
+ range->num_txpower = 8;
+ range->txpower_capa = IW_TXPOW_DBM;
+ range->txpower_capa |= IW_TXPOW_RANGE;
+
+ range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+ IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+ IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+ range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
+ if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
+ range->enc_capa = IW_ENC_CAPA_WPA
+ | IW_ENC_CAPA_WPA2
+ | IW_ENC_CAPA_CIPHER_TKIP
+ | IW_ENC_CAPA_CIPHER_CCMP;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* PS is currently supported only in Infrastructure mode
+ * Remove this check if it is to be supported in IBSS mode also
+ */
+
+ if (vwrq->disabled) {
+ adapter->psmode = wlan802_11powermodecam;
+ if (adapter->psstate != PS_STATE_FULL_POWER) {
+ libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+ }
+
+ return 0;
+ }
+
+ if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+ lbs_pr_debug(1,
+ "Setting power timeout command is not supported\n");
+ return -EINVAL;
+ } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+ lbs_pr_debug(1, "Setting power period command is not supported\n");
+ return -EINVAL;
+ }
+
+ if (adapter->psmode != wlan802_11powermodecam) {
+ return 0;
+ }
+
+ adapter->psmode = wlan802_11powermodemax_psp;
+
+ if (adapter->connect_status == libertas_connected) {
+ libertas_ps_sleep(priv, cmd_option_waitforrsp);
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int mode;
+
+ ENTER();
+
+ mode = adapter->psmode;
+
+ if ((vwrq->disabled = (mode == wlan802_11powermodecam))
+ || adapter->connect_status == libertas_disconnected) {
+ LEAVE();
+ return 0;
+ }
+
+ vwrq->value = 0;
+
+ LEAVE();
+ return 0;
+}
+
+/*
+ * iwpriv settable callbacks
+ */
+
+static const iw_handler wlan_private_handler[] = {
+ NULL, /* SIOCIWFIRSTPRIV */
+};
+
+static const struct iw_priv_args wlan_private_args[] = {
+ /*
+ * { cmd, set_args, get_args, name }
+ */
+ {
+ WLANSCAN_TYPE,
+ IW_PRIV_TYPE_CHAR | 8,
+ IW_PRIV_TYPE_CHAR | 8,
+ "scantype"},
+
+ {
+ WLAN_SETINT_GETINT,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ ""},
+ {
+ WLANNF,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getNF"},
+ {
+ WLANRSSI,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getRSSI"},
+ {
+ WLANENABLE11D,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "enable11d"},
+ {
+ WLANADHOCGRATE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "adhocgrate"},
+
+ {
+ WLAN_SUBCMD_SET_PRESCAN,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "prescan"},
+ {
+ WLAN_SETONEINT_GETONEINT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ ""},
+ {
+ WLAN_BEACON_INTERVAL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "bcninterval"},
+ {
+ WLAN_LISTENINTRVL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "lolisteninter"},
+ {
+ WLAN_TXCONTROL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "txcontrol"},
+ {
+ WLAN_NULLPKTINTERVAL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "psnullinterval"},
+ /* Using iwpriv sub-command feature */
+ {
+ WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ ""},
+
+ {
+ WLAN_SUBCMD_SETRXANTENNA,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setrxant"},
+ {
+ WLAN_SUBCMD_SETTXANTENNA,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "settxant"},
+ {
+ WLANSETAUTHALG,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "authalgs",
+ },
+ {
+ WLANSET8021XAUTHALG,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "8021xauthalgs",
+ },
+ {
+ WLANSETENCRYPTIONMODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "encryptionmode",
+ },
+ {
+ WLANSETREGION,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setregioncode"},
+ {
+ WLAN_SET_LISTEN_INTERVAL,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setlisteninter"},
+ {
+ WLAN_SET_MULTIPLE_DTIM,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setmultipledtim"},
+ {
+ WLAN_SET_ATIM_WINDOW,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "atimwindow"},
+ {
+ WLANSETBCNAVG,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setbcnavg"},
+ {
+ WLANSETDATAAVG,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setdataavg"},
+ {
+ WLAN_SET_LINKMODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "linkmode"},
+ {
+ WLAN_SET_RADIOMODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "radiomode"},
+ {
+ WLAN_SET_DEBUGMODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "debugmode"},
+ {
+ WLAN_SUBCMD_MESH_SET_TTL,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "mesh_set_ttl"},
+ {
+ WLAN_SETNONE_GETONEINT,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ ""},
+ {
+ WLANGETREGION,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getregioncode"},
+ {
+ WLAN_GET_LISTEN_INTERVAL,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getlisteninter"},
+ {
+ WLAN_GET_MULTIPLE_DTIM,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getmultipledtim"},
+ {
+ WLAN_GET_TX_RATE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "gettxrate"},
+ {
+ WLANGETBCNAVG,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getbcnavg"},
+ {
+ WLAN_GET_LINKMODE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_linkmode"},
+ {
+ WLAN_GET_RADIOMODE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_radiomode"},
+ {
+ WLAN_GET_DEBUGMODE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_debugmode"},
+ {
+ WLAN_SUBCMD_FWT_CLEANUP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "fwt_cleanup"},
+ {
+ WLAN_SUBCMD_FWT_TIME,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "fwt_time"},
+ {
+ WLAN_SUBCMD_MESH_GET_TTL,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "mesh_get_ttl"},
+ {
+ WLAN_SETNONE_GETTWELVE_CHAR,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ ""},
+ {
+ WLAN_SUBCMD_GETRXANTENNA,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ "getrxant"},
+ {
+ WLAN_SUBCMD_GETTXANTENNA,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ "gettxant"},
+ {
+ WLAN_GET_TSF,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ "gettsf"},
+ {
+ WLAN_SETNONE_GETNONE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ ""},
+ {
+ WLANDEAUTH,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "deauth"},
+ {
+ WLANADHOCSTOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "adhocstop"},
+ {
+ WLANRADIOON,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "radioon"},
+ {
+ WLANRADIOOFF,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "radiooff"},
+ {
+ WLANWLANIDLEON,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "wlanidle-on"},
+ {
+ WLANWLANIDLEOFF,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "wlanidle-off"},
+ {
+ WLAN_SUBCMD_FWT_RESET,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "fwt_reset"},
+ {
+ WLAN_SUBCMD_BT_RESET,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "bt_reset"},
+ {
+ WLAN_SET128CHAR_GET128CHAR,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ ""},
+ /* BT Management */
+ {
+ WLAN_SUBCMD_BT_ADD,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "bt_add"},
+ {
+ WLAN_SUBCMD_BT_DEL,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "bt_del"},
+ {
+ WLAN_SUBCMD_BT_LIST,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "bt_list"},
+ /* FWT Management */
+ {
+ WLAN_SUBCMD_FWT_ADD,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_add"},
+ {
+ WLAN_SUBCMD_FWT_DEL,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_del"},
+ {
+ WLAN_SUBCMD_FWT_LOOKUP,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_lookup"},
+ {
+ WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_list_neigh"},
+ {
+ WLAN_SUBCMD_FWT_LIST,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_list"},
+ {
+ WLAN_SUBCMD_FWT_LIST_ROUTE,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_list_route"},
+ {
+ WLANSCAN_MODE,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "scanmode"},
+ {
+ WLAN_GET_ADHOC_STATUS,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "getadhocstatus"},
+ {
+ WLAN_SETNONE_GETWORDCHAR,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 128,
+ ""},
+ {
+ WLANSETWPAIE,
+ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24,
+ IW_PRIV_TYPE_NONE,
+ "setwpaie"},
+ {
+ WLANGETLOG,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
+ "getlog"},
+ {
+ WLAN_SET_GET_SIXTEEN_INT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ ""},
+ {
+ WLAN_TPCCFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "tpccfg"},
+ {
+ WLAN_POWERCFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "powercfg"},
+ {
+ WLAN_AUTO_FREQ_SET,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "setafc"},
+ {
+ WLAN_AUTO_FREQ_GET,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getafc"},
+ {
+ WLAN_SCANPROBES,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "scanprobes"},
+ {
+ WLAN_LED_GPIO_CTRL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "ledgpio"},
+ {
+ WLAN_ADAPT_RATESET,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "rateadapt"},
+ {
+ WLAN_INACTIVITY_TIMEOUT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "inactivityto"},
+ {
+ WLANSNR,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getSNR"},
+ {
+ WLAN_GET_RATE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getrate"},
+ {
+ WLAN_GET_RXINFO,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getrxinfo"},
+};
+
+static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
+{
+ enum {
+ POOR = 30,
+ FAIR = 60,
+ GOOD = 80,
+ VERY_GOOD = 90,
+ EXCELLENT = 95,
+ PERFECT = 100
+ };
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ u32 rssi_qual;
+ u32 tx_qual;
+ u32 quality = 0;
+ int stats_valid = 0;
+ u8 rssi;
+ u32 tx_retries;
+
+ ENTER();
+
+ priv->wstats.status = adapter->inframode;
+
+ /* If we're not associated, all quality values are meaningless */
+ if (adapter->connect_status != libertas_connected)
+ goto out;
+
+ /* Quality by RSSI */
+ priv->wstats.qual.level =
+ CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+ adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+ if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+ priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ } else {
+ priv->wstats.qual.noise =
+ CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+ }
+
+ lbs_pr_debug(1, "Signal Level = %#x\n", priv->wstats.qual.level);
+ lbs_pr_debug(1, "Noise = %#x\n", priv->wstats.qual.noise);
+
+ rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
+ if (rssi < 15)
+ rssi_qual = rssi * POOR / 10;
+ else if (rssi < 20)
+ rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
+ else if (rssi < 30)
+ rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
+ else if (rssi < 40)
+ rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
+ 10 + GOOD;
+ else
+ rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
+ 10 + VERY_GOOD;
+ quality = rssi_qual;
+
+ /* Quality by TX errors */
+ priv->wstats.discard.retries = priv->stats.tx_errors;
+
+ tx_retries = adapter->logmsg.retry;
+
+ if (tx_retries > 75)
+ tx_qual = (90 - tx_retries) * POOR / 15;
+ else if (tx_retries > 70)
+ tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
+ else if (tx_retries > 65)
+ tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
+ else if (tx_retries > 50)
+ tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
+ 15 + GOOD;
+ else
+ tx_qual = (50 - tx_retries) *
+ (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
+ quality = min(quality, tx_qual);
+
+ priv->wstats.discard.code = adapter->logmsg.wepundecryptable;
+ priv->wstats.discard.fragment = adapter->logmsg.fcserror;
+ priv->wstats.discard.retries = tx_retries;
+ priv->wstats.discard.misc = adapter->logmsg.ackfailure;
+
+ /* Calculate quality */
+ priv->wstats.qual.qual = max(quality, (u32)100);
+ priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+ stats_valid = 1;
+
+ /* update stats asynchronously for future calls */
+ libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
+ 0, 0, NULL);
+ libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
+ 0, 0, NULL);
+out:
+ if (!stats_valid) {
+ priv->wstats.miss.beacon = 0;
+ priv->wstats.discard.retries = 0;
+ priv->wstats.qual.qual = 0;
+ priv->wstats.qual.level = 0;
+ priv->wstats.qual.noise = 0;
+ priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
+ priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
+ IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+ }
+
+ LEAVE ();
+ return &priv->wstats;
+
+
+}
+
+static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int rc = -EINPROGRESS; /* Call commit handler */
+ struct chan_freq_power *cfp;
+
+ ENTER();
+
+ /*
+ * If setting by frequency, convert to a channel
+ */
+ if (fwrq->e == 1) {
+
+ long f = fwrq->m / 100000;
+ int c = 0;
+
+ cfp = find_cfp_by_band_and_freq(adapter, 0, f);
+ if (!cfp) {
+ lbs_pr_debug(1, "Invalid freq=%ld\n", f);
+ return -EINVAL;
+ }
+
+ c = (int)cfp->channel;
+
+ if (c < 0)
+ return -EINVAL;
+
+ fwrq->e = 0;
+ fwrq->m = c;
+ }
+
+ /*
+ * Setting by channel number
+ */
+ if (fwrq->m > 1000 || fwrq->e > 0) {
+ rc = -EOPNOTSUPP;
+ } else {
+ int channel = fwrq->m;
+
+ cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
+ if (!cfp) {
+ rc = -EINVAL;
+ } else {
+ if (adapter->inframode == wlan802_11ibss) {
+ rc = changeadhocchannel(priv, channel);
+ /* If station is WEP enabled, send the
+ * command to set WEP in firmware
+ */
+ if (adapter->secinfo.WEPstatus ==
+ wlan802_11WEPenabled) {
+ lbs_pr_debug(1, "set_freq: WEP enabled\n");
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_set_wep,
+ cmd_act_add,
+ cmd_option_waitforrsp,
+ 0,
+ NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ adapter->currentpacketfilter |=
+ cmd_act_mac_wep_enable;
+
+ libertas_set_mac_packet_filter(priv);
+ }
+ } else {
+ rc = -EOPNOTSUPP;
+ }
+ }
+ }
+
+ LEAVE();
+ return rc;
+}
+
+/**
+ * @brief use index to get the data rate
+ *
+ * @param index The index of data rate
+ * @return data rate or 0
+ */
+u32 libertas_index_to_data_rate(u8 index)
+{
+ if (index >= sizeof(libertas_wlan_data_rates))
+ index = 0;
+
+ return libertas_wlan_data_rates[index];
+}
+
+/**
+ * @brief use rate to get the index
+ *
+ * @param rate data rate
+ * @return index or 0
+ */
+u8 libertas_data_rate_to_index(u32 rate)
+{
+ u8 *ptr;
+
+ if (rate)
+ if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
+ sizeof(libertas_wlan_data_rates))))
+ return (ptr - libertas_wlan_data_rates);
+
+ return 0;
+}
+
+static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ u32 data_rate;
+ u16 action;
+ int ret = 0;
+ u8 rates[WLAN_SUPPORTED_RATES];
+ u8 *rate;
+
+ ENTER();
+
+ lbs_pr_debug(1, "Vwrq->value = %d\n", vwrq->value);
+
+ if (vwrq->value == -1) {
+ action = cmd_act_set_tx_auto; // Auto
+ adapter->is_datarate_auto = 1;
+ adapter->datarate = 0;
+ } else {
+ if (vwrq->value % 100000) {
+ return -EINVAL;
+ }
+
+ data_rate = vwrq->value / 500000;
+
+ memset(rates, 0, sizeof(rates));
+ get_active_data_rates(adapter, rates);
+ rate = rates;
+ while (*rate) {
+ lbs_pr_debug(1, "Rate=0x%X Wanted=0x%X\n", *rate,
+ data_rate);
+ if ((*rate & 0x7f) == (data_rate & 0x7f))
+ break;
+ rate++;
+ }
+ if (!*rate) {
+ lbs_pr_alert( "The fixed data rate 0x%X is out "
+ "of range.\n", data_rate);
+ return -EINVAL;
+ }
+
+ adapter->datarate = data_rate;
+ action = cmd_act_set_tx_fix_rate;
+ adapter->is_datarate_auto = 0;
+ }
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+ action, cmd_option_waitforrsp, 0, NULL);
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (adapter->is_datarate_auto) {
+ vwrq->fixed = 0;
+ } else {
+ vwrq->fixed = 1;
+ }
+
+ vwrq->value = adapter->datarate * 500000;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_mode(struct net_device *dev,
+ struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct assoc_request * assoc_req;
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
+
+ ENTER();
+
+ switch (*uwrq) {
+ case IW_MODE_ADHOC:
+ lbs_pr_debug(1, "Wanted mode is ad-hoc: current datarate=%#x\n",
+ adapter->datarate);
+ new_mode = wlan802_11ibss;
+ adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
+ break;
+
+ case IW_MODE_INFRA:
+ lbs_pr_debug(1, "Wanted mode is Infrastructure\n");
+ new_mode = wlan802_11infrastructure;
+ break;
+
+ case IW_MODE_AUTO:
+ lbs_pr_debug(1, "Wanted mode is Auto\n");
+ new_mode = wlan802_11autounknown;
+ break;
+
+ default:
+ lbs_pr_debug(1, "Wanted mode is Unknown: 0x%x\n", *uwrq);
+ return -EINVAL;
+ }
+
+ mutex_lock(&adapter->lock);
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ } else {
+ assoc_req->mode = new_mode;
+ }
+
+ if (ret == 0) {
+ set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ } else {
+ wlan_cancel_association_work(priv);
+ }
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+
+/**
+ * @brief Get Encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_get_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, u8 * extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+ ENTER();
+
+ lbs_pr_debug(1, "flags=0x%x index=%d length=%d wep_tx_keyidx=%d\n",
+ dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
+
+ dwrq->flags = 0;
+
+ /* Authentication method */
+ switch (adapter->secinfo.authmode) {
+ case wlan802_11authmodeopen:
+ dwrq->flags = IW_ENCODE_OPEN;
+ break;
+
+ case wlan802_11authmodeshared:
+ case wlan802_11authmodenetworkEAP:
+ dwrq->flags = IW_ENCODE_RESTRICTED;
+ break;
+ default:
+ dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+ break;
+ }
+
+ if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
+ || adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else {
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ }
+
+ memset(extra, 0, 16);
+
+ mutex_lock(&adapter->lock);
+
+ /* Default to returning current transmit key */
+ if (index < 0)
+ index = adapter->wep_tx_keyidx;
+
+ if ((adapter->wep_keys[index].len) &&
+ (adapter->secinfo.WEPstatus == wlan802_11WEPenabled)) {
+ memcpy(extra, adapter->wep_keys[index].key,
+ adapter->wep_keys[index].len);
+ dwrq->length = adapter->wep_keys[index].len;
+
+ dwrq->flags |= (index + 1);
+ /* Return WEP enabled */
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else if ((adapter->secinfo.WPAenabled)
+ || (adapter->secinfo.WPA2enabled)) {
+ /* return WPA enabled */
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else {
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ }
+
+ mutex_unlock(&adapter->lock);
+
+ dwrq->flags |= IW_ENCODE_NOKEY;
+
+ lbs_pr_debug(1, "key:%02x:%02x:%02x:%02x:%02x:%02x keylen=%d\n",
+ extra[0], extra[1], extra[2],
+ extra[3], extra[4], extra[5], dwrq->length);
+
+ lbs_pr_debug(1, "Return flags=0x%x\n", dwrq->flags);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set Encryption key (internal)
+ *
+ * @param priv A pointer to private card structure
+ * @param key_material A pointer to key material
+ * @param key_length length of key material
+ * @param index key index to set
+ * @param set_tx_key Force set TX key (1 = yes, 0 = no)
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_wep_key(struct assoc_request *assoc_req,
+ const char *key_material,
+ u16 key_length,
+ u16 index,
+ int set_tx_key)
+{
+ struct WLAN_802_11_KEY *pkey;
+
+ ENTER();
+
+ /* Paranoid validation of key index */
+ if (index > 3) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ /* validate max key length */
+ if (key_length > KEY_LEN_WEP_104) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ pkey = &assoc_req->wep_keys[index];
+
+ if (key_length > 0) {
+ memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+ pkey->type = KEY_TYPE_ID_WEP;
+
+ /* Standardize the key length */
+ pkey->len = (key_length > KEY_LEN_WEP_40) ?
+ KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
+ memcpy(pkey->key, key_material, key_length);
+ }
+
+ if (set_tx_key) {
+ /* Ensure the chosen key is valid */
+ if (!pkey->len) {
+ lbs_pr_debug(1, "key not set, so cannot enable it\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ assoc_req->wep_tx_keyidx = index;
+ }
+
+ assoc_req->secinfo.WEPstatus = wlan802_11WEPenabled;
+
+ LEAVE();
+ return 0;
+}
+
+static int validate_key_index(u16 def_index, u16 raw_index,
+ u16 *out_index, u16 *is_default)
+{
+ if (!out_index || !is_default)
+ return -EINVAL;
+
+ /* Verify index if present, otherwise use default TX key index */
+ if (raw_index > 0) {
+ if (raw_index > 4)
+ return -EINVAL;
+ *out_index = raw_index - 1;
+ } else {
+ *out_index = def_index;
+ *is_default = 1;
+ }
+ return 0;
+}
+
+static void disable_wep(struct assoc_request *assoc_req)
+{
+ int i;
+
+ /* Set Open System auth mode */
+ assoc_req->secinfo.authmode = wlan802_11authmodeopen;
+
+ /* Clear WEP keys and mark WEP as disabled */
+ assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ for (i = 0; i < 4; i++)
+ assoc_req->wep_keys[i].len = 0;
+
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+ set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+}
+
+/**
+ * @brief Set Encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct assoc_request * assoc_req;
+ u16 is_default = 0, index = 0, set_tx_key = 0;
+
+ ENTER();
+
+ mutex_lock(&adapter->lock);
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (dwrq->flags & IW_ENCODE_DISABLED) {
+ disable_wep (assoc_req);
+ goto out;
+ }
+
+ ret = validate_key_index(assoc_req->wep_tx_keyidx,
+ (dwrq->flags & IW_ENCODE_INDEX),
+ &index, &is_default);
+ if (ret) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* If WEP isn't enabled, or if there is no key data but a valid
+ * index, set the TX key.
+ */
+ if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
+ || (dwrq->length == 0 && !is_default))
+ set_tx_key = 1;
+
+ ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
+ if (ret)
+ goto out;
+
+ if (dwrq->length)
+ set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+ if (set_tx_key)
+ set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+
+ if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+ assoc_req->secinfo.authmode = wlan802_11authmodeshared;
+ } else if (dwrq->flags & IW_ENCODE_OPEN) {
+ assoc_req->secinfo.authmode = wlan802_11authmodeopen;
+ }
+
+out:
+ if (ret == 0) {
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ } else {
+ wlan_cancel_association_work(priv);
+ }
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Extended Encryption key (WPA/802.1x and WEP)
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 on success, otherwise failure
+ */
+static int wlan_get_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ int ret = -EINVAL;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int index, max_key_len;
+
+ ENTER();
+
+ max_key_len = dwrq->length - sizeof(*ext);
+ if (max_key_len < 0)
+ goto out;
+
+ index = dwrq->flags & IW_ENCODE_INDEX;
+ if (index) {
+ if (index < 1 || index > 4)
+ goto out;
+ index--;
+ } else {
+ index = adapter->wep_tx_keyidx;
+ }
+
+ if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
+ ext->alg != IW_ENCODE_ALG_WEP) {
+ if (index != 0 || adapter->inframode != wlan802_11infrastructure)
+ goto out;
+ }
+
+ dwrq->flags = index + 1;
+ memset(ext, 0, sizeof(*ext));
+
+ if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled)
+ && !adapter->secinfo.WPAenabled && !adapter->secinfo.WPA2enabled) {
+ ext->alg = IW_ENCODE_ALG_NONE;
+ ext->key_len = 0;
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ } else {
+ u8 *key = NULL;
+
+ if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
+ && !adapter->secinfo.WPAenabled
+ && !adapter->secinfo.WPA2enabled) {
+ ext->alg = IW_ENCODE_ALG_WEP;
+ ext->key_len = adapter->wep_keys[index].len;
+ key = &adapter->wep_keys[index].key[0];
+ } else if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) &&
+ (adapter->secinfo.WPAenabled ||
+ adapter->secinfo.WPA2enabled)) {
+ /* WPA */
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ ext->key_len = 0;
+ } else {
+ goto out;
+ }
+
+ if (ext->key_len > max_key_len) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+ if (ext->key_len)
+ memcpy(ext->key, key, ext->key_len);
+ else
+ dwrq->flags |= IW_ENCODE_NOKEY;
+ dwrq->flags |= IW_ENCODE_ENABLED;
+ }
+ ret = 0;
+
+out:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Encryption key Extended (WPA/802.1x and WEP)
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int alg = ext->alg;
+ struct assoc_request * assoc_req;
+
+ ENTER();
+
+ mutex_lock(&adapter->lock);
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
+ disable_wep (assoc_req);
+ } else if (alg == IW_ENCODE_ALG_WEP) {
+ u16 is_default = 0, index, set_tx_key = 0;
+
+ ret = validate_key_index(assoc_req->wep_tx_keyidx,
+ (dwrq->flags & IW_ENCODE_INDEX),
+ &index, &is_default);
+ if (ret)
+ goto out;
+
+ /* If WEP isn't enabled, or if there is no key data but a valid
+ * index, or if the set-TX-key flag was passed, set the TX key.
+ */
+ if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
+ || (dwrq->length == 0 && !is_default)
+ || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
+ set_tx_key = 1;
+
+ /* Copy key to driver */
+ ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
+ set_tx_key);
+ if (ret)
+ goto out;
+
+ if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeshared;
+ } else if (dwrq->flags & IW_ENCODE_OPEN) {
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeopen;
+ }
+
+ /* Mark the various WEP bits as modified */
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+ if (dwrq->length)
+ set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+ if (set_tx_key)
+ set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+
+ } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
+ struct WLAN_802_11_KEY * pkey;
+
+ /* validate key length */
+ if (((alg == IW_ENCODE_ALG_TKIP)
+ && (ext->key_len != KEY_LEN_WPA_TKIP))
+ || ((alg == IW_ENCODE_ALG_CCMP)
+ && (ext->key_len != KEY_LEN_WPA_AES))) {
+ lbs_pr_debug(1, "Invalid size %d for key of alg"
+ "type %d.\n",
+ ext->key_len,
+ alg);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+ pkey = &assoc_req->wpa_mcast_key;
+ else
+ pkey = &assoc_req->wpa_unicast_key;
+
+ memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
+ memcpy(pkey->key, ext->key, ext->key_len);
+ pkey->len = ext->key_len;
+ pkey->flags = KEY_INFO_WPA_ENABLED;
+
+ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+ pkey->flags |= KEY_INFO_WPA_MCAST;
+ set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
+ } else {
+ pkey->flags |= KEY_INFO_WPA_UNICAST;
+ set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+ }
+
+ if (alg == IW_ENCODE_ALG_TKIP)
+ pkey->type = KEY_TYPE_ID_TKIP;
+ else if (alg == IW_ENCODE_ALG_CCMP)
+ pkey->type = KEY_TYPE_ID_AES;
+
+ /* If WPA isn't enabled yet, do that now */
+ if ( assoc_req->secinfo.WPAenabled == 0
+ && assoc_req->secinfo.WPA2enabled == 0) {
+ assoc_req->secinfo.WPAenabled = 1;
+ assoc_req->secinfo.WPA2enabled = 1;
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+ }
+
+ disable_wep (assoc_req);
+ }
+
+out:
+ if (ret == 0) {
+ wlan_postpone_association_work(priv);
+ } else {
+ wlan_cancel_association_work(priv);
+ }
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+
+static int wlan_set_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct assoc_request * assoc_req;
+
+ ENTER();
+
+ mutex_lock(&adapter->lock);
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (dwrq->length > MAX_WPA_IE_LEN ||
+ (dwrq->length && extra == NULL)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (dwrq->length) {
+ memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
+ assoc_req->wpa_ie_len = dwrq->length;
+ } else {
+ memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
+ assoc_req->wpa_ie_len = 0;
+ }
+
+out:
+ if (ret == 0) {
+ set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ } else {
+ wlan_cancel_association_work(priv);
+ }
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (adapter->wpa_ie_len == 0) {
+ dwrq->length = 0;
+ LEAVE();
+ return 0;
+ }
+
+ if (dwrq->length < adapter->wpa_ie_len) {
+ LEAVE();
+ return -E2BIG;
+ }
+
+ dwrq->length = adapter->wpa_ie_len;
+ memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
+
+ LEAVE();
+ return 0;
+}
+
+
+static int wlan_set_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *dwrq,
+ char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct assoc_request * assoc_req;
+ int ret = 0;
+ int updated = 0;
+
+ ENTER();
+
+ mutex_lock(&adapter->lock);
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ switch (dwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_KEY_MGMT:
+ /*
+ * libertas does not use these parameters
+ */
+ break;
+
+ case IW_AUTH_WPA_VERSION:
+ if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
+ assoc_req->secinfo.WPAenabled = 0;
+ assoc_req->secinfo.WPA2enabled = 0;
+ }
+ if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
+ assoc_req->secinfo.WPAenabled = 1;
+ assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeopen;
+ }
+ if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
+ assoc_req->secinfo.WPA2enabled = 1;
+ assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeopen;
+ }
+ updated = 1;
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ if (dwrq->value) {
+ adapter->currentpacketfilter |=
+ cmd_act_mac_strict_protection_enable;
+ } else {
+ adapter->currentpacketfilter &=
+ ~cmd_act_mac_strict_protection_enable;
+ }
+ updated = 1;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeshared;
+ } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeopen;
+ } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodenetworkEAP;
+ } else {
+ ret = -EINVAL;
+ }
+ updated = 1;
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ if (dwrq->value) {
+ if (!assoc_req->secinfo.WPAenabled &&
+ !assoc_req->secinfo.WPA2enabled) {
+ assoc_req->secinfo.WPAenabled = 1;
+ assoc_req->secinfo.WPA2enabled = 1;
+ assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeopen;
+ }
+ } else {
+ assoc_req->secinfo.WPAenabled = 0;
+ assoc_req->secinfo.WPA2enabled = 0;
+ }
+ updated = 1;
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+out:
+ if (ret == 0) {
+ if (updated)
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ } else if (ret != -EOPNOTSUPP) {
+ wlan_cancel_association_work(priv);
+ }
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *dwrq,
+ char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ switch (dwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ dwrq->value = 0;
+ if (adapter->secinfo.WPAenabled)
+ dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
+ if (adapter->secinfo.WPA2enabled)
+ dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
+ if (!dwrq->value)
+ dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ dwrq->value = 0;
+ if (adapter->currentpacketfilter &
+ cmd_act_mac_strict_protection_enable)
+ dwrq->value = 1;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ switch (adapter->secinfo.authmode) {
+ case wlan802_11authmodeshared:
+ dwrq->value = IW_AUTH_ALG_SHARED_KEY;
+ break;
+ case wlan802_11authmodeopen:
+ dwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ break;
+ case wlan802_11authmodenetworkEAP:
+ dwrq->value = IW_AUTH_ALG_LEAP;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
+ dwrq->value = 1;
+ break;
+
+ default:
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+
+static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ u16 dbm;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ wlan_radio_ioctl(priv, RADIO_OFF);
+ return 0;
+ }
+
+ adapter->preamble = cmd_type_auto_preamble;
+
+ wlan_radio_ioctl(priv, RADIO_ON);
+
+ if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
+ dbm = (u16) mw_to_dbm(vwrq->value);
+ } else
+ dbm = (u16) vwrq->value;
+
+ /* auto tx power control */
+
+ if (vwrq->fixed == 0)
+ dbm = 0xffff;
+
+ lbs_pr_debug(1, "<1>TXPOWER SET %d dbm.\n", dbm);
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rf_tx_power,
+ cmd_act_tx_power_opt_set_low,
+ cmd_option_waitforrsp, 0, (void *)&dbm);
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+ /*
+ * Note : if dwrq->flags != 0, we should get the relevant SSID from
+ * the SSID list...
+ */
+
+ /*
+ * Get the current SSID
+ */
+ if (adapter->connect_status == libertas_connected) {
+ memcpy(extra, adapter->curbssparams.ssid.ssid,
+ adapter->curbssparams.ssid.ssidlength);
+ extra[adapter->curbssparams.ssid.ssidlength] = '\0';
+ } else {
+ memset(extra, 0, 32);
+ extra[adapter->curbssparams.ssid.ssidlength] = '\0';
+ }
+ /*
+ * If none, we may want to get the one that was set
+ */
+
+ /* To make the driver backward compatible with WPA supplicant v0.2.4 */
+ if (dwrq->length == 32) /* check with WPA supplicant buffer size */
+ dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength,
+ IW_ESSID_MAX_SIZE);
+ else
+ dwrq->length = adapter->curbssparams.ssid.ssidlength + 1;
+
+ dwrq->flags = 1; /* active */
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct WLAN_802_11_SSID ssid;
+ struct assoc_request * assoc_req;
+ int ssid_len = dwrq->length;
+
+ ENTER();
+
+ /*
+ * WE-20 and earlier NULL pad the end of the SSID and increment
+ * SSID length so it can be used like a string. WE-21 and later don't,
+ * but some userspace tools aren't able to cope with the change.
+ */
+ if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
+ ssid_len--;
+
+ /* Check the size of the string */
+ if (ssid_len > IW_ESSID_MAX_SIZE) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+ memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
+
+ if (!dwrq->flags || !ssid_len) {
+ /* "any" SSID requested; leave SSID blank */
+ } else {
+ /* Specific SSID requested */
+ memcpy(&ssid.ssid, extra, ssid_len);
+ ssid.ssidlength = ssid_len;
+ }
+
+ lbs_pr_debug(1, "Requested new SSID = %s\n",
+ (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
+
+out:
+ mutex_lock(&adapter->lock);
+ if (ret == 0) {
+ /* Get or create the current association request */
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ } else {
+ /* Copy the SSID to the association request */
+ memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
+ set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ }
+ }
+
+ /* Cancel the association request if there was an error */
+ if (ret != 0) {
+ wlan_cancel_association_work(priv);
+ }
+
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Connect to the AP or Ad-hoc Network with specific bssid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct assoc_request * assoc_req;
+ int ret = 0;
+
+ ENTER();
+
+ if (awrq->sa_family != ARPHRD_ETHER)
+ return -EINVAL;
+
+ lbs_pr_debug(1, "ASSOC: WAP: sa_data: " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
+
+ mutex_lock(&adapter->lock);
+
+ /* Get or create the current association request */
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ wlan_cancel_association_work(priv);
+ ret = -ENOMEM;
+ } else {
+ /* Copy the BSSID to the association request */
+ memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
+ set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ }
+
+ mutex_unlock(&adapter->lock);
+
+ return ret;
+}
+
+void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
+{
+ union {
+ u32 l;
+ u8 c[4];
+ } ver;
+ char fwver[32];
+
+ mutex_lock(&adapter->lock);
+ ver.l = adapter->fwreleasenumber;
+ mutex_unlock(&adapter->lock);
+
+ if (ver.c[3] == 0)
+ sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
+ else
+ sprintf(fwver, "%u.%u.%u.p%u",
+ ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+ snprintf(fwversion, maxlen, fwver);
+}
+
+
+/*
+ * iwconfig settable callbacks
+ */
+static const iw_handler wlan_handler[] = {
+ (iw_handler) NULL, /* SIOCSIWCOMMIT */
+ (iw_handler) wlan_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
+ (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
+ (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+ (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
+ (iw_handler) NULL, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* SIOCGIWSTATS */
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+ (iw_handler) wlan_set_wap, /* SIOCSIWAP */
+ (iw_handler) wlan_get_wap, /* SIOCGIWAP */
+ (iw_handler) NULL, /* SIOCSIWMLME */
+ (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
+ (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
+ (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
+ (iw_handler) wlan_set_essid, /* SIOCSIWESSID */
+ (iw_handler) wlan_get_essid, /* SIOCGIWESSID */
+ (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
+ (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
+ (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
+ (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
+ (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
+ (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
+ (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
+ (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
+ (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
+ (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
+ (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
+ (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
+ (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
+ (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
+ (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
+ (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
+ (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
+ (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
+ (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
+ (iw_handler) NULL, /* SIOCSIWPMKSA */
+};
+
+struct iw_handler_def libertas_handler_def = {
+ .num_standard = sizeof(wlan_handler) / sizeof(iw_handler),
+ .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler),
+ .num_private_args = sizeof(wlan_private_args) /
+ sizeof(struct iw_priv_args),
+ .standard = (iw_handler *) wlan_handler,
+ .private = (iw_handler *) wlan_private_handler,
+ .private_args = (struct iw_priv_args *)wlan_private_args,
+ .get_wireless_stats = wlan_get_wireless_stats,
+};
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
new file mode 100644
index 000000000000..39f367c38d90
--- /dev/null
+++ b/drivers/net/wireless/libertas/wext.h
@@ -0,0 +1,147 @@
+/**
+ * This file contains definition for IOCTL call.
+ */
+#ifndef _WLAN_WEXT_H_
+#define _WLAN_WEXT_H_
+
+#define SUBCMD_OFFSET 4
+#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET))
+
+/** PRIVATE CMD ID */
+#define WLANIOCTL SIOCIWFIRSTPRIV
+
+#define WLANSETWPAIE (WLANIOCTL + 0)
+
+#define WLAN_SETINT_GETINT (WLANIOCTL + 7)
+#define WLANNF 1
+#define WLANRSSI 2
+#define WLANENABLE11D 5
+#define WLANADHOCGRATE 6
+#define WLAN_SUBCMD_SET_PRESCAN 11
+
+#define WLAN_SETNONE_GETNONE (WLANIOCTL + 8)
+#define WLANDEAUTH 1
+#define WLANRADIOON 2
+#define WLANRADIOOFF 3
+#define WLANREMOVEADHOCAES 4
+#define WLANADHOCSTOP 5
+#define WLANCIPHERTEST 6
+#define WLANCRYPTOTEST 7
+
+#define WLANWLANIDLEON 10
+#define WLANWLANIDLEOFF 11
+#define WLAN_SUBCMD_BT_RESET 13
+#define WLAN_SUBCMD_FWT_RESET 14
+
+#define WLANGETLOG (WLANIOCTL + 9)
+#define GETLOG_BUFSIZE 300
+
+#define WLANSCAN_TYPE (WLANIOCTL + 11)
+
+#define WLAN_SETNONE_GETONEINT (WLANIOCTL + 15)
+#define WLANGETREGION 1
+#define WLAN_GET_LISTEN_INTERVAL 2
+#define WLAN_GET_MULTIPLE_DTIM 3
+#define WLAN_GET_TX_RATE 4
+#define WLANGETBCNAVG 5
+
+#define WLAN_GET_LINKMODE 6
+#define WLAN_GET_RADIOMODE 7
+#define WLAN_GET_DEBUGMODE 8
+#define WLAN_SUBCMD_FWT_CLEANUP 15
+#define WLAN_SUBCMD_FWT_TIME 16
+#define WLAN_SUBCMD_MESH_GET_TTL 17
+
+#define WLANREGCFRDWR (WLANIOCTL + 18)
+
+#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19)
+#define WLAN_SUBCMD_GETRXANTENNA 1
+#define WLAN_SUBCMD_GETTXANTENNA 2
+#define WLAN_GET_TSF 3
+
+#define WLAN_SETNONE_GETWORDCHAR (WLANIOCTL + 21)
+#define WLANGETADHOCAES 1
+
+#define WLAN_SETONEINT_GETONEINT (WLANIOCTL + 23)
+#define WLAN_BEACON_INTERVAL 1
+#define WLAN_LISTENINTRVL 4
+
+#define WLAN_TXCONTROL 6
+#define WLAN_NULLPKTINTERVAL 7
+
+#define WLAN_SETONEINT_GETNONE (WLANIOCTL + 24)
+#define WLAN_SUBCMD_SETRXANTENNA 1
+#define WLAN_SUBCMD_SETTXANTENNA 2
+#define WLANSETAUTHALG 5
+#define WLANSET8021XAUTHALG 6
+#define WLANSETENCRYPTIONMODE 7
+#define WLANSETREGION 8
+#define WLAN_SET_LISTEN_INTERVAL 9
+
+#define WLAN_SET_MULTIPLE_DTIM 10
+#define WLAN_SET_ATIM_WINDOW 11
+#define WLANSETBCNAVG 13
+#define WLANSETDATAAVG 14
+#define WLAN_SET_LINKMODE 15
+#define WLAN_SET_RADIOMODE 16
+#define WLAN_SET_DEBUGMODE 17
+#define WLAN_SUBCMD_MESH_SET_TTL 18
+
+#define WLAN_SET128CHAR_GET128CHAR (WLANIOCTL + 25)
+#define WLANSCAN_MODE 6
+
+#define WLAN_GET_ADHOC_STATUS 9
+
+#define WLAN_SUBCMD_BT_ADD 18
+#define WLAN_SUBCMD_BT_DEL 19
+#define WLAN_SUBCMD_BT_LIST 20
+#define WLAN_SUBCMD_FWT_ADD 21
+#define WLAN_SUBCMD_FWT_DEL 22
+#define WLAN_SUBCMD_FWT_LOOKUP 23
+#define WLAN_SUBCMD_FWT_LIST_NEIGHBOR 24
+#define WLAN_SUBCMD_FWT_LIST 25
+#define WLAN_SUBCMD_FWT_LIST_ROUTE 26
+
+#define WLAN_SET_GET_SIXTEEN_INT (WLANIOCTL + 29)
+#define WLAN_TPCCFG 1
+#define WLAN_POWERCFG 2
+
+#define WLAN_AUTO_FREQ_SET 3
+#define WLAN_AUTO_FREQ_GET 4
+#define WLAN_LED_GPIO_CTRL 5
+#define WLAN_SCANPROBES 6
+#define WLAN_ADAPT_RATESET 8
+#define WLAN_INACTIVITY_TIMEOUT 9
+#define WLANSNR 10
+#define WLAN_GET_RATE 11
+#define WLAN_GET_RXINFO 12
+
+#define WLANCMD52RDWR (WLANIOCTL + 30)
+#define WLANCMD53RDWR (WLANIOCTL + 31)
+#define CMD53BUFLEN 32
+
+#define REG_MAC 0x19
+#define REG_BBP 0x1a
+#define REG_RF 0x1b
+#define REG_EEPROM 0x59
+#define WLAN_LINKMODE_802_3 0
+#define WLAN_LINKMODE_802_11 2
+#define WLAN_RADIOMODE_NONE 0
+#define WLAN_RADIOMODE_RADIOTAP 2
+
+/** wlan_ioctl_regrdwr */
+struct wlan_ioctl_regrdwr {
+ /** Which register to access */
+ u16 whichreg;
+ /** Read or Write */
+ u16 action;
+ u32 offset;
+ u16 NOB;
+ u32 value;
+};
+
+extern struct iw_handler_def libertas_handler_def;
+int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+int wlan_radio_ioctl(wlan_private * priv, u8 option);
+
+#endif /* _WLAN_WEXT_H_ */
diff --git a/drivers/net/wireless/todo.txt b/drivers/net/wireless/todo.txt
deleted file mode 100644
index 32234018de72..000000000000
--- a/drivers/net/wireless/todo.txt
+++ /dev/null
@@ -1,15 +0,0 @@
- Wireless Todo
- -------------
-
-1) Bring other kernel Wireless LAN drivers here
- Completed
-
-2) Bring new Wireless LAN driver not yet in the kernel there
- See my web page for details
- In particular : HostAP
-
-3) Misc
- o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete
- o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete
-
- Jean II
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 87ee3ee020fe..95b4a2a26707 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -67,11 +67,12 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " ");
i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
- i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type,
+ i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type,
chip->patch_cck_gain ? 'g' : '-',
chip->patch_cr157 ? '7' : '-',
chip->patch_6m_band_edge ? '6' : '-',
- chip->new_phy_layout ? 'N' : '-');
+ chip->new_phy_layout ? 'N' : '-',
+ chip->al2230s_bit ? 'S' : '-');
return i;
}
@@ -114,7 +115,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
/* Allocate a single memory block for values and addresses. */
count16 = 2*count;
a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
- GFP_NOFS);
+ GFP_KERNEL);
if (!a16) {
dev_dbg_f(zd_chip_dev(chip),
"error ENOMEM in allocation of a16\n");
@@ -163,7 +164,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
/* Allocate a single memory block for values and addresses. */
count16 = 2*count;
- ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS);
+ ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_KERNEL);
if (!ioreqs16) {
r = -ENOMEM;
dev_dbg_f(zd_chip_dev(chip),
@@ -614,16 +615,24 @@ static int patch_cr157(struct zd_chip *chip)
* Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge
* bit (for AL2230, AL2230S)
*/
-static int patch_6m_band_edge(struct zd_chip *chip, int channel)
+static int patch_6m_band_edge(struct zd_chip *chip, u8 channel)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ if (!chip->patch_6m_band_edge)
+ return 0;
+
+ return zd_rf_patch_6m_band_edge(&chip->rf, channel);
+}
+
+/* Generic implementation of 6M band edge patching, used by most RFs via
+ * zd_rf_generic_patch_6m() */
+int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel)
{
struct zd_ioreq16 ioreqs[] = {
{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
{ CR47, 0x1e },
};
- if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge)
- return 0;
-
/* FIXME: Channel 11 is not the edge for all regulatory domains. */
if (channel == 1 || channel == 11)
ioreqs[0].value = 0x12;
@@ -683,17 +692,17 @@ static int zd1211_hw_reset_phy(struct zd_chip *chip)
{ CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
{ CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
{ CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f },
- { CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 },
- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 },
- { CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 },
- { CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c },
- { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c },
- { CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 },
- { CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa },
- { CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea },
- { CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a },
- { CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba },
+ { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 },
+ { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C },
+ { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 },
+ { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 },
+ { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c },
+ { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 },
+ { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe },
+ { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
+ { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
+ { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
+ { CR170, 0xba }, { CR171, 0xba },
/* Note: CR204 must lead the CR203 */
{ CR204, 0x7d },
{ },
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index e57ed75d9425..ce0a5f6da0d2 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -833,6 +833,7 @@ int zd_chip_enable_rx(struct zd_chip *chip);
void zd_chip_disable_rx(struct zd_chip *chip);
int zd_chip_enable_hwint(struct zd_chip *chip);
int zd_chip_disable_hwint(struct zd_chip *chip);
+int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel);
int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
u8 rts_rate, int preamble);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 4c5f78eac349..6753d240c168 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -156,17 +156,8 @@ void zd_mac_clear(struct zd_mac *mac)
static int reset_mode(struct zd_mac *mac)
{
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
- struct zd_ioreq32 ioreqs[] = {
- { CR_RX_FILTER, STA_RX_FILTER },
- { CR_SNIFFER_ON, 0U },
- };
-
- if (ieee->iw_mode == IW_MODE_MONITOR) {
- ioreqs[0].value = 0xffffffff;
- ioreqs[1].value = 0x1;
- }
-
- return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
+ u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
+ return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
}
int zd_mac_open(struct net_device *netdev)
@@ -974,14 +965,14 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
switch (ieee->iw_mode) {
case IW_MODE_ADHOC:
if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
- memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0)
+ compare_ether_addr(hdr->addr3, ieee->bssid) != 0)
return 0;
break;
case IW_MODE_AUTO:
case IW_MODE_INFRA:
if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
IEEE80211_FCTL_FROMDS ||
- memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0)
+ compare_ether_addr(hdr->addr2, ieee->bssid) != 0)
return 0;
break;
default:
@@ -989,9 +980,9 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
return 0;
}
- return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
+ return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 ||
(is_multicast_ether_addr(hdr->addr1) &&
- memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) ||
+ compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) ||
(netdev->flags & IFF_PROMISC);
}
@@ -1047,7 +1038,7 @@ static void update_qual_rssi(struct zd_mac *mac,
hdr = (struct ieee80211_hdr_3addr *)buffer;
if (length < offsetof(struct ieee80211_hdr_3addr, addr3))
return;
- if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0)
+ if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0)
return;
spin_lock_irqsave(&mac->lock, flags);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index f50cff3db916..549c23bcd6cc 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -23,7 +23,7 @@
#include "zd_ieee80211.h"
#include "zd_chip.h"
-static const char *rfs[] = {
+static const char * const rfs[] = {
[0] = "unknown RF0",
[1] = "unknown RF1",
[UW2451_RF] = "UW2451_RF",
@@ -34,7 +34,7 @@ static const char *rfs[] = {
[AL2210_RF] = "AL2210_RF",
[MAXIM_NEW_RF] = "MAXIM_NEW_RF",
[UW2453_RF] = "UW2453_RF",
- [AL2230S_RF] = "AL2230S_RF",
+ [UNKNOWN_A_RF] = "UNKNOWN_A_RF",
[RALINK_RF] = "RALINK_RF",
[INTERSIL_RF] = "INTERSIL_RF",
[RF2959_RF] = "RF2959_RF",
@@ -154,3 +154,17 @@ int zd_switch_radio_off(struct zd_rf *rf)
r = t;
return r;
}
+
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel)
+{
+ if (!rf->patch_6m_band_edge)
+ return 0;
+
+ return rf->patch_6m_band_edge(rf, channel);
+}
+
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel)
+{
+ return zd_chip_generic_patch_6m_band(zd_rf_to_chip(rf), channel);
+}
+
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index a57732eb69e1..aa9cc105ce60 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -26,7 +26,7 @@
#define AL2210_RF 0x7
#define MAXIM_NEW_RF 0x8
#define UW2453_RF 0x9
-#define AL2230S_RF 0xa
+#define UNKNOWN_A_RF 0xa
#define RALINK_RF 0xb
#define INTERSIL_RF 0xc
#define RF2959_RF 0xd
@@ -47,17 +47,13 @@ struct zd_rf {
u8 type;
u8 channel;
- /*
- * Whether this RF should patch the 6M band edge
- * (assuming E2P_POD agrees)
- */
- u8 patch_6m_band_edge:1;
/* RF-specific functions */
int (*init_hw)(struct zd_rf *rf);
int (*set_channel)(struct zd_rf *rf, u8 channel);
int (*switch_radio_on)(struct zd_rf *rf);
int (*switch_radio_off)(struct zd_rf *rf);
+ int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel);
};
const char *zd_rf_name(u8 type);
@@ -72,6 +68,9 @@ int zd_rf_set_channel(struct zd_rf *rf, u8 channel);
int zd_switch_radio_on(struct zd_rf *rf);
int zd_switch_radio_off(struct zd_rf *rf);
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel);
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel);
+
/* Functions for individual RF chips */
int zd_rf_init_rf2959(struct zd_rf *rf);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 5235a7827ac5..511392acfedf 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -59,6 +59,18 @@ static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
{ CR240, 0x57 }, { CR9, 0xe0 },
};
+static const struct zd_ioreq16 ioreqs_init_al2230s[] = {
+ { CR47, 0x1e }, /* MARK_002 */
+ { CR106, 0x22 },
+ { CR107, 0x2a }, /* MARK_002 */
+ { CR109, 0x13 }, /* MARK_002 */
+ { CR118, 0xf8 }, /* MARK_002 */
+ { CR119, 0x12 }, { CR122, 0xe0 },
+ { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */
+ { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */
+ { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */
+};
+
static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
{
int r;
@@ -90,7 +102,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
int r;
struct zd_chip *chip = zd_rf_to_chip(rf);
- static const struct zd_ioreq16 ioreqs[] = {
+ static const struct zd_ioreq16 ioreqs_init[] = {
{ CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
{ CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
{ CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a },
@@ -117,10 +129,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
{ CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 },
{ CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff },
{ CR253, 0xff },
+ };
- /* These following happen separately in the vendor driver */
- { },
-
+ static const struct zd_ioreq16 ioreqs_pll[] = {
/* shdnb(PLL_ON)=0 */
{ CR251, 0x2f },
/* shdnb(PLL_ON)=1 */
@@ -128,7 +139,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
{ CR138, 0x28 }, { CR203, 0x06 },
};
- static const u32 rv[] = {
+ static const u32 rv1[] = {
/* Channel 1 */
0x03f790,
0x033331,
@@ -137,6 +148,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
0x0b3331,
0x03b812,
0x00fff3,
+ };
+
+ static const u32 rv2[] = {
0x000da4,
0x0f4dc5, /* fix freq shift, 0x04edc5 */
0x0805b6,
@@ -148,8 +162,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
0x0bdffc,
0x00000d,
0x00500f,
+ };
- /* These writes happen separately in the vendor driver */
+ static const u32 rv3[] = {
0x00d00f,
0x004c0f,
0x00540f,
@@ -157,11 +172,38 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
0x00500f,
};
- r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ r = zd_iowrite16a_locked(chip, ioreqs_init, ARRAY_SIZE(ioreqs_init));
if (r)
return r;
- r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+ if (chip->al2230s_bit) {
+ r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
+ ARRAY_SIZE(ioreqs_init_al2230s));
+ if (r)
+ return r;
+ }
+
+ r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+ if (r)
+ return r;
+
+ /* improve band edge for AL2230S */
+ if (chip->al2230s_bit)
+ r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS);
+ else
+ r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS);
+ if (r)
+ return r;
+
+ r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+ if (r)
+ return r;
+
+ r = zd_iowrite16a_locked(chip, ioreqs_pll, ARRAY_SIZE(ioreqs_pll));
+ if (r)
+ return r;
+
+ r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
if (r)
return r;
@@ -227,7 +269,9 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
0x481dc0,
0xcfff00,
0x25a000,
+ };
+ static const u32 rv2[] = {
/* To improve AL2230 yield, improve phase noise, 4713 */
0x25a000,
0xa3b2f0,
@@ -250,7 +294,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
{ CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
};
- static const u32 rv2[] = {
+ static const u32 rv3[] = {
/* To improve AL2230 yield, 4713 */
0xf01b00,
0xf01e00,
@@ -269,18 +313,37 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
if (r)
return r;
+
+ if (chip->al2230s_bit) {
+ r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
+ ARRAY_SIZE(ioreqs_init_al2230s));
+ if (r)
+ return r;
+ }
+
r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3);
if (r)
return r;
r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1));
if (r)
return r;
- r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+
+ if (chip->al2230s_bit)
+ r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS);
+ else
+ r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS);
if (r)
return r;
+
r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2));
if (r)
return r;
+ r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+ if (r)
+ return r;
+ r = zd_rfwritev_cr_locked(chip, rv3, ARRAY_SIZE(rv3));
+ if (r)
+ return r;
r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
if (r)
return r;
@@ -358,12 +421,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
- if (chip->al2230s_bit) {
- dev_err(zd_chip_dev(chip), "AL2230S devices are not yet "
- "supported by this driver.\n");
- return -ENODEV;
- }
-
rf->switch_radio_off = al2230_switch_radio_off;
if (chip->is_zd1211b) {
rf->init_hw = zd1211b_al2230_init_hw;
@@ -374,6 +431,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
rf->set_channel = zd1211_al2230_set_channel;
rf->switch_radio_on = zd1211_al2230_switch_radio_on;
}
- rf->patch_6m_band_edge = 1;
+ rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
index a289f95187ec..5e5e9ddc6a74 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -51,9 +51,52 @@ static const u32 std_rv[] = {
0xd8c010,
};
-static int al7230b_init_hw(struct zd_rf *rf)
+static const u32 rv_init1[] = {
+ 0x3c9000,
+ 0xbfffff,
+ 0x700000,
+ 0xf15d58,
+};
+
+static const u32 rv_init2[] = {
+ 0xf15d59,
+ 0xf15d5c,
+ 0xf15d58,
+};
+
+static const struct zd_ioreq16 ioreqs_sw[] = {
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR38, 0x38 }, { CR136, 0xdf },
+};
+
+static int zd1211b_al7230b_finalize(struct zd_chip *chip)
{
- int i, r;
+ int r;
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 },
+ { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 },
+ { CR203, 0x04 },
+ { },
+ { CR240, 0x80 },
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ if (chip->new_phy_layout) {
+ /* antenna selection? */
+ r = zd_iowrite16_locked(chip, 0xe5, CR9);
+ if (r)
+ return r;
+ }
+
+ return zd_iowrite16_locked(chip, 0x04, CR203);
+}
+
+static int zd1211_al7230b_init_hw(struct zd_rf *rf)
+{
+ int r;
struct zd_chip *chip = zd_rf_to_chip(rf);
/* All of these writes are identical to AL2230 unless otherwise
@@ -117,39 +160,136 @@ static int al7230b_init_hw(struct zd_rf *rf)
};
static const struct zd_ioreq16 ioreqs_2[] = {
- /* PLL_ON */
- { CR251, 0x3f },
+ { CR251, 0x3f }, /* PLL_ON */
{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR38, 0x38 }, { CR136, 0xdf },
+ { CR38, 0x38 }, { CR136, 0xdf },
};
r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0x09ec04);
+ r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0]));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0x8cccc8);
+
+ r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
if (r)
return r;
- for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
- r = zd_rfwrite_cr_locked(chip, std_rv[i]);
- if (r)
- return r;
- }
+ r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1));
+ if (r)
+ return r;
- r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0xbfffff);
+
+ r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0x700000);
+
+ r = zd_iowrite16_locked(chip, 0x06, CR203);
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+ r = zd_iowrite16_locked(chip, 0x80, CR240);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int zd1211b_al7230b_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs_1[] = {
+ { CR240, 0x57 }, { CR9, 0x9 },
+ { },
+ { CR10, 0x8b }, { CR15, 0x20 },
+ { CR17, 0x2B }, /* for newest (3rd cut) AL2230 */
+ { CR20, 0x10 }, /* 4N25->Stone Request */
+ { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 },
+ { CR28, 0x3e }, { CR29, 0x00 },
+ { CR33, 0x28 }, /* 5613 */
+ { CR34, 0x30 },
+ { CR35, 0x3e }, /* for newest (3rd cut) AL2230 */
+ { CR41, 0x24 }, { CR44, 0x32 },
+ { CR46, 0x99 }, /* for newest (3rd cut) AL2230 */
+ { CR47, 0x1e },
+
+ /* ZD1215 5610 */
+ { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 },
+ { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 },
+ { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 },
+ { CR69, 0x28 },
+
+ { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
+ { CR87, 0x0A }, { CR89, 0x04 },
+ { CR90, 0x58 }, /* 5112 */
+ { CR91, 0x00 }, /* 5613 */
+ { CR92, 0x0a },
+ { CR98, 0x8d }, /* 4804, for 1212 new algorithm */
+ { CR99, 0x00 }, { CR100, 0x02 }, { CR101, 0x13 },
+ { CR102, 0x27 },
+ { CR106, 0x20 }, /* change to 0x24 for AL7230B */
+ { CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+ { CR112, 0x1f },
+ };
+
+ static const struct zd_ioreq16 ioreqs_new_phy[] = {
+ { CR107, 0x28 },
+ { CR110, 0x1f }, /* 5127, 0x13->0x1f */
+ { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */
+ { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 },
+ { CR121, 0x6c }, /* 5613 */
+ };
+
+ static const struct zd_ioreq16 ioreqs_old_phy[] = {
+ { CR107, 0x24 },
+ { CR110, 0x13 }, /* 5127, 0x13->0x1f */
+ { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */
+ { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 },
+ { CR121, 0x6a }, /* 5613 */
+ };
+
+ static const struct zd_ioreq16 ioreqs_2[] = {
+ { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 },
+ { CR117, 0xfa }, { CR120, 0x4f },
+ { CR122, 0xfc }, /* E0->FCh at 4901 */
+ { CR123, 0x57 }, /* 5613 */
+ { CR125, 0xad }, /* 4804, for 1212 new algorithm */
+ { CR126, 0x6c }, /* 5613 */
+ { CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+ { CR130, 0x10 },
+ { CR131, 0x00 }, /* 5112 */
+ { CR137, 0x50 }, /* 5613 */
+ { CR138, 0xa8 }, /* 5112 */
+ { CR144, 0xac }, /* 5613 */
+ { CR148, 0x40 }, /* 5112 */
+ { CR149, 0x40 }, /* 4O07, 50->40 */
+ { CR150, 0x1a }, /* 5112, 0C->1A */
+ { CR252, 0x34 }, { CR253, 0x34 },
+ { CR251, 0x2f }, /* PLL_OFF */
+ };
+
+ static const struct zd_ioreq16 ioreqs_3[] = {
+ { CR251, 0x7f }, /* PLL_ON */
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR38, 0x38 }, { CR136, 0xdf },
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+ if (r)
+ return r;
+
+ if (chip->new_phy_layout)
+ r = zd_iowrite16a_locked(chip, ioreqs_new_phy,
+ ARRAY_SIZE(ioreqs_new_phy));
+ else
+ r = zd_iowrite16a_locked(chip, ioreqs_old_phy,
+ ARRAY_SIZE(ioreqs_old_phy));
if (r)
return r;
@@ -157,38 +297,36 @@ static int al7230b_init_hw(struct zd_rf *rf)
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0xf15d59);
+ r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0]));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0xf15d5c);
+
+ r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+
+ r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1));
if (r)
return r;
- r = zd_iowrite16_locked(chip, 0x06, CR203);
+ r = zd_iowrite16a_locked(chip, ioreqs_3, ARRAY_SIZE(ioreqs_3));
if (r)
return r;
- r = zd_iowrite16_locked(chip, 0x80, CR240);
+
+ r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2));
if (r)
return r;
- return 0;
+ return zd1211b_al7230b_finalize(chip);
}
-static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
+static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel)
{
- int i, r;
+ int r;
const u32 *rv = chan_rv[channel-1];
struct zd_chip *chip = zd_rf_to_chip(rf);
- struct zd_ioreq16 ioreqs_1[] = {
- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR38, 0x38 }, { CR136, 0xdf },
- };
-
- struct zd_ioreq16 ioreqs_2[] = {
+ static const struct zd_ioreq16 ioreqs[] = {
/* PLL_ON */
{ CR251, 0x3f },
{ CR203, 0x06 }, { CR240, 0x08 },
@@ -203,11 +341,9 @@ static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
if (r)
return r;
- for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
- r = zd_rfwrite_cr_locked(chip, std_rv[i]);
- if (r)
- return r;
- }
+ r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
+ if (r)
+ return r;
r = zd_rfwrite_cr_locked(chip, 0x3c9000);
if (r)
@@ -216,24 +352,69 @@ static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
if (r)
return r;
- r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+ r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw));
if (r)
return r;
- for (i = 0; i < 2; i++) {
- r = zd_rfwrite_cr_locked(chip, rv[i]);
- if (r)
- return r;
- }
+ r = zd_rfwritev_cr_locked(chip, rv, 2);
+ if (r)
+ return r;
r = zd_rfwrite_cr_locked(chip, 0x3c9000);
if (r)
return r;
- return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
-static int al7230b_switch_radio_on(struct zd_rf *rf)
+static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+ const u32 *rv = chan_rv[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ r = zd_iowrite16_locked(chip, 0x57, CR240);
+ if (r)
+ return r;
+ r = zd_iowrite16_locked(chip, 0xe4, CR9);
+ if (r)
+ return r;
+
+ /* PLL_OFF */
+ r = zd_iowrite16_locked(chip, 0x2f, CR251);
+ if (r)
+ return r;
+ r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
+ if (r)
+ return r;
+
+ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+ if (r)
+ return r;
+
+ r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw));
+ if (r)
+ return r;
+
+ r = zd_rfwritev_cr_locked(chip, rv, 2);
+ if (r)
+ return r;
+
+ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ if (r)
+ return r;
+
+ r = zd_iowrite16_locked(chip, 0x7f, CR251);
+ if (r)
+ return r;
+
+ return zd1211b_al7230b_finalize(chip);
+}
+
+static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
@@ -244,6 +425,17 @@ static int al7230b_switch_radio_on(struct zd_rf *rf)
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
+static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 },
+ { CR251, 0x7f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
static int al7230b_switch_radio_off(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
@@ -255,20 +447,45 @@ static int al7230b_switch_radio_off(struct zd_rf *rf)
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
+/* ZD1211B+AL7230B 6m band edge patching differs slightly from other
+ * configurations */
+static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ struct zd_ioreq16 ioreqs[] = {
+ { CR128, 0x14 }, { CR129, 0x12 },
+ };
+
+ /* FIXME: Channel 11 is not the edge for all regulatory domains. */
+ if (channel == 1) {
+ ioreqs[0].value = 0x0e;
+ ioreqs[1].value = 0x10;
+ } else if (channel == 11) {
+ ioreqs[0].value = 0x10;
+ ioreqs[1].value = 0x10;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel);
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
int zd_rf_init_al7230b(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
if (chip->is_zd1211b) {
- dev_err(zd_chip_dev(chip), "AL7230B is currently not "
- "supported for ZD1211B devices\n");
- return -ENODEV;
+ rf->init_hw = zd1211b_al7230b_init_hw;
+ rf->switch_radio_on = zd1211b_al7230b_switch_radio_on;
+ rf->set_channel = zd1211b_al7230b_set_channel;
+ rf->patch_6m_band_edge = zd1211b_al7230b_patch_6m;
+ } else {
+ rf->init_hw = zd1211_al7230b_init_hw;
+ rf->switch_radio_on = zd1211_al7230b_switch_radio_on;
+ rf->set_channel = zd1211_al7230b_set_channel;
+ rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
}
- rf->init_hw = al7230b_init_hw;
- rf->set_channel = al7230b_set_channel;
- rf->switch_radio_on = al7230b_switch_radio_on;
rf->switch_radio_off = al7230b_switch_radio_off;
- rf->patch_6m_band_edge = 1;
+
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
index 58247271cc24..2d736bdf707c 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -21,7 +21,7 @@
#include "zd_usb.h"
#include "zd_chip.h"
-static u32 rf2959_table[][2] = {
+static const u32 rf2959_table[][2] = {
RF_CHANNEL( 1) = { 0x181979, 0x1e6666 },
RF_CHANNEL( 2) = { 0x181989, 0x1e6666 },
RF_CHANNEL( 3) = { 0x181999, 0x1e6666 },
@@ -228,7 +228,7 @@ static int rf2959_init_hw(struct zd_rf *rf)
static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
{
int i, r;
- u32 *rv = rf2959_table[channel-1];
+ const u32 *rv = rf2959_table[channel-1];
struct zd_chip *chip = zd_rf_to_chip(rf);
for (i = 0; i < 2; i++) {
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index edaaad2f648b..e04cffc8adf3 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -52,6 +52,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -62,7 +63,10 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{}
@@ -413,7 +417,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
dev_dbg_f(zd_usb_dev(usb), "\n");
- urb = usb_alloc_urb(0, GFP_NOFS);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
r = -ENOMEM;
goto out;
@@ -431,7 +435,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
/* TODO: make it a DMA buffer */
r = -ENOMEM;
- transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS);
+ transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_KERNEL);
if (!transfer_buffer) {
dev_dbg_f(zd_usb_dev(usb),
"couldn't allocate transfer_buffer\n");
@@ -445,7 +449,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
intr->interval);
dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
- r = usb_submit_urb(urb, GFP_NOFS);
+ r = usb_submit_urb(urb, GFP_KERNEL);
if (r) {
dev_dbg_f(zd_usb_dev(usb),
"Couldn't submit urb. Error number %d\n", r);
@@ -594,10 +598,10 @@ static struct urb *alloc_urb(struct zd_usb *usb)
struct urb *urb;
void *buffer;
- urb = usb_alloc_urb(0, GFP_NOFS);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return NULL;
- buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS,
+ buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
&urb->transfer_dma);
if (!buffer) {
usb_free_urb(urb);
@@ -630,7 +634,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
dev_dbg_f(zd_usb_dev(usb), "\n");
r = -ENOMEM;
- urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS);
+ urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
if (!urbs)
goto error;
for (i = 0; i < URBS_COUNT; i++) {
@@ -651,7 +655,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
spin_unlock_irq(&rx->lock);
for (i = 0; i < URBS_COUNT; i++) {
- r = usb_submit_urb(urbs[i], GFP_NOFS);
+ r = usb_submit_urb(urbs[i], GFP_KERNEL);
if (r)
goto error_submit;
}
@@ -1157,7 +1161,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
}
req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
- req = kmalloc(req_len, GFP_NOFS);
+ req = kmalloc(req_len, GFP_KERNEL);
if (!req)
return -ENOMEM;
req->id = cpu_to_le16(USB_REQ_READ_REGS);
@@ -1220,7 +1224,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
req_len = sizeof(struct usb_req_write_regs) +
count * sizeof(struct reg_data);
- req = kmalloc(req_len, GFP_NOFS);
+ req = kmalloc(req_len, GFP_KERNEL);
if (!req)
return -ENOMEM;
@@ -1300,7 +1304,7 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
- req = kmalloc(req_len, GFP_NOFS);
+ req = kmalloc(req_len, GFP_KERNEL);
if (!req)
return -ENOMEM;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index a064f36a0805..b5ac810404c0 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -317,6 +317,10 @@ static int __init acpi_pci_init(void)
{
int ret;
+ if (acpi_gbl_FADT.boot_flags & BAF_MSI_NOT_SUPPORTED) {
+ printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n");
+ pci_no_msi();
+ }
ret = register_acpi_bus_type(&acpi_pci_bus);
if (ret)
return 0;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 65d6f23ead41..3411483240cd 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1303,119 +1303,6 @@ static void __init quirk_alder_ioapic(struct pci_dev *pdev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic );
#endif
-enum ide_combined_type { COMBINED = 0, IDE = 1, LIBATA = 2 };
-/* Defaults to combined */
-static enum ide_combined_type combined_mode;
-
-static int __init combined_setup(char *str)
-{
- if (!strncmp(str, "ide", 3))
- combined_mode = IDE;
- else if (!strncmp(str, "libata", 6))
- combined_mode = LIBATA;
- else /* "combined" or anything else defaults to old behavior */
- combined_mode = COMBINED;
-
- return 1;
-}
-__setup("combined_mode=", combined_setup);
-
-#ifdef CONFIG_SATA_INTEL_COMBINED
-static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
-{
- u8 prog, comb, tmp;
- int ich = 0;
-
- /*
- * Narrow down to Intel SATA PCI devices.
- */
- switch (pdev->device) {
- /* PCI ids taken from drivers/scsi/ata_piix.c */
- case 0x24d1:
- case 0x24df:
- case 0x25a3:
- case 0x25b0:
- ich = 5;
- break;
- case 0x2651:
- case 0x2652:
- case 0x2653:
- case 0x2680: /* ESB2 */
- ich = 6;
- break;
- case 0x27c0:
- case 0x27c4:
- ich = 7;
- break;
- case 0x2828: /* ICH8M */
- ich = 8;
- break;
- default:
- /* we do not handle this PCI device */
- return;
- }
-
- /*
- * Read combined mode register.
- */
- pci_read_config_byte(pdev, 0x90, &tmp); /* combined mode reg */
-
- if (ich == 5) {
- tmp &= 0x6; /* interesting bits 2:1, PATA primary/secondary */
- if (tmp == 0x4) /* bits 10x */
- comb = (1 << 0); /* SATA port 0, PATA port 1 */
- else if (tmp == 0x6) /* bits 11x */
- comb = (1 << 2); /* PATA port 0, SATA port 1 */
- else
- return; /* not in combined mode */
- } else {
- WARN_ON((ich != 6) && (ich != 7) && (ich != 8));
- tmp &= 0x3; /* interesting bits 1:0 */
- if (tmp & (1 << 0))
- comb = (1 << 2); /* PATA port 0, SATA port 1 */
- else if (tmp & (1 << 1))
- comb = (1 << 0); /* SATA port 0, PATA port 1 */
- else
- return; /* not in combined mode */
- }
-
- /*
- * Read programming interface register.
- * (Tells us if it's legacy or native mode)
- */
- pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
-
- /* if SATA port is in native mode, we're ok. */
- if (prog & comb)
- return;
-
- /* Don't reserve any so the IDE driver can get them (but only if
- * combined_mode=ide).
- */
- if (combined_mode == IDE)
- return;
-
- /* Grab them both for libata if combined_mode=libata. */
- if (combined_mode == LIBATA) {
- request_region(0x1f0, 8, "libata"); /* port 0 */
- request_region(0x170, 8, "libata"); /* port 1 */
- return;
- }
-
- /* SATA port is in legacy mode. Reserve port so that
- * IDE driver does not attempt to use it. If request_region
- * fails, it will be obvious at boot time, so we don't bother
- * checking return values.
- */
- if (comb == (1 << 0))
- request_region(0x1f0, 8, "libata"); /* port 0 */
- else
- request_region(0x170, 8, "libata"); /* port 1 */
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined );
-#endif /* CONFIG_SATA_INTEL_COMBINED */
-
-
int pcie_mch_quirk;
EXPORT_SYMBOL(pcie_mch_quirk);
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
index 6c12744eeb9d..7d7cab1d91b4 100644
--- a/drivers/ps3/vuart.c
+++ b/drivers/ps3/vuart.c
@@ -82,14 +82,6 @@ struct ports_bmp {
u64 unused[3];
} __attribute__ ((aligned (32)));
-/* redefine dev_dbg to do a syntax check */
-
-#if !defined(DEBUG)
-#undef dev_dbg
-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
- const struct device *_dev, const char *fmt, ...) {return 0;}
-#endif
-
#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
static void __attribute__ ((unused)) _dump_ports_bmp(
const struct ports_bmp* bmp, const char* func, int line)
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index 4368ca0e8270..a39a478bb39a 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -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;
}
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 227c0f2f4d74..0a533f398f52 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -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)
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 95045e33710d..e9bd29975db4 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -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;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 9f7482d0b594..05d79af5ab90 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -31,7 +31,7 @@
#define SG_MEMPOOL_NR ARRAY_SIZE(scsi_sg_pools)
-#define SG_MEMPOOL_SIZE 32
+#define SG_MEMPOOL_SIZE 2
struct scsi_host_sg_pool {
size_t size;
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 752ef07516b9..be8d75721a85 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -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");
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8372ace4a0d9..b1cb72c3780f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -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
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 9a2b0d69b0ae..c411293cefc8 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -1262,7 +1262,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
/* This is the code for the Aluminium PowerBooks M10 / iBooks M11 */
if (rinfo->family == CHIP_FAMILY_RV350) {
u32 sdram_mode_reg = rinfo->save_regs[35];
- static u32 default_mrtable[] =
+ static const u32 default_mrtable[] =
{ 0x21320032,
0x21321000, 0xa1321000, 0x21321000, 0xffffffff,
0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index fd60dba294da..8b762739b1e0 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -179,12 +179,14 @@ MODULE_LICENSE("GPL");
int init_module(void)
{
struct device_node *dp;
+ int ret = -ENXIO;
- dp = find_devices("control");
+ dp = of_find_node_by_name(NULL, "control");
if (dp != 0 && !control_of_init(dp))
- return 0;
+ ret = 0;
+ of_node_put(dp);
- return -ENXIO;
+ return ret;
}
void cleanup_module(void)
@@ -589,16 +591,18 @@ static int __init control_init(void)
{
struct device_node *dp;
char *option = NULL;
+ int ret = -ENXIO;
if (fb_get_options("controlfb", &option))
return -ENODEV;
control_setup(option);
- dp = find_devices("control");
+ dp = of_find_node_by_name(NULL, "control");
if (dp != 0 && !control_of_init(dp))
- return 0;
+ ret = 0;
+ of_node_put(dp);
- return -ENXIO;
+ return ret;
}
module_init(control_init);
diff --git a/fs/bio.c b/fs/bio.c
index 7618bcb18368..693940da4090 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -28,7 +28,7 @@
#include <linux/blktrace_api.h>
#include <scsi/sg.h> /* for struct sg_iovec */
-#define BIO_POOL_SIZE 256
+#define BIO_POOL_SIZE 2
static struct kmem_cache *bio_slab __read_mostly;
@@ -38,7 +38,7 @@ static struct kmem_cache *bio_slab __read_mostly;
* a small number of entries is fine, not going to be performance critical.
* basically we just need to survive
*/
-#define BIO_SPLIT_ENTRIES 8
+#define BIO_SPLIT_ENTRIES 2
mempool_t *bio_split_pool __read_mostly;
struct biovec_slab {
@@ -1120,7 +1120,7 @@ struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, int first_sectors)
* create memory pools for biovec's in a bio_set.
* use the global biovec slabs created for general use.
*/
-static int biovec_create_pools(struct bio_set *bs, int pool_entries, int scale)
+static int biovec_create_pools(struct bio_set *bs, int pool_entries)
{
int i;
@@ -1128,9 +1128,6 @@ static int biovec_create_pools(struct bio_set *bs, int pool_entries, int scale)
struct biovec_slab *bp = bvec_slabs + i;
mempool_t **bvp = bs->bvec_pools + i;
- if (pool_entries > 1 && i >= scale)
- pool_entries >>= 1;
-
*bvp = mempool_create_slab_pool(pool_entries, bp->slab);
if (!*bvp)
return -ENOMEM;
@@ -1161,7 +1158,7 @@ void bioset_free(struct bio_set *bs)
kfree(bs);
}
-struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size, int scale)
+struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size)
{
struct bio_set *bs = kzalloc(sizeof(*bs), GFP_KERNEL);
@@ -1172,7 +1169,7 @@ struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size, int scale)
if (!bs->bio_pool)
goto bad;
- if (!biovec_create_pools(bs, bvec_pool_size, scale))
+ if (!biovec_create_pools(bs, bvec_pool_size))
return bs;
bad:
@@ -1196,38 +1193,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");
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index abdf068bc27f..eca471bc8512 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -38,7 +38,7 @@ static int property_read_proc(char *page, char **start, off_t off,
n = count;
else
*eof = 1;
- memcpy(page, pp->value + off, n);
+ memcpy(page, (char *)pp->value + off, n);
*start = page;
return n;
}
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index 09469e7db6a5..955adfb8d64c 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -276,6 +276,7 @@ enum acpi_prefered_pm_profiles {
#define BAF_LEGACY_DEVICES 0x0001
#define BAF_8042_KEYBOARD_CONTROLLER 0x0002
+#define BAF_MSI_NOT_SUPPORTED 0x0008
#define FADT2_REVISION_ID 3
#define FADT2_MINUS_REVISION_ID 2
diff --git a/include/asm-powerpc/asm-compat.h b/include/asm-powerpc/asm-compat.h
index c89bd58ee283..c19e7367fce6 100644
--- a/include/asm-powerpc/asm-compat.h
+++ b/include/asm-powerpc/asm-compat.h
@@ -78,6 +78,15 @@
#define PPC_STLCX stringify_in_c(stdcx.)
#define PPC_CNTLZL stringify_in_c(cntlzd)
+/* Move to CR, single-entry optimized version. Only available
+ * on POWER4 and later.
+ */
+#ifdef CONFIG_POWER4_ONLY
+#define PPC_MTOCRF stringify_in_c(mtocrf)
+#else
+#define PPC_MTOCRF stringify_in_c(mtcrf)
+#endif
+
#else /* 32-bit */
/* operations for longs and pointers */
@@ -89,6 +98,7 @@
#define PPC_LLARX stringify_in_c(lwarx)
#define PPC_STLCX stringify_in_c(stwcx.)
#define PPC_CNTLZL stringify_in_c(cntlzw)
+#define PPC_MTOCRF stringify_in_c(mtcrf)
#endif
diff --git a/include/asm-powerpc/cacheflush.h b/include/asm-powerpc/cacheflush.h
index 08e93e789219..ba667a383b8c 100644
--- a/include/asm-powerpc/cacheflush.h
+++ b/include/asm-powerpc/cacheflush.h
@@ -64,6 +64,12 @@ extern void flush_dcache_phys_range(unsigned long start, unsigned long stop);
memcpy(dst, src, len)
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+/* internal debugging function */
+void kernel_map_pages(struct page *page, int numpages, int enable);
+#endif
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_CACHEFLUSH_H */
diff --git a/include/asm-powerpc/cell-pmu.h b/include/asm-powerpc/cell-pmu.h
index 35b95773746c..8066eede3a0c 100644
--- a/include/asm-powerpc/cell-pmu.h
+++ b/include/asm-powerpc/cell-pmu.h
@@ -97,11 +97,6 @@ extern void cbe_disable_pm_interrupts(u32 cpu);
extern u32 cbe_get_and_clear_pm_interrupts(u32 cpu);
extern void cbe_sync_irq(int node);
-/* Utility functions, macros */
-extern u32 cbe_get_hw_thread_id(int cpu);
-
-#define cbe_cpu_to_node(cpu) ((cpu) >> 1)
-
#define CBE_COUNT_SUPERVISOR_MODE 0
#define CBE_COUNT_HYPERVISOR_MODE 1
#define CBE_COUNT_PROBLEM_MODE 2
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index e870b5393175..434524931ef3 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -48,6 +48,7 @@ enum powerpc_oprofile_type {
PPC_OPROFILE_G4 = 3,
PPC_OPROFILE_BOOKE = 4,
PPC_OPROFILE_CELL = 5,
+ PPC_OPROFILE_PA6T = 6,
};
enum powerpc_pmc_type {
@@ -223,6 +224,10 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
CPU_FTR_PPC_LE)
+#define CPU_FTRS_750CL (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+ CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+ CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
#define CPU_FTRS_750FX1 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
@@ -235,9 +240,9 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
-#define CPU_FTRS_750GX (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
- CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | \
- CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+#define CPU_FTRS_750GX (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+ CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
#define CPU_FTRS_7400_NOTAU (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
diff --git a/include/asm-powerpc/current.h b/include/asm-powerpc/current.h
index b8708aedf925..e2c7f06931e7 100644
--- a/include/asm-powerpc/current.h
+++ b/include/asm-powerpc/current.h
@@ -12,6 +12,7 @@
struct task_struct;
#ifdef __powerpc64__
+#include <linux/stddef.h>
#include <asm/paca.h>
static inline struct task_struct *get_current(void)
diff --git a/include/asm-powerpc/edac.h b/include/asm-powerpc/edac.h
new file mode 100644
index 000000000000..6ead88bbfbb8
--- /dev/null
+++ b/include/asm-powerpc/edac.h
@@ -0,0 +1,40 @@
+/*
+ * PPC EDAC common defs
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef ASM_EDAC_H
+#define ASM_EDAC_H
+/*
+ * ECC atomic, DMA, SMP and interrupt safe scrub function.
+ * Implements the per arch atomic_scrub() that EDAC use for software
+ * ECC scrubbing. It reads memory and then writes back the original
+ * value, allowing the hardware to detect and correct memory errors.
+ */
+static __inline__ void atomic_scrub(void *va, u32 size)
+{
+ unsigned int *virt_addr = va;
+ unsigned int temp;
+ unsigned int i;
+
+ for (i = 0; i < size / sizeof(*virt_addr); i++, virt_addr++) {
+ /* Very carefully read and write to memory atomically
+ * so we are interrupt, DMA and SMP safe.
+ */
+ __asm__ __volatile__ ("\n\
+ 1: lwarx %0,0,%1\n\
+ stwcx. %0,0,%1\n\
+ bne- 1b\n\
+ isync"
+ : "=&r"(temp)
+ : "r"(virt_addr)
+ : "cr0", "memory");
+ }
+}
+
+#endif
diff --git a/include/asm-powerpc/eeh_event.h b/include/asm-powerpc/eeh_event.h
index dc6bf0ffb796..cc3cb04539ac 100644
--- a/include/asm-powerpc/eeh_event.h
+++ b/include/asm-powerpc/eeh_event.h
@@ -30,8 +30,6 @@ struct eeh_event {
struct list_head list;
struct device_node *dn; /* struct device node */
struct pci_dev *dev; /* affected device */
- enum pci_channel_state state; /* PCI bus state for the affected device */
- int time_unavail; /* milliseconds until device might be available */
};
/**
@@ -46,9 +44,7 @@ struct eeh_event {
* (from a workqueue).
*/
int eeh_send_failure_event (struct device_node *dn,
- struct pci_dev *dev,
- enum pci_channel_state state,
- int time_unavail);
+ struct pci_dev *dev);
/* Main recovery function */
struct pci_dn * handle_eeh_events (struct eeh_event *);
diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h
index 66112114b8c5..87d396e28db2 100644
--- a/include/asm-powerpc/ibmebus.h
+++ b/include/asm-powerpc/ibmebus.h
@@ -2,36 +2,37 @@
* IBM PowerPC eBus Infrastructure Support.
*
* Copyright (c) 2005 IBM Corporation
+ * Joachim Fenkes <fenkes@de.ibm.com>
* Heiko J Schick <schickhj@de.ibm.com>
- *
+ *
* All rights reserved.
*
- * This source code is distributed under a dual license of GPL v2.0 and OpenIB
- * BSD.
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
*
* OpenIB BSD License
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
*
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
*
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
* and/or other materials
- * provided with the distribution.
+ * provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
@@ -46,12 +47,11 @@
extern struct bus_type ibmebus_bus_type;
-struct ibmebus_dev {
- const char *name;
+struct ibmebus_dev {
struct of_device ofdev;
};
-struct ibmebus_driver {
+struct ibmebus_driver {
char *name;
struct of_device_id *id_table;
int (*probe) (struct ibmebus_dev *dev, const struct of_device_id *id);
@@ -63,7 +63,7 @@ int ibmebus_register_driver(struct ibmebus_driver *drv);
void ibmebus_unregister_driver(struct ibmebus_driver *drv);
int ibmebus_request_irq(struct ibmebus_dev *dev,
- u32 ist,
+ u32 ist,
irq_handler_t handler,
unsigned long irq_flags, const char * devname,
void *dev_id);
diff --git a/include/asm-powerpc/immap_86xx.h b/include/asm-powerpc/immap_86xx.h
index d905b6622268..59b9e07b8e99 100644
--- a/include/asm-powerpc/immap_86xx.h
+++ b/include/asm-powerpc/immap_86xx.h
@@ -85,81 +85,6 @@ typedef struct ccsr_pci {
char res19[472];
} ccsr_pci_t;
-/* PCI Express Registers */
-typedef struct ccsr_pex {
- uint pex_config_addr; /* 0x.000 - PCI Express Configuration Address Register */
- uint pex_config_data; /* 0x.004 - PCI Express Configuration Data Register */
- char res1[4];
- uint pex_otb_cpl_tor; /* 0x.00c - PCI Express Outbound completion timeout register */
- uint pex_conf_tor; /* 0x.010 - PCI Express configuration timeout register */
- char res2[12];
- uint pex_pme_mes_dr; /* 0x.020 - PCI Express PME and message detect register */
- uint pex_pme_mes_disr; /* 0x.024 - PCI Express PME and message disable register */
- uint pex_pme_mes_ier; /* 0x.028 - PCI Express PME and message interrupt enable register */
- uint pex_pmcr; /* 0x.02c - PCI Express power management command register */
- char res3[3024];
- uint pexotar0; /* 0x.c00 - PCI Express outbound translation address register 0 */
- uint pexotear0; /* 0x.c04 - PCI Express outbound translation extended address register 0*/
- char res4[8];
- uint pexowar0; /* 0x.c10 - PCI Express outbound window attributes register 0*/
- char res5[12];
- uint pexotar1; /* 0x.c20 - PCI Express outbound translation address register 1 */
- uint pexotear1; /* 0x.c24 - PCI Express outbound translation extended address register 1*/
- uint pexowbar1; /* 0x.c28 - PCI Express outbound window base address register 1*/
- char res6[4];
- uint pexowar1; /* 0x.c30 - PCI Express outbound window attributes register 1*/
- char res7[12];
- uint pexotar2; /* 0x.c40 - PCI Express outbound translation address register 2 */
- uint pexotear2; /* 0x.c44 - PCI Express outbound translation extended address register 2*/
- uint pexowbar2; /* 0x.c48 - PCI Express outbound window base address register 2*/
- char res8[4];
- uint pexowar2; /* 0x.c50 - PCI Express outbound window attributes register 2*/
- char res9[12];
- uint pexotar3; /* 0x.c60 - PCI Express outbound translation address register 3 */
- uint pexotear3; /* 0x.c64 - PCI Express outbound translation extended address register 3*/
- uint pexowbar3; /* 0x.c68 - PCI Express outbound window base address register 3*/
- char res10[4];
- uint pexowar3; /* 0x.c70 - PCI Express outbound window attributes register 3*/
- char res11[12];
- uint pexotar4; /* 0x.c80 - PCI Express outbound translation address register 4 */
- uint pexotear4; /* 0x.c84 - PCI Express outbound translation extended address register 4*/
- uint pexowbar4; /* 0x.c88 - PCI Express outbound window base address register 4*/
- char res12[4];
- uint pexowar4; /* 0x.c90 - PCI Express outbound window attributes register 4*/
- char res13[12];
- char res14[256];
- uint pexitar3; /* 0x.da0 - PCI Express inbound translation address register 3 */
- char res15[4];
- uint pexiwbar3; /* 0x.da8 - PCI Express inbound window base address register 3 */
- uint pexiwbear3; /* 0x.dac - PCI Express inbound window base extended address register 3 */
- uint pexiwar3; /* 0x.db0 - PCI Express inbound window attributes register 3 */
- char res16[12];
- uint pexitar2; /* 0x.dc0 - PCI Express inbound translation address register 2 */
- char res17[4];
- uint pexiwbar2; /* 0x.dc8 - PCI Express inbound window base address register 2 */
- uint pexiwbear2; /* 0x.dcc - PCI Express inbound window base extended address register 2 */
- uint pexiwar2; /* 0x.dd0 - PCI Express inbound window attributes register 2 */
- char res18[12];
- uint pexitar1; /* 0x.de0 - PCI Express inbound translation address register 2 */
- char res19[4];
- uint pexiwbar1; /* 0x.de8 - PCI Express inbound window base address register 2 */
- uint pexiwbear1; /* 0x.dec - PCI Express inbound window base extended address register 2 */
- uint pexiwar1; /* 0x.df0 - PCI Express inbound window attributes register 2 */
- char res20[12];
- uint pex_err_dr; /* 0x.e00 - PCI Express error detect register */
- char res21[4];
- uint pex_err_en; /* 0x.e08 - PCI Express error interrupt enable register */
- char res22[4];
- uint pex_err_disr; /* 0x.e10 - PCI Express error disable register */
- char res23[12];
- uint pex_err_cap_stat; /* 0x.e20 - PCI Express error capture status register */
- char res24[4];
- uint pex_err_cap_r0; /* 0x.e28 - PCI Express error capture register 0 */
- uint pex_err_cap_r1; /* 0x.e2c - PCI Express error capture register 0 */
- uint pex_err_cap_r2; /* 0x.e30 - PCI Express error capture register 0 */
- uint pex_err_cap_r3; /* 0x.e34 - PCI Express error capture register 0 */
-} ccsr_pex_t;
-
/* Global Utility Registers */
typedef struct ccsr_guts {
uint porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 301c9bb308b1..350c9bdb31dc 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -11,7 +11,12 @@
/* Check of existence of legacy devices */
extern int check_legacy_ioport(unsigned long base_port);
-#define PNPBIOS_BASE 0xf000 /* only relevant for PReP */
+#define I8042_DATA_REG 0x60
+#define FDC_BASE 0x3f0
+/* only relevant for PReP */
+#define _PIDXR 0x279
+#define _PNPWRP 0xa79
+#define PNPBIOS_BASE 0xf000
#include <linux/compiler.h>
#include <asm/page.h>
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index 3a5dd492588f..f850ca7020ed 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -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 {
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 1b04e5723548..b204926ce913 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -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
index 000000000000..6739457d8bc0
--- /dev/null
+++ b/include/asm-powerpc/mmu-hash64.h
@@ -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_ */
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h
index 200055a4b82b..06b3e6d336cb 100644
--- a/include/asm-powerpc/mmu.h
+++ b/include/asm-powerpc/mmu.h
@@ -2,407 +2,14 @@
#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_ */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index cb204a71e912..e4d5fc5362a0 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -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".
diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
index a889b2005bf5..4f1aabe0ce73 100644
--- a/include/asm-powerpc/of_device.h
+++ b/include/asm-powerpc/of_device.h
@@ -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 */
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index 94c0ad2bff96..8d6b47f7b300 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -57,6 +57,8 @@ extern struct op_powerpc_model op_model_rs64;
extern struct op_powerpc_model op_model_power4;
extern struct op_powerpc_model op_model_7450;
extern struct op_powerpc_model op_model_cell;
+extern struct op_powerpc_model op_model_pa6t;
+
/* All the classic PPC parts use these */
static inline unsigned int classic_ctr_read(unsigned int i)
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index 0d3adc09c847..cf95274f735e 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -70,6 +70,7 @@ struct paca_struct {
s16 hw_cpu_id; /* Physical processor number */
u8 cpu_start; /* At startup, processor spins until */
/* this becomes non-zero. */
+ struct slb_shadow *slb_shadow_ptr;
/*
* Now, starting in cacheline 2, the exception save areas
@@ -93,6 +94,7 @@ struct paca_struct {
u64 stab_rr; /* stab/slb round-robin counter */
u64 saved_r1; /* r1 save for RTAS calls */
u64 saved_msr; /* MSR saved here by enter_rtas */
+ u16 trap_save; /* Used when bad stack is encountered */
u8 soft_enabled; /* irq soft-enable flag */
u8 hard_enabled; /* set if irqs are enabled in MSR */
u8 io_sync; /* writel() needs spin_unlock sync */
@@ -101,8 +103,6 @@ struct paca_struct {
u64 user_time; /* accumulated usermode TB ticks */
u64 system_time; /* accumulated system TB ticks */
u64 startpurr; /* PURR/TB value snapshot */
-
- struct slb_shadow *slb_shadow_ptr;
};
extern struct paca_struct paca[];
diff --git a/include/asm-powerpc/parport.h b/include/asm-powerpc/parport.h
index 3fca21ddf546..b37b81e37278 100644
--- a/include/asm-powerpc/parport.h
+++ b/include/asm-powerpc/parport.h
@@ -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)
diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h
index ac656ee6bb19..ce0f13e8eb14 100644
--- a/include/asm-powerpc/pci.h
+++ b/include/asm-powerpc/pci.h
@@ -70,19 +70,22 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
*/
#define PCI_DISABLE_MWI
-extern struct dma_mapping_ops *pci_dma_ops;
+#ifdef CONFIG_PCI
+extern void set_pci_dma_ops(struct dma_mapping_ops *dma_ops);
+extern struct dma_mapping_ops *get_pci_dma_ops(void);
/* For DAC DMA, we currently don't support it by default, but
* we let 64-bit platforms override this.
*/
static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
{
- if (pci_dma_ops && pci_dma_ops->dac_dma_supported)
- return pci_dma_ops->dac_dma_supported(&hwdev->dev, mask);
+ struct dma_mapping_ops *d = get_pci_dma_ops();
+
+ if (d && d->dac_dma_supported)
+ return d->dac_dma_supported(&hwdev->dev, mask);
return 0;
}
-#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
unsigned long *strategy_parameter)
@@ -99,6 +102,9 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
*strat = PCI_DMA_BURST_MULTIPLE;
*strategy_parameter = cacheline_size;
}
+#else /* CONFIG_PCI */
+#define set_pci_dma_ops(d)
+#define get_pci_dma_ops() NULL
#endif
extern int pci_domain_nr(struct pci_bus *bus);
diff --git a/include/asm-powerpc/pgtable-4k.h b/include/asm-powerpc/pgtable-4k.h
index 345d9b07b3e2..a28fa8bc01da 100644
--- a/include/asm-powerpc/pgtable-4k.h
+++ b/include/asm-powerpc/pgtable-4k.h
@@ -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))
diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h
index 4b7126c53f37..5e84f070eaf7 100644
--- a/include/asm-powerpc/pgtable-64k.h
+++ b/include/asm-powerpc/pgtable-64k.h
@@ -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 */
@@ -93,6 +94,10 @@
#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 */
diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h
index 10f52743f4ff..19edb6982b81 100644
--- a/include/asm-powerpc/pgtable.h
+++ b/include/asm-powerpc/pgtable.h
@@ -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__ */
diff --git a/include/asm-powerpc/pmc.h b/include/asm-powerpc/pmc.h
index 8588be68e0ad..d6a616a1b3ea 100644
--- a/include/asm-powerpc/pmc.h
+++ b/include/asm-powerpc/pmc.h
@@ -30,6 +30,7 @@ void release_pmc_hardware(void);
#ifdef CONFIG_PPC64
void power4_enable_pmcs(void);
+void pasemi_enable_pmcs(void);
#endif
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index ab6eddb518c7..d74b2965bb82 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -10,6 +10,8 @@
#define _ASM_POWERPC_PPC_PCI_H
#ifdef __KERNEL__
+#ifdef CONFIG_PCI
+
#include <linux/pci.h>
#include <asm/pci-bridge.h>
@@ -22,7 +24,7 @@ extern void pci_setup_phb_io_dynamic(struct pci_controller *hose, int primary);
extern struct list_head hose_list;
extern int global_phb_number;
-extern unsigned long find_and_init_phbs(void);
+extern void find_and_init_phbs(void);
extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */
@@ -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 */
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index a26c32ee5527..d947b1609491 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -133,7 +133,6 @@ struct thread_struct {
mm_segment_t fs; /* for get_fs() validation */
#ifdef CONFIG_PPC32
void *pgdir; /* root of page-table tree */
- signed long last_syscall;
#endif
#if defined(CONFIG_4xx) || defined (CONFIG_BOOKE)
unsigned long dbcr0; /* debug control register values */
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index 020ed015a94b..ec400f608e16 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -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 */
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index 0d7f0164ed81..749c7f953b58 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -469,12 +469,68 @@
#define SPRN_SIAR 780
#define SPRN_SDAR 781
-#define PA6T_SPRN_PMC0 787
-#define PA6T_SPRN_PMC1 788
-#define PA6T_SPRN_PMC2 789
-#define PA6T_SPRN_PMC3 790
-#define PA6T_SPRN_PMC4 791
-#define PA6T_SPRN_PMC5 792
+#define SPRN_PA6T_MMCR0 795
+#define PA6T_MMCR0_EN0 0x0000000000000001UL
+#define PA6T_MMCR0_EN1 0x0000000000000002UL
+#define PA6T_MMCR0_EN2 0x0000000000000004UL
+#define PA6T_MMCR0_EN3 0x0000000000000008UL
+#define PA6T_MMCR0_EN4 0x0000000000000010UL
+#define PA6T_MMCR0_EN5 0x0000000000000020UL
+#define PA6T_MMCR0_SUPEN 0x0000000000000040UL
+#define PA6T_MMCR0_PREN 0x0000000000000080UL
+#define PA6T_MMCR0_HYPEN 0x0000000000000100UL
+#define PA6T_MMCR0_FCM0 0x0000000000000200UL
+#define PA6T_MMCR0_FCM1 0x0000000000000400UL
+#define PA6T_MMCR0_INTGEN 0x0000000000000800UL
+#define PA6T_MMCR0_INTEN0 0x0000000000001000UL
+#define PA6T_MMCR0_INTEN1 0x0000000000002000UL
+#define PA6T_MMCR0_INTEN2 0x0000000000004000UL
+#define PA6T_MMCR0_INTEN3 0x0000000000008000UL
+#define PA6T_MMCR0_INTEN4 0x0000000000010000UL
+#define PA6T_MMCR0_INTEN5 0x0000000000020000UL
+#define PA6T_MMCR0_DISCNT 0x0000000000040000UL
+#define PA6T_MMCR0_UOP 0x0000000000080000UL
+#define PA6T_MMCR0_TRG 0x0000000000100000UL
+#define PA6T_MMCR0_TRGEN 0x0000000000200000UL
+#define PA6T_MMCR0_TRGREG 0x0000000001600000UL
+#define PA6T_MMCR0_SIARLOG 0x0000000002000000UL
+#define PA6T_MMCR0_SDARLOG 0x0000000004000000UL
+#define PA6T_MMCR0_PROEN 0x0000000008000000UL
+#define PA6T_MMCR0_PROLOG 0x0000000010000000UL
+#define PA6T_MMCR0_DAMEN2 0x0000000020000000UL
+#define PA6T_MMCR0_DAMEN3 0x0000000040000000UL
+#define PA6T_MMCR0_DAMEN4 0x0000000080000000UL
+#define PA6T_MMCR0_DAMEN5 0x0000000100000000UL
+#define PA6T_MMCR0_DAMSEL2 0x0000000200000000UL
+#define PA6T_MMCR0_DAMSEL3 0x0000000400000000UL
+#define PA6T_MMCR0_DAMSEL4 0x0000000800000000UL
+#define PA6T_MMCR0_DAMSEL5 0x0000001000000000UL
+#define PA6T_MMCR0_HANDDIS 0x0000002000000000UL
+#define PA6T_MMCR0_PCTEN 0x0000004000000000UL
+#define PA6T_MMCR0_SOCEN 0x0000008000000000UL
+#define PA6T_MMCR0_SOCMOD 0x0000010000000000UL
+
+#define SPRN_PA6T_MMCR1 798
+#define PA6T_MMCR1_ES2 0x00000000000000ffUL
+#define PA6T_MMCR1_ES3 0x000000000000ff00UL
+#define PA6T_MMCR1_ES4 0x0000000000ff0000UL
+#define PA6T_MMCR1_ES5 0x00000000ff000000UL
+
+#define SPRN_PA6T_SIAR 780
+#define SPRN_PA6T_UPMC0 771
+#define SPRN_PA6T_UPMC1 772
+#define SPRN_PA6T_UPMC2 773
+#define SPRN_PA6T_UPMC3 774
+#define SPRN_PA6T_UPMC4 775
+#define SPRN_PA6T_UPMC5 776
+#define SPRN_PA6T_UMMCR0 779
+#define SPRN_PA6T_UMMCR1 782
+#define SPRN_PA6T_PMC0 787
+#define SPRN_PA6T_PMC1 788
+#define SPRN_PA6T_PMC2 789
+#define SPRN_PA6T_PMC3 790
+#define SPRN_PA6T_PMC4 791
+#define SPRN_PA6T_PMC5 792
#else /* 32-bit */
#define SPRN_MMCR0 952 /* Monitor Mode Control Register 0 */
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
index 8aad0619eb8e..02e56a6685a2 100644
--- a/include/asm-powerpc/spu_csa.h
+++ b/include/asm-powerpc/spu_csa.h
@@ -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;
};
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index f7b1227d6454..d3e0906ff2bc 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -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 *);
diff --git a/include/asm-powerpc/tlb.h b/include/asm-powerpc/tlb.h
index 4e2a834683fb..0a17682663d8 100644
--- a/include/asm-powerpc/tlb.h
+++ b/include/asm-powerpc/tlb.h
@@ -38,7 +38,6 @@ extern void pte_free_finish(void);
static inline void tlb_flush(struct mmu_gather *tlb)
{
- flush_tlb_pending();
pte_free_finish();
}
diff --git a/include/asm-powerpc/tlbflush.h b/include/asm-powerpc/tlbflush.h
index 93c7d0c7230f..86e6266a028b 100644
--- a/include/asm-powerpc/tlbflush.h
+++ b/include/asm-powerpc/tlbflush.h
@@ -17,10 +17,73 @@
*/
#ifdef __KERNEL__
-
struct mm_struct;
+struct vm_area_struct;
+
+#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE)
+/*
+ * TLB flushing for software loaded TLB chips
+ *
+ * TODO: (CONFIG_FSL_BOOKE) determine if flush_tlb_range &
+ * flush_tlb_kernel_range are best implemented as tlbia vs
+ * specific tlbie's
+ */
+
+extern void _tlbie(unsigned long address);
+
+#if defined(CONFIG_40x) || defined(CONFIG_8xx)
+#define _tlbia() asm volatile ("tlbia; sync" : : : "memory")
+#else /* CONFIG_44x || CONFIG_FSL_BOOKE */
+extern void _tlbia(void);
+#endif
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+ _tlbia();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long vmaddr)
+{
+ _tlbie(vmaddr);
+}
+
+static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
+ unsigned long vmaddr)
+{
+ _tlbie(vmaddr);
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ _tlbia();
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start,
+ unsigned long end)
+{
+ _tlbia();
+}
-#ifdef CONFIG_PPC64
+#elif defined(CONFIG_PPC32)
+/*
+ * TLB flushing for "classic" hash-MMMU 32-bit CPUs, 6xx, 7xx, 7xxx
+ */
+extern void _tlbie(unsigned long address);
+extern void _tlbia(void);
+
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+
+#else
+/*
+ * TLB flushing for 64-bit has-MMU CPUs
+ */
#include <linux/percpu.h>
#include <asm/page.h>
@@ -28,117 +91,90 @@ struct mm_struct;
#define PPC64_TLB_BATCH_NR 192
struct ppc64_tlb_batch {
- unsigned long index;
- struct mm_struct *mm;
- real_pte_t pte[PPC64_TLB_BATCH_NR];
- unsigned long vaddr[PPC64_TLB_BATCH_NR];
- unsigned int psize;
+ int active;
+ unsigned long index;
+ struct mm_struct *mm;
+ real_pte_t pte[PPC64_TLB_BATCH_NR];
+ unsigned long vaddr[PPC64_TLB_BATCH_NR];
+ unsigned int psize;
};
DECLARE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
extern void __flush_tlb_pending(struct ppc64_tlb_batch *batch);
-static inline void flush_tlb_pending(void)
+extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, unsigned long pte, int huge);
+
+#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
+
+static inline void arch_enter_lazy_mmu_mode(void)
+{
+ struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
+
+ batch->active = 1;
+}
+
+static inline void arch_leave_lazy_mmu_mode(void)
{
- struct ppc64_tlb_batch *batch = &get_cpu_var(ppc64_tlb_batch);
+ struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
if (batch->index)
__flush_tlb_pending(batch);
- put_cpu_var(ppc64_tlb_batch);
+ batch->active = 0;
}
+#define arch_flush_lazy_mmu_mode() do {} while (0)
+
+
extern void flush_hash_page(unsigned long va, real_pte_t pte, int psize,
int local);
extern void flush_hash_range(unsigned long number, int local);
-#else /* CONFIG_PPC64 */
-
-#include <linux/mm.h>
-
-extern void _tlbie(unsigned long address);
-extern void _tlbia(void);
-
-/*
- * TODO: (CONFIG_FSL_BOOKE) determine if flush_tlb_range &
- * flush_tlb_kernel_range are best implemented as tlbia vs
- * specific tlbie's
- */
-
-#if (defined(CONFIG_4xx) && !defined(CONFIG_44x)) || defined(CONFIG_8xx)
-#define flush_tlb_pending() asm volatile ("tlbia; sync" : : : "memory")
-#elif defined(CONFIG_4xx) || defined(CONFIG_FSL_BOOKE)
-#define flush_tlb_pending() _tlbia()
-#endif
-
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to ensure coherency between the i-cache and d-cache
- * for the page which has just been mapped in.
- * On machines which use an MMU hash table, we use this to put a
- * corresponding HPTE into the hash table ahead of time, instead of
- * waiting for the inevitable extra hash-table miss exception.
- */
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-
-#endif /* CONFIG_PPC64 */
-
-#if defined(CONFIG_PPC64) || defined(CONFIG_4xx) || \
- defined(CONFIG_FSL_BOOKE) || defined(CONFIG_8xx)
static inline void flush_tlb_mm(struct mm_struct *mm)
{
- flush_tlb_pending();
}
static inline void flush_tlb_page(struct vm_area_struct *vma,
- unsigned long vmaddr)
+ unsigned long vmaddr)
{
-#ifdef CONFIG_PPC64
- flush_tlb_pending();
-#else
- _tlbie(vmaddr);
-#endif
}
static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
unsigned long vmaddr)
{
-#ifndef CONFIG_PPC64
- _tlbie(vmaddr);
-#endif
}
static inline void flush_tlb_range(struct vm_area_struct *vma,
- unsigned long start, unsigned long end)
+ unsigned long start, unsigned long end)
{
- flush_tlb_pending();
}
static inline void flush_tlb_kernel_range(unsigned long start,
- unsigned long end)
+ unsigned long end)
{
- flush_tlb_pending();
}
-#else /* 6xx, 7xx, 7xxx cpus */
-
-extern void flush_tlb_mm(struct mm_struct *mm);
-extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr);
-extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
- unsigned long end);
-extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
-
#endif
/*
+ * This gets called at the end of handling a page fault, when
+ * the kernel has put a new PTE into the page table for the process.
+ * We use it to ensure coherency between the i-cache and d-cache
+ * for the page which has just been mapped in.
+ * On machines which use an MMU hash table, we use this to put a
+ * corresponding HPTE into the hash table ahead of time, instead of
+ * waiting for the inevitable extra hash-table miss exception.
+ */
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+
+/*
* This is called in munmap when we have freed up some page-table
* pages. We don't need to do anything here, there's nothing special
* about our page-table pages. -- paulus
*/
static inline void flush_tlb_pgtables(struct mm_struct *mm,
- unsigned long start, unsigned long end)
+ unsigned long start, unsigned long end)
{
}
diff --git a/include/asm-powerpc/uaccess.h b/include/asm-powerpc/uaccess.h
index adbf16b8cfbb..8e798e3758bc 100644
--- a/include/asm-powerpc/uaccess.h
+++ b/include/asm-powerpc/uaccess.h
@@ -110,12 +110,18 @@ struct exception_table_entry {
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
#define __put_user(x, ptr) \
__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
#ifndef __powerpc64__
#define __get_user64(x, ptr) \
__get_user64_nocheck((x), (ptr), sizeof(*(ptr)))
#define __put_user64(x, ptr) __put_user(x, ptr)
#endif
+#define __get_user_inatomic(x, ptr) \
+ __get_user_nosleep((x), (ptr), sizeof(*(ptr)))
+#define __put_user_inatomic(x, ptr) \
+ __put_user_nosleep((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
#define __get_user_unaligned __get_user
#define __put_user_unaligned __put_user
@@ -198,6 +204,16 @@ do { \
__pu_err; \
})
+#define __put_user_nosleep(x, ptr, size) \
+({ \
+ long __pu_err; \
+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
+ __chk_user_ptr(ptr); \
+ __put_user_size((x), __pu_addr, (size), __pu_err); \
+ __pu_err; \
+})
+
+
extern long __get_user_bad(void);
#define __get_user_asm(x, addr, err, op) \
@@ -297,6 +313,18 @@ do { \
__gu_err; \
})
+#define __get_user_nosleep(x, ptr, size) \
+({ \
+ long __gu_err; \
+ unsigned long __gu_val; \
+ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
+ __chk_user_ptr(ptr); \
+ __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ __gu_err; \
+})
+
+
/* more complex routines */
extern unsigned long __copy_tofrom_user(void __user *to,
diff --git a/include/asm-powerpc/ucc_fast.h b/include/asm-powerpc/ucc_fast.h
index 39d1c90fd2ca..f529f70b1d82 100644
--- a/include/asm-powerpc/ucc_fast.h
+++ b/include/asm-powerpc/ucc_fast.h
@@ -159,6 +159,9 @@ struct ucc_fast_private {
struct ucc_fast *uf_regs; /* a pointer to memory map of UCC regs. */
u32 *p_ucce; /* a pointer to the event register in memory. */
u32 *p_uccm; /* a pointer to the mask register in memory. */
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+ u16 *p_utodr; /* pointer to the transmit on demand register */
+#endif
int enabled_tx; /* Whether channel is enabled for Tx (ENT) */
int enabled_rx; /* Whether channel is enabled for Rx (ENR) */
int stopped_tx; /* Whether channel has been stopped for Tx
diff --git a/include/asm-powerpc/uic.h b/include/asm-powerpc/uic.h
new file mode 100644
index 000000000000..970eb7e2186a
--- /dev/null
+++ b/include/asm-powerpc/uic.h
@@ -0,0 +1,23 @@
+/*
+ * include/asm-powerpc/uic.h
+ *
+ * IBM PPC4xx UIC external definitions and structure.
+ *
+ * Maintainer: David Gibson <dwg@au1.ibm.com>
+ * Copyright 2007 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#ifndef _ASM_POWERPC_UIC_H
+#define _ASM_POWERPC_UIC_H
+
+#ifdef __KERNEL__
+
+extern void __init uic_init_tree(void);
+extern unsigned int uic_get_irq(void);
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_UIC_H */
diff --git a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h
index 92fd02d7b177..ed6891af05d3 100644
--- a/include/asm-ppc/ibm4xx.h
+++ b/include/asm-ppc/ibm4xx.h
@@ -47,12 +47,8 @@
#include <platforms/4xx/walnut.h>
#endif
-#if defined(CONFIG_XILINX_ML300)
-#include <platforms/4xx/xilinx_ml300.h>
-#endif
-
-#if defined(CONFIG_XILINX_ML403)
-#include <platforms/4xx/xilinx_ml403.h>
+#if defined(CONFIG_XILINX_VIRTEX)
+#include <platforms/4xx/virtex.h>
#endif
#ifndef __ASSEMBLY__
diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h
index 40f197af6508..de99e92d627b 100644
--- a/include/asm-ppc/ppc_sys.h
+++ b/include/asm-ppc/ppc_sys.h
@@ -33,8 +33,6 @@
#include <asm/mpc52xx.h>
#elif defined(CONFIG_MPC10X_BRIDGE)
#include <asm/mpc10x.h>
-#elif defined(CONFIG_XILINX_VIRTEX)
-#include <platforms/4xx/virtex.h>
#else
#error "need definition of ppc_sys_devices"
#endif
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index adc5ae784924..901f7fa8b2d7 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -34,7 +34,8 @@ extern unsigned long sub_reloc_offset(unsigned long);
*/
#define machine_is_compatible(x) 0
#define of_find_compatible_node(f, t, c) NULL
-#define get_property(p, n, l) NULL
+#define of_get_property(p, n, l) NULL
+#define get_property(a, b, c) of_get_property((a), (b), (c))
#endif /* _PPC_PROM_H */
#endif /* __KERNEL__ */
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 6caeb98e29dd..edb31bfff68f 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -159,11 +159,19 @@ enum {
ATA_CMD_INIT_DEV_PARAMS = 0x91,
ATA_CMD_READ_NATIVE_MAX = 0xF8,
ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
+ ATA_CMD_SET_MAX = 0xF9,
+ ATA_CMD_SET_MAX_EXT = 0x37,
ATA_CMD_READ_LOG_EXT = 0x2f,
/* READ_LOG_EXT pages */
ATA_LOG_SATA_NCQ = 0x10,
+ /* READ/WRITE LONG (obsolete) */
+ ATA_CMD_READ_LONG = 0x22,
+ ATA_CMD_READ_LONG_ONCE = 0x23,
+ ATA_CMD_WRITE_LONG = 0x32,
+ ATA_CMD_WRITE_LONG_ONCE = 0x33,
+
/* SETFEATURES stuff */
SETFEATURES_XFER = 0x03,
XFER_UDMA_7 = 0x47,
@@ -194,6 +202,8 @@ enum {
SETFEATURES_WC_ON = 0x02, /* Enable write cache */
SETFEATURES_WC_OFF = 0x82, /* Disable write cache */
+ SETFEATURES_SPINUP = 0x07, /* Spin-up drive */
+
/* ATAPI stuff */
ATAPI_PKT_DMA = (1 << 0),
ATAPI_DMADIR = (1 << 2), /* ATAPI data dir:
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 08daf3272c02..4d85262b4fa4 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -276,7 +276,7 @@ extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool,
extern mempool_t *bio_split_pool;
extern void bio_pair_release(struct bio_pair *dbio);
-extern struct bio_set *bioset_create(int, int, int);
+extern struct bio_set *bioset_create(int, int);
extern void bioset_free(struct bio_set *);
extern struct bio *bio_alloc(gfp_t, int);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 83dcd8c0e974..a686eabe22d6 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -116,6 +116,7 @@ struct io_context {
struct as_io_context *aic;
struct rb_root cic_root;
+ void *ioc_data;
};
void put_io_context(struct io_context *ioc);
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index abb64c437f6f..73710d617775 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -120,44 +120,5 @@ struct fsl_spi_platform_data {
u32 sysclk;
};
-/* Ethernet interface (phy management and speed)
-*/
-enum enet_interface {
- ENET_10_MII, /* 10 Base T, MII interface */
- ENET_10_RMII, /* 10 Base T, RMII interface */
- ENET_10_RGMII, /* 10 Base T, RGMII interface */
- ENET_100_MII, /* 100 Base T, MII interface */
- ENET_100_RMII, /* 100 Base T, RMII interface */
- ENET_100_RGMII, /* 100 Base T, RGMII interface */
- ENET_1000_GMII, /* 1000 Base T, GMII interface */
- ENET_1000_RGMII, /* 1000 Base T, RGMII interface */
- ENET_1000_TBI, /* 1000 Base T, TBI interface */
- ENET_1000_RTBI /* 1000 Base T, RTBI interface */
-};
-
-struct ucc_geth_platform_data {
- /* device specific information */
- u32 device_flags;
- u32 phy_reg_addr;
-
- /* board specific information */
- u32 board_flags;
- u8 rx_clock;
- u8 tx_clock;
- u32 phy_id;
- enum enet_interface phy_interface;
- u32 phy_interrupt;
- u8 mac_addr[6];
-};
-
-/* Flags related to UCC Gigabit Ethernet device features */
-#define FSL_UGETH_DEV_HAS_GIGABIT 0x00000001
-#define FSL_UGETH_DEV_HAS_COALESCE 0x00000002
-#define FSL_UGETH_DEV_HAS_RMON 0x00000004
-
-/* Flags in ucc_geth_platform_data */
-#define FSL_UGETH_BRD_HAS_PHY_INTR 0x00000001
- /* if not set use a timer */
-
#endif /* _FSL_DEVICE_H_ */
#endif /* __KERNEL__ */
diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h
index 0fe562af9c8c..db390c511ada 100644
--- a/include/linux/hdlc.h
+++ b/include/linux/hdlc.h
@@ -43,8 +43,7 @@ struct hdlc_proto {
void (*stop)(struct net_device *dev); /* if open & !DCD */
void (*detach)(struct net_device *dev);
int (*ioctl)(struct net_device *dev, struct ifreq *ifr);
- unsigned short (*type_trans)(struct sk_buff *skb,
- struct net_device *dev);
+ __be16 (*type_trans)(struct sk_buff *skb, struct net_device *dev);
struct module *module;
struct hdlc_proto *next; /* next protocol in the list */
};
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 6859a3b14088..71ea92319241 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -99,7 +99,6 @@ extern struct resource ioport_resource;
extern struct resource iomem_resource;
extern int request_resource(struct resource *root, struct resource *new);
-extern struct resource * ____request_resource(struct resource *root, struct resource *new);
extern int release_resource(struct resource *new);
extern int insert_resource(struct resource *parent, struct resource *new);
extern int allocate_resource(struct resource *root, struct resource *new,
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 0cfbcb6f08eb..d8cfc72ea9c1 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -210,6 +210,7 @@ enum {
/* host set flags */
ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */
+ ATA_HOST_STARTED = (1 << 1), /* Host started */
/* various lengths of time */
ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */
@@ -281,11 +282,13 @@ enum {
ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */
ATA_EHI_QUIET = (1 << 3), /* be quiet */
- ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */
- ATA_EHI_PRINTINFO = (1 << 17), /* print configuration info */
- ATA_EHI_SETMODE = (1 << 18), /* configure transfer mode */
- ATA_EHI_POST_SETMODE = (1 << 19), /* revaildating after setmode */
+ ATA_EHI_DID_SOFTRESET = (1 << 16), /* already soft-reset this port */
+ ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */
+ ATA_EHI_PRINTINFO = (1 << 18), /* print configuration info */
+ ATA_EHI_SETMODE = (1 << 19), /* configure transfer mode */
+ ATA_EHI_POST_SETMODE = (1 << 20), /* revaildating after setmode */
+ ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET,
ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK,
/* max repeat if error condition is still set after ->error_handler */
@@ -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__ */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index a3ad76221c6f..972491089ac9 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -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 */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 600308fdf9ce..1b0ddbb8a804 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -368,7 +368,6 @@
#define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379
#define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a
#define PCI_DEVICE_ID_ATI_IXP600_SATA 0x4380
-#define PCI_DEVICE_ID_ATI_IXP600_SRAID 0x4381
#define PCI_DEVICE_ID_ATI_IXP600_SMBUS 0x4385
#define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c
@@ -1459,6 +1458,8 @@
#define PCI_VENDOR_ID_TOSHIBA_2 0x102f
#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU 0x0031
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939 0x0032
#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105
#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108
#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
diff --git a/include/linux/phy.h b/include/linux/phy.h
index edd4c88ca7d8..2a659789f9ca 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -55,6 +55,7 @@ typedef enum {
PHY_INTERFACE_MODE_TBI,
PHY_INTERFACE_MODE_RMII,
PHY_INTERFACE_MODE_RGMII,
+ PHY_INTERFACE_MODE_RGMII_ID,
PHY_INTERFACE_MODE_RTBI
} phy_interface_t;
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index 783177387ac6..b0952e532ed5 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -168,24 +168,16 @@ extern int pmu_get_model(void);
struct pmu_sleep_notifier
{
- int (*notifier_call)(struct pmu_sleep_notifier *self, int when);
+ void (*notifier_call)(struct pmu_sleep_notifier *self, int when);
int priority;
struct list_head list;
};
/* Code values for calling sleep/wakeup handlers
- *
- * Note: If a sleep request got cancelled, all drivers will get
- * the PBOOK_SLEEP_REJECT, even those who didn't get the PBOOK_SLEEP_REQUEST.
*/
#define PBOOK_SLEEP_REQUEST 1
#define PBOOK_SLEEP_NOW 2
-#define PBOOK_SLEEP_REJECT 3
-#define PBOOK_WAKE 4
-
-/* Result codes returned by the notifiers */
-#define PBOOK_SLEEP_OK 0
-#define PBOOK_SLEEP_REFUSE -1
+#define PBOOK_WAKE 3
/* priority levels in notifiers */
#define SLEEP_LEVEL_VIDEO 100 /* Video driver (first wake) */
diff --git a/include/linux/sony-laptop.h b/include/linux/sony-laptop.h
new file mode 100644
index 000000000000..e2e036d94e4a
--- /dev/null
+++ b/include/linux/sony-laptop.h
@@ -0,0 +1,34 @@
+#ifndef _SONYLAPTOP_H_
+#define _SONYLAPTOP_H_
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+
+/* used only for communication between v4l and sony-laptop */
+
+#define SONY_PIC_COMMAND_GETCAMERA 1 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERA 2
+#define SONY_PIC_COMMAND_GETCAMERABRIGHTNESS 3 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERABRIGHTNESS 4
+#define SONY_PIC_COMMAND_GETCAMERACONTRAST 5 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERACONTRAST 6
+#define SONY_PIC_COMMAND_GETCAMERAHUE 7 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAHUE 8
+#define SONY_PIC_COMMAND_GETCAMERACOLOR 9 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERACOLOR 10
+#define SONY_PIC_COMMAND_GETCAMERASHARPNESS 11 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERASHARPNESS 12
+#define SONY_PIC_COMMAND_GETCAMERAPICTURE 13 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAPICTURE 14
+#define SONY_PIC_COMMAND_GETCAMERAAGC 15 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAAGC 16
+#define SONY_PIC_COMMAND_GETCAMERADIRECTION 17 /* obsolete */
+#define SONY_PIC_COMMAND_GETCAMERAROMVERSION 18 /* obsolete */
+#define SONY_PIC_COMMAND_GETCAMERAREVISION 19 /* obsolete */
+
+int sony_pic_camera_command(int command, u8 value);
+
+#endif /* __KERNEL__ */
+
+#endif /* _SONYLAPTOP_H_ */
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 48759b2f57d7..0987aa7a6cf5 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -186,7 +186,7 @@
* - Wireless Event capability in struct iw_range
* - Add support for relative TxPower (yick !)
*
- * V17 to V18 (From Jouni Malinen <jkmaline@cc.hut.fi>)
+ * V17 to V18 (From Jouni Malinen <j@w1.fi>)
* ----------
* - Add support for WPA/WPA2
* - Add extended encoding configuration (SIOCSIWENCODEEXT and
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index e02d85f56e60..d56b2923d61a 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -6,8 +6,8 @@
* LAN access point) driver for Intersil Prism2/2.5/3.
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
*
* Adaption to a generic IEEE 802.11 stack by James Ketrenos
* <jketreno@linux.intel.com>
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
index eb476414fd72..b3d65e0bedd3 100644
--- a/include/net/ieee80211_crypt.h
+++ b/include/net/ieee80211_crypt.h
@@ -3,8 +3,8 @@
* for Intersil Prism2/2.5/3.
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
*
* Adaption to a generic IEEE 802.11 stack by James Ketrenos
* <jketreno@linux.intel.com>
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index 429b73892a5f..a0c2b41a24d7 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -66,7 +66,9 @@
*/
#define IEEE80211_RADIOTAP_HDRLEN 64
-/* The radio capture header precedes the 802.11 header. */
+/* The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
struct ieee80211_radiotap_header {
u8 it_version; /* Version 0. Only increases
* for drastic changes,
@@ -74,12 +76,12 @@ struct ieee80211_radiotap_header {
* new fields does not count.
*/
u8 it_pad;
- u16 it_len; /* length of the whole
+ __le16 it_len; /* length of the whole
* header in bytes, including
* it_version, it_pad,
* it_len, and data fields.
*/
- u32 it_present; /* A bitmap telling which
+ __le32 it_present; /* A bitmap telling which
* fields are present. Set bit 31
* (0x80000000) to extend the
* bitmap by another 32 bits.
@@ -88,89 +90,102 @@ struct ieee80211_radiotap_header {
*/
};
-/* Name Data type Units
- * ---- --------- -----
+/* Name Data type Units
+ * ---- --------- -----
*
- * IEEE80211_RADIOTAP_TSFT u64 microseconds
+ * IEEE80211_RADIOTAP_TSFT __le64 microseconds
*
* Value in microseconds of the MAC's 64-bit 802.11 Time
* Synchronization Function timer when the first bit of the
* MPDU arrived at the MAC. For received frames, only.
*
- * IEEE80211_RADIOTAP_CHANNEL 2 x u16 MHz, bitmap
+ * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap
*
* Tx/Rx frequency in MHz, followed by flags (see below).
*
- * IEEE80211_RADIOTAP_FHSS u16 see below
+ * IEEE80211_RADIOTAP_FHSS __le16 see below
*
* For frequency-hopping radios, the hop set (first byte)
* and pattern (second byte).
*
- * IEEE80211_RADIOTAP_RATE u8 500kb/s
+ * IEEE80211_RADIOTAP_RATE u8 500kb/s
*
* Tx/Rx data rate
*
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from
- * one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
+ * one milliwatt (dBm)
*
* RF signal power at the antenna, decibel difference from
* one milliwatt.
*
- * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from
- * one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
+ * one milliwatt (dBm)
*
* RF noise power at the antenna, decibel difference from one
* milliwatt.
*
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
*
* RF signal power at the antenna, decibel difference from an
* arbitrary, fixed reference.
*
- * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
+ * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
*
* RF noise power at the antenna, decibel difference from an
* arbitrary, fixed reference point.
*
- * IEEE80211_RADIOTAP_LOCK_QUALITY u16 unitless
+ * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless
*
* Quality of Barker code lock. Unitless. Monotonically
* nondecreasing with "better" lock strength. Called "Signal
* Quality" in datasheets. (Is there a standard way to measure
* this?)
*
- * IEEE80211_RADIOTAP_TX_ATTENUATION u16 unitless
+ * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless
*
* Transmit power expressed as unitless distance from max
* power set at factory calibration. 0 is max power.
* Monotonically nondecreasing with lower power levels.
*
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u16 decibels (dB)
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB)
*
* Transmit power expressed as decibel distance from max power
* set at factory calibration. 0 is max power. Monotonically
* nondecreasing with lower power levels.
*
- * IEEE80211_RADIOTAP_DBM_TX_POWER int8_t decibels from
- * one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
+ * one milliwatt (dBm)
*
* Transmit power expressed as dBm (decibels from a 1 milliwatt
* reference). This is the absolute power level measured at
* the antenna port.
*
- * IEEE80211_RADIOTAP_FLAGS u8 bitmap
+ * IEEE80211_RADIOTAP_FLAGS u8 bitmap
*
* Properties of transmitted and received frames. See flags
* defined below.
*
- * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
+ * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
*
* Unitless indication of the Rx/Tx antenna for this packet.
* The first antenna is antenna 0.
*
- * IEEE80211_RADIOTAP_FCS u32 data
+ * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap
+ *
+ * Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap
+ *
+ * Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
+ *
+ * Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
+ *
+ * Number of unicast retries a transmitted frame used.
*
- * FCS from frame in network byte order.
*/
enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TSFT = 0,
@@ -187,7 +202,11 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_ANTENNA = 11,
IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
- IEEE80211_RADIOTAP_EXT = 31,
+ IEEE80211_RADIOTAP_RX_FLAGS = 14,
+ IEEE80211_RADIOTAP_TX_FLAGS = 15,
+ IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+ IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+ IEEE80211_RADIOTAP_EXT = 31
};
/* Channel flags. */
@@ -219,6 +238,14 @@ enum ieee80211_radiotap_type {
* 802.11 header and payload
* (to 32-bit boundary)
*/
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
+ * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
/* Ugly macro to convert literal channel numbers into their mhz equivalents
* There are certianly some conditions that will break this (like feeding it '30')
diff --git a/kernel/resource.c b/kernel/resource.c
index bdb55a33f969..9bd14fd3e6de 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -213,27 +213,6 @@ int request_resource(struct resource *root, struct resource *new)
EXPORT_SYMBOL(request_resource);
/**
- * ____request_resource - reserve a resource, with resource conflict returned
- * @root: root resource descriptor
- * @new: resource descriptor desired by caller
- *
- * Returns:
- * On success, NULL is returned.
- * On error, a pointer to the conflicting resource is returned.
- */
-struct resource *____request_resource(struct resource *root, struct resource *new)
-{
- struct resource *conflict;
-
- write_lock(&resource_lock);
- conflict = __request_resource(root, new);
- write_unlock(&resource_lock);
- return conflict;
-}
-
-EXPORT_SYMBOL(____request_resource);
-
-/**
* release_resource - release a previously reserved resource
* @old: resource pointer
*/
diff --git a/lib/devres.c b/lib/devres.c
index eb38849aa717..b1d336ce7f3d 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -296,5 +296,31 @@ int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name)
return rc;
}
EXPORT_SYMBOL(pcim_iomap_regions);
+
+/**
+ * pcim_iounmap_regions - Unmap and release PCI BARs
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to unmap and release
+ *
+ * Unamp and release regions specified by @mask.
+ */
+void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask)
+{
+ void __iomem * const *iomap;
+ int i;
+
+ iomap = pcim_iomap_table(pdev);
+ if (!iomap)
+ return;
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ if (!(mask & (1 << i)))
+ continue;
+
+ pcim_iounmap(pdev, iomap[i]);
+ pci_release_region(pdev, i);
+ }
+}
+EXPORT_SYMBOL(pcim_iounmap_regions);
#endif
#endif
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c
index 5ed0a98b2d76..df5592c9339f 100644
--- a/net/ieee80211/ieee80211_crypt.c
+++ b/net/ieee80211/ieee80211_crypt.c
@@ -1,7 +1,7 @@
/*
* Host AP crypto routines
*
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
* Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c
index 35aa3426c3fa..b016b4104de6 100644
--- a/net/ieee80211/ieee80211_crypt_ccmp.c
+++ b/net/ieee80211/ieee80211_crypt_ccmp.c
@@ -1,7 +1,7 @@
/*
* Host AP crypt: host-based CCMP encryption implementation for Host AP driver
*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -338,7 +338,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (ccmp_replay_check(pn, key->rx_pn)) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
+ IEEE80211_DEBUG_DROP("CCMP: replay detected: STA=" MAC_FMT
" previous PN %02x%02x%02x%02x%02x%02x "
"received PN %02x%02x%02x%02x%02x%02x\n",
MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c
index fc1f99a59732..5a48d8e0aec1 100644
--- a/net/ieee80211/ieee80211_crypt_tkip.c
+++ b/net/ieee80211/ieee80211_crypt_tkip.c
@@ -1,7 +1,7 @@
/*
* Host AP crypt: host-based TKIP encryption implementation for Host AP driver
*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -465,7 +465,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+ IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=" MAC_FMT
" previous TSC %08x%04x received TSC "
"%08x%04x\n", MAC_ARG(hdr->addr2),
tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
@@ -507,7 +507,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
tkey->rx_phase1_done = 0;
}
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: ICV error detected: STA="
+ IEEE80211_DEBUG_DROP("TKIP: ICV error detected: STA="
MAC_FMT "\n", MAC_ARG(hdr->addr2));
}
tkey->dot11RSNAStatsTKIPICVErrors++;
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c
index 4eb35079e434..8d182459344e 100644
--- a/net/ieee80211/ieee80211_crypt_wep.c
+++ b/net/ieee80211/ieee80211_crypt_wep.c
@@ -1,7 +1,7 @@
/*
* Host AP crypt: host-based WEP encryption implementation for Host AP driver
*
- * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
index b1c6d1f717d9..7ec6610841ba 100644
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -5,8 +5,8 @@
Portions of this file are based on the WEP enablement code provided by the
Host AP project hostap-drivers v0.1.3
Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <jkmaline@cc.hut.fi>
- Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ <j@w1.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
@@ -229,6 +229,7 @@ void free_ieee80211(struct net_device *dev)
static int debug = 0;
u32 ieee80211_debug_level = 0;
+EXPORT_SYMBOL_GPL(ieee80211_debug_level);
static struct proc_dir_entry *ieee80211_proc = NULL;
static int show_debug_level(char *page, char **start, off_t offset,
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 6ae036b1920f..f2de2e48b021 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -3,8 +3,8 @@
* for Intersil Prism2/2.5/3 - hostap.o module, common routines
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2005, Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 40d7a55fe03e..cee5e13bc427 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -5,8 +5,8 @@
Portions of this file are based on the WEP enablement code provided by the
Host AP project hostap-drivers v0.1.3
Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <jkmaline@cc.hut.fi>
- Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ <j@w1.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c
index b00fc4842c93..7f980be5d060 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.c
+++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c
@@ -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);
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c
index 2cd81fa07ce1..ceca38486eae 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.c
+++ b/sound/aoa/codecs/snd-aoa-codec-tas.c
@@ -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;
diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c
index 2b03bc798bcb..805dcbff2257 100644
--- a/sound/aoa/core/snd-aoa-gpio-feature.c
+++ b/sound/aoa/core/snd-aoa-gpio-feature.c
@@ -55,7 +55,7 @@ static struct device_node *get_gpio(char *name,
int *gpioactiveptr)
{
struct device_node *np, *gpio;
- u32 *reg;
+ const u32 *reg;
const char *audio_gpio;
*gpioptr = -1;
@@ -71,7 +71,7 @@ static struct device_node *get_gpio(char *name,
if (!gpio)
return NULL;
while ((np = of_get_next_child(gpio, np))) {
- audio_gpio = get_property(np, "audio-gpio", NULL);
+ audio_gpio = of_get_property(np, "audio-gpio", NULL);
if (!audio_gpio)
continue;
if (strcmp(audio_gpio, name) == 0)
@@ -84,7 +84,7 @@ static struct device_node *get_gpio(char *name,
return NULL;
}
- reg = (u32 *)get_property(np, "reg", NULL);
+ reg = of_get_property(np, "reg", NULL);
if (!reg)
return NULL;
@@ -96,7 +96,7 @@ static struct device_node *get_gpio(char *name,
if (*gpioptr < 0x50)
*gpioptr += 0x50;
- reg = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
+ reg = of_get_property(np, "audio-gpio-active-state", NULL);
if (!reg)
/* Apple seems to default to 1, but
* that doesn't seem right at least on most
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
index 1b94ba6dd279..98806283d1b2 100644
--- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c
+++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
@@ -724,7 +724,7 @@ static int check_codec(struct aoa_codec *codec,
struct layout_dev *ldev,
struct codec_connect_info *cci)
{
- u32 *ref;
+ const u32 *ref;
char propname[32];
struct codec_connection *cc;
@@ -732,7 +732,7 @@ static int check_codec(struct aoa_codec *codec,
if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
snprintf(propname, sizeof(propname),
"platform-%s-codec-ref", codec->name);
- ref = (u32*)get_property(ldev->sound, propname, NULL);
+ ref = of_get_property(ldev->sound, propname, NULL);
if (!ref) {
printk(KERN_INFO "snd-aoa-fabric-layout: "
"required property %s not present\n", propname);
@@ -946,7 +946,7 @@ static struct aoa_fabric layout_fabric = {
static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
{
struct device_node *sound = NULL;
- unsigned int *layout_id;
+ const unsigned int *layout_id;
struct layout *layout;
struct layout_dev *ldev = NULL;
int err;
@@ -962,7 +962,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
}
if (!sound) return -ENODEV;
- layout_id = (unsigned int *) get_property(sound, "layout-id", NULL);
+ layout_id = of_get_property(sound, "layout-id", NULL);
if (!layout_id)
goto outnodev;
printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n",
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c
index 418a98a10c73..8b2e9b905cda 100644
--- a/sound/aoa/soundbus/core.c
+++ b/sound/aoa/soundbus/core.c
@@ -61,7 +61,7 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
{
struct soundbus_dev * soundbus_dev;
struct of_device * of;
- char *compat;
+ const char *compat;
int retval = 0, i = 0, length = 0;
int cplen, seen = 0;
@@ -91,7 +91,7 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
* it's not really legal to split it out with commas. We split it
* up using a number of environment variables instead. */
- compat = (char *) get_property(of->node, "compatible", &cplen);
+ compat = of_get_property(of->node, "compatible", &cplen);
while (compat && cplen > 0) {
int tmp = length;
retval = add_uevent_var(envp, num_envp, &i,
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
index e36f6aa448d4..79fc4bc09e5e 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
@@ -122,7 +122,7 @@ static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
{
struct device_node *parent;
int pindex, rc = -ENXIO;
- u32 *reg;
+ const u32 *reg;
/* Machines with layout 76 and 36 (K2 based) have a weird device
* tree what we need to special case.
@@ -141,7 +141,7 @@ static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
rc = of_address_to_resource(parent, pindex, res);
if (rc)
goto bail;
- reg = (u32 *)get_property(np, "reg", NULL);
+ reg = of_get_property(np, "reg", NULL);
if (reg == NULL) {
rc = -ENXIO;
goto bail;
@@ -188,8 +188,8 @@ static int i2sbus_add_dev(struct macio_dev *macio,
}
}
if (i == 1) {
- u32 *layout_id;
- layout_id = (u32*) get_property(sound, "layout-id", NULL);
+ const u32 *layout_id =
+ of_get_property(sound, "layout-id", NULL);
if (layout_id) {
layout = *layout_id;
snprintf(dev->sound.modalias, 32,
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index 37773b1deea5..730fa1d001a5 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -257,7 +257,7 @@ static volatile struct dbdma_cmd *emergency_dbdma_cmd;
/*
* Stuff for restoring after a sleep.
*/
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
struct pmu_sleep_notifier awacs_sleep_notifier = {
awacs_sleep_notify, SLEEP_LEVEL_SOUND,
};
@@ -346,36 +346,42 @@ int gpio_headphone_irq;
int
setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol)
{
+ struct device_node *gpiop;
struct device_node *np;
const u32* pp;
+ int ret = -ENODEV;
- np = find_devices("gpio");
- if (!np)
- return -ENODEV;
+ gpiop = of_find_node_by_name(NULL, "gpio");
+ if (!gpiop)
+ goto done;
- np = np->child;
+ np = of_get_next_child(gpiop, NULL);
while(np != 0) {
if (name) {
const char *property =
- get_property(np,"audio-gpio",NULL);
+ of_get_property(np,"audio-gpio",NULL);
if (property != 0 && strcmp(property,name) == 0)
break;
} else if (compatible && device_is_compatible(np, compatible))
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.");
diff --git a/sound/oss/dmasound/tas_common.c b/sound/oss/dmasound/tas_common.c
index 665e85b5562b..b295ef682192 100644
--- a/sound/oss/dmasound/tas_common.c
+++ b/sound/oss/dmasound/tas_common.c
@@ -41,7 +41,6 @@
static u8 tas_i2c_address = 0x34;
static struct i2c_client *tas_client;
-static struct device_node* tas_node;
static int tas_attach_adapter(struct i2c_adapter *);
static int tas_detach_client(struct i2c_client *);
@@ -190,17 +189,18 @@ tas_cleanup(void)
int __init
tas_init(int driver_id, const char *driver_name)
{
- u32* paddr;
+ const u32* paddr;
+ struct device_node *tas_node;
printk(KERN_INFO "tas driver [%s])\n", driver_name);
#ifndef CONFIG_I2C_POWERMAC
request_module("i2c-powermac");
#endif
- tas_node = find_devices("deq");
+ tas_node = of_find_node_by_name("deq");
if (tas_node == NULL)
return -ENODEV;
- paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
+ paddr = of_get_property(tas_node, "i2c-address", NULL);
if (paddr) {
tas_i2c_address = (*paddr) >> 1;
printk(KERN_INFO "using i2c address: 0x%x from device-tree\n",
@@ -208,6 +208,7 @@ tas_init(int driver_id, const char *driver_name)
} else
printk(KERN_INFO "using i2c address: 0x%x (default)\n",
tas_i2c_address);
+ of_node_put(tas_node);
return i2c_add_driver(&tas_driver);
}
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index c64af55865d4..2bae9c1a2b54 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -816,6 +816,7 @@ static int snd_pmac_free(struct snd_pmac *chip)
if (chip->pdev)
pci_dev_put(chip->pdev);
+ of_node_put(chip->node);
kfree(chip);
return 0;
}
@@ -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;
}
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 8f074c7936e6..54e333fbb1d0 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -1031,32 +1031,40 @@ static irqreturn_t headphone_intr(int irq, void *devid)
/* look for audio-gpio device */
static struct device_node *find_audio_device(const char *name)
{
+ struct device_node *gpiop;
struct device_node *np;
- if (! (np = find_devices("gpio")))
+ gpiop = of_find_node_by_name(NULL, "gpio");
+ if (! gpiop)
return NULL;
- for (np = np->child; np; np = np->sibling) {
- const char *property = get_property(np, "audio-gpio", NULL);
+ for (np = of_get_next_child(gpiop, NULL); np;
+ np = of_get_next_child(gpiop, np)) {
+ const char *property = of_get_property(np, "audio-gpio", NULL);
if (property && strcmp(property, name) == 0)
- return np;
+ break;
}
- return NULL;
+ of_node_put(gpiop);
+ return np;
}
/* look for audio-gpio device */
static struct device_node *find_compatible_audio_device(const char *name)
{
+ struct device_node *gpiop;
struct device_node *np;
- if (! (np = find_devices("gpio")))
+ gpiop = of_find_node_by_name(NULL, "gpio");
+ if (!gpiop)
return NULL;
- for (np = np->child; np; np = np->sibling) {
+ 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);